C: Processing Windows Bitmaps Or DIBs With The Propeller?
idbruce
Posts: 6,197
Hello Everyone
I am looking for existing code or a processing scheme to read the bits of Windows bitmaps or DIBs with the Propeller. It has been a while since I have messed with the bitmap file structures, so I know I will have to do a little studying, but not much.
Anyhow, the bitmaps will always be monochrome, and they are currently being saved as *.bmp, with a bit depth of 1, and a maximum file size of 572kb.
I can easily create a Windows program, which will send the color of each pixel serially to the Propeller, however I would prefer not to be tied to a PC. Although, the original bitmaps will need a little preprocessing, so I will be writing a Windows program for this, and I can also do additional modifications to the files during the preprocessing stage, if necessary.
My thoughts are to save the *.bmp files to an SD card and read the pixel information off of the card with the Propeller, however I do not yet know if this is possible or if there is already existing code to perform this task.
To sum it up, I want to be able to read a bmp file from an SD card and represent black and white colors with 1s and 0s, or equivalency thereof.
Bruce
I am looking for existing code or a processing scheme to read the bits of Windows bitmaps or DIBs with the Propeller. It has been a while since I have messed with the bitmap file structures, so I know I will have to do a little studying, but not much.
Anyhow, the bitmaps will always be monochrome, and they are currently being saved as *.bmp, with a bit depth of 1, and a maximum file size of 572kb.
I can easily create a Windows program, which will send the color of each pixel serially to the Propeller, however I would prefer not to be tied to a PC. Although, the original bitmaps will need a little preprocessing, so I will be writing a Windows program for this, and I can also do additional modifications to the files during the preprocessing stage, if necessary.
My thoughts are to save the *.bmp files to an SD card and read the pixel information off of the card with the Propeller, however I do not yet know if this is possible or if there is already existing code to perform this task.
To sum it up, I want to be able to read a bmp file from an SD card and represent black and white colors with 1s and 0s, or equivalency thereof.
Bruce
Comments
Couldn't help chuckling at this. Sounds a lot like the difficulty I have putting ideas I can picture so clearly into words others can understand.
Even though I confuse myself at times, with my thoughts, I make a worthy attempt, to make my thoughts clear to others, so that they may be confused also
Suppose your image is 640x480: the raw bitmap is then 38400 bytes.
Now, to find out the size of the header, save one empty 640x480x1 image using Paint or any other app (I always do this because I'm not sure if there are optional fields in the header, so size might differ depending on the program used).
Suppose you get 38520 bytes.
So you simply open the file, seek +120 from start, start reading from there (80 bytes per row in the example above).
Be warned that row order is bottom-to-top.
Hope this helps.
Alessandro
Upon taking a second look and thinking about it a bit, I came to the conclusion that it should be quite easy to convert a BMP file to PBM file format.
With a PBM file saved to an SD card, it should be quite easy for the Propeller to parse this file and determine whether a pixel should be white or black.
Solution in the works
I will finish programming the other available options later this evening, such as mirrored images, mirrored images with right hand alignment, and mirrored images with right hand alignment and alternating scan lines
The output files contain three characters, which are 0, 1, and LF, with a *.plt file extension.
I can now see where this program could be very handy for LED displays.
you can find it here:
https://msdn.microsoft.com/en-us/library/dd183391(v=vs.85).aspx
That gives you about 8:1 compression, would reduce the time to process the data (because reading from an SD is slow) and is still pretty trivial to display.
Hmmmm...... I wouldn't be able to process bitmap files like I am, if I didn't already have that information. But thanks anyway.
@JasonDorie
My intent was to get the programming done as quick as possible. I am using a very old version of Visual C++ 6.0 to write the program and taking full advantage of the MFC classes, but more specifically, I am using the CString class for writing to the files and string reversal.
Basically, I am much better at working with strings, which makes it much faster for me to write the program this way, and that is why I went this route. The characters will eventually have to be compared and converted to a number, which will slow things down quite a bit, but my thoughts are to read and compare the SD characters in a separate cog, and pump numbers into a queue for processing.
However, I am always open to new and different ideas, and perhaps I could do a CString to binary conversion, after all the bitmap processing is completed. Or once the text file is written, could I then convert that text file to binary, because at that point, the data would already be formatted in the proper order?
This is C-ish pseudocode, and assumes "myString" is your string of 0's and 1's, presumably for the current line of pixels:
Decoding them at runtime would be similar. In fact, you could access any individual bit in a horizontal line with:
That's very cool and thank you very much! I should have no problem inserting that code into my program. It looks pretty cut and dry. In fact, I will just provide program options to create either file type or both.
The beauty of your code is that it will utilize my formatted strings, which makes it very easy on me at this point.
I just thought of something. What is the best way to incorporate the LF into your code? I am using LF to either indicate the advancement to the next scan line or a movement of the Y axis.
Files written in ASCII / text mode don't like having raw 0 bytes written into them - that's usually interpreted as an end-of-file marker, and the above code that packs bits together will end up emitting 0 bytes when you have 8 sequential clear pixels, so you should only use it when writing to a binary file. I wrote it to allow you to still use your strings right up to the point where you write the file.
So your runtime, using the GetBit() function above, would look something like this:
Hopefully that's fairly easy for you. If you're more comfortable with a text-based file just do that - the only reason I suggested this was that it would likely be faster to get onto the display from the SD card. If your display is mono you might even be able to just blast the bytes directly to it.
Okay, I see your point about the header. However, I really didn't need it with my previous plan. However, as you know, I like speed, so I will add a header and your code.
I love it! It will fit right in.
Thanks again Jason
Controlling Propeller pins with this data at runtime should be interesting
I am now onto Jason's version. Hopefully I can figure this all out. Everything seems fairly easy, except the header.
I really should know how to do this already
After translating your code to the following code below, I kept getting CFileException's until I added the & symbol before BitRack, to make it &BiitRack. 'DOH'
I can now write the bits to a file.
The header code also helps tremendously. I would have spent hours trying to figure that out.
I am now onto translating your header code to MFC.
Thank you very much Jason!!!
If your strBitmapBitArray represents a single horizontal row then the code you have is fine as it is. If the function is intended to output the whole bitmap at once, I'd suggest reworking it a little, like this, to get the per-scanline padding right. (it won't actually matter if the image is a multiple of 8 pixels wide):
Yea, you were pretty much right on the money Certainly made it easy on me
Yep... That code is just meant to write a single line. It was a lot easier to do that way then to start rewriting a bunch of code. I now basically have two versions, separated into two main functions, with each version controlled by a separate button, one for text and one for binary output.
In the text version, I was using the CStdioFile class for writing to the files, because of the simplicity provided by the class member function WriteString. However, for the binary version, I switched over to the CFile class for writing to the files. Of course, these two different classes have similar, but different file openers, which is the main reason behind separate functions. Since the CFile class does not have a WriteString class member function, I decided to write it as shown above. By doing so, I could basically just copy the text version, remove all references to line feeds, and replace all calls to WriteString with calls to WriteBitmapsBits(..., ...) shown above.
Easy, peasy, Japaneasy (With your help of course)
You said...
For a 1795 X 1622 bitmap image, when stored on a Windows OS, the text version weighs in at 2847 KB, and the binary version weighs in at 357 KB.
2847 KB / 357 KB = 7.97 (rounded) compression
WOW... You're good!!! You seen it all, right from the start.
Anyhow, I stole the header portion out of your last snippet (rewritten to my style) and added it to the following function. This is the function that calls the previous function that I posted. Between the two functions, you can clearly see how I utilized the help and code that you provided.
And, happy to help.
I might be saying a little too much.... but....
Com'on... Have you ever known me to really talk about displays or LEDs? Although the code could be used for displays, as I said, but you know me as the one who always talks about CNC. This code is for machine control.
As I said earlier, the bits will be dumped into a queue, small portions at a time.
Here's one for you....
As mentioned in the previous post, the intent is machine control. However, the output generated could theoretically control displays.
While working on both your version and mine, I have been tossing this idea around in my head (although I am certain that I am not the first to come up with it), of describing a monochrome bitmap with moves (white pixels), lines (black pixels), and next scan lines, to be machine specific. Well I decided to experiment with the idea this morning.
Here is a portion of my new machine code
There is still a couple flaws, but utilizing the same file as the size tests above, the complete file size for this version currently weighs in at 135 KB
EDIT: However, perhaps parsing will take longer.
EDIT: Coordinates are relative to current position
Make a sequence of shorts (16 bits) where the upper 2 bits are:
00 = MN
01 = M
10 = L
11= end-of-stream
The next 14 bits are your move/line distance.
If you're actually storing the numbers in your file as ascii, you'll have to "reassemble" then into numbers at runtime. Encoding them into shorts just means doing an & 0x3fff at runtime to get the numbers out. As text, your commands are, at largest, 1 character (move/line) + 4 chars (length), whereas the shorts version would be always 2 chars per command + length, so about 2/5 the size, best case. Not as easily human readable, but much easier to work with from the Prop, and smaller.
I really like the shorts idea
Actually the MN was one of the flaws I was referring to, although it got me pondering whether it would be useful or not. It occurred because of a missing accumulation in the main processing loop, and it represents an entire scan line of white pixels. In theory, there could have also been an LN, which would have represented an entire scan line of black pixels, however the test image had a white border.
My thoughts are that if I attempt to turn these flaws into something useful, then I will have to keep count during run time, which I believe would be painful, as compared to just fixing the loop and letting it run.
Once again, in theory, every M should contain at least one pixel and every L should contain at least one pixel.
Thanks for the idea about the shorts
I was somehow missing your posts, lurking here, and thinking what he is up to now?
So really good to see you back!
It took me a while to understand your reason to mirror odd lines in the image, until I read '*.plt", that gave you away!
Sure when plotting (or cutting) a bitmap on a x-y table, that reversal makes a lot of sense.
You could use a count of 0 to signal a complete black line or a complete white line. But I think with the short version you can just add a couple of instruction and will not lose much speed or gain much space in your file doing that.
On the other hand , not allowing a count of 0 while creating the file, makes a lot of sense. Can not happen when you just create the output file from a bitmap of the right size. But if you want to put in scaling, of the bitmap before outputting to the CNC - then it might prevent a lot of unused not-movements.
Enjoy!
Mike
That is really quite a good idea, providing I decide to add the extra command.
Which is one of the pros for M0, or MN.
However the same result could be achieved by adding a header and comparing the very beginning of each new line against bitmap width. For example, let's assume a bitmap width of 10 pixels.
If an entire scan line is represented by M10N, the M10 would be the first command parsed for that scan line
This would or should eliminate a lot of unnecessary movement.
Additionally, the above pseudo-code would not be useful for plot files with alternating scan lines.
EDIT: Okay, I was over thinking this problem. Instead of reorganizing the code, all I really have to do is create my own string reversal function, which reverses the commands, but not the values associated with them.
If you need more commands, you can "steal" another bit or two from the short. For example:
If you even need to encode more than 8191 on or off pixels in a row, you just make two of them in a row:
000_1111111111 = move 8191
000_0000001111 = move 15 more
This means your entire stream just contains a series of binary short values, written to the file like this:
If your lines are less than 8192 in length, you technically don't need "fill/skip" line commands, because a "draw or skip" of that many pixels accomplishes the same thing. You could save a couple command bits by doing that, and be able to make your lines longer (like up to 16383).
If the endianness is reversed on the Prop (I can't remember for sure) you'd insert this line in between the above two, but only in the PC code:
Also, I **hate** that 8 ) is read as 8) even in 'code' blocks on this board.