BMP load/save code
BlitzPlus Forums/BlitzPlus Programming/BMP load/save code
| ||
Hi, Has anyone made any code to read BMP files? I need to be able to read, work on and save individual pixels. Andy |
| ||
Someone was saying somewhere that bmp files are stored in 32bit integers (8 bits nothing, 8 bits red, 8 bits green, 8 bits blue) and read from bottom to top. I would wager that that's all you need to know. |
| ||
Guess I was somewhat correct (they aren't 32bit). Did some tests, came up with the following: 54 bytes to header byte 1 is "B" byte 2 is "M" bytes 19-22 is width (32bit integer) bytes 23-26 is height (32bit integer) byte 29 is bits/pixel 8 bit or lower images have color table immediately following header image data is stored bottom to top, left to right in 8 bit images as (didn't check) format in 24 bit images as (8b, 8g, 8r) format (notice NOT RGB) I wrote up this short code to load in a bmp image and display it: Graphics 640, 480, 0, 2 filein = ReadFile ("image.bmp") verify$ = Chr$(ReadByte(filein)) + Chr$(ReadByte(filein)) If verify$ <> "BM" Then RuntimeError("Not a .bmp file") For y = 1 To 16 ReadByte(filein) Next width = ReadInt(filein) height = ReadInt(filein) For y = 1 To 2 ReadByte(filein) Next bpp = ReadByte(filein) For y = 1 To 25 ReadByte(filein) Next Select bpp Case 8 ;?? Case 24 For y = height To 1 Step -1 For x = 1 To width b = ReadByte(filein) g = ReadByte(filein) r = ReadByte(filein) Color r, g, b Plot x, y ;Plot x*2, y*2 ;Plot x*2+1, y*2 ;Plot x*2+1, y*2+1 ;Plot x*2, y*2+1 Next Next End Select WaitKey() End I didn't bother checking into 8 bit images. There's a lot more info in the header that I'm not sure what they're for, so the code just skips through them. Maybe somebody else knows. |
| ||
Maybe some leftovers from the pallete era, you know that you needed a color pallete to set for your image... The code could be handy... If you need with LoadImage? Maybe, I could use a certain code because there are some image I don't want to pre-load as they only pop-up in the screen once (like a logo or a title screen)... All I know about BMP is that's the only format that holds no form of compression in it, and is with that the largest image format in the world... But that's MicroSoft's trademark... |
| ||
Oh yeah, I tried your code... It does not work very well... It was first black-white, and second the picture is eh... (What's the English word for "Scheef"?).... I'll post a screenshot of the result one of these days... |
| ||
>WolRon< I havent tried it yet, but I really appreciate your code, and interest. >Tricrokra< It may not be perfect, but WolRon pointed me in the right direction... I need to process a large BMP pixel by pixel, and I have found no software that can do what I need it to do, so I have to write it myself. Andy |
| ||
http://www.blitzcoder.com/cgi-bin/showcase/showcase_showentry.pl?id=snarty12082002081455&comments=no Something I started on, never finished it though, but, could be useful to you. |
| ||
Maybe some leftovers from the pallete era, you know that you needed a color pallete to set for your image... No, the color palette is seperate from the header and in 8 bit images immediately follows the header. There is no color palette in 24 bit images. Oh yeah, I tried your code... It does not work very well... Funny, it worked fine for all of the images I loaded with it. Maybe what you loaded was something other than 24 bit (16, 15, 8, 4, 2)? Is there possibly something such as 32 bit bitmaps? |
| ||
What's the English word for "Scheef"? In this case you would probably say "slanted" or "leaning at an angle". Other possibilities: oblique, angled, tilted, leaning, skewed, sheared, etc. =) |
| ||
Perhaps the images you tried that went wrong were saved with run length encoding ? this might help explain it in a bit more detail. http://www.daubnet.com/formats/BMP.html |
| ||
The info on daubnet seems to have some inaccuracies (at least from what I can decipher so far), especially the 24 bit images stored as RGB0 and not needing to be 32bit aligned. From what I can tell so far, 24 bit images are stored as BGR and 32bit aligned at the end of each row (if necessary). Note to Tricrokra: The initial code I posted wasn't 32bit aligning each row, and so (by chance) all of the files I tried worked but the ones you did didn't. I will post an updated version soon. |
| ||
Something I wrote a while ago and (I think) I forgot to post. Maybe I didn't post it because I wasn't finished. Here's what I came up with so far.;Bitmap reader/viewer Dim ColorTable(255, 2) Graphics 640, 480, 0, 2 .beginning Cls Color 255, 255, 255 filename$ = Input ("Enter filename to view:") If filename$ = "" Then End If Right$(filename$, 4) <> ".bmp" Then filename$ = filename$ + ".bmp" Cls filein = ReadFile (filename$) If filein = 0 Then RuntimeError("File not found.") ;verify if a .bmp file Signature$ = Chr$(ReadByte(filein)) + Chr$(ReadByte(filein)) If Signature$ <> "BM" Then RuntimeError("Not a .bmp file") ;read in header info SizeFile = ReadInt(filein) ReadInt(filein) ;unused DataOffset = ReadInt(filein) InfoSize = ReadInt(filein) Width = ReadInt(filein) Height = ReadInt(filein) Planes = ReadShort(filein) BitsPerPixel = ReadShort(filein) CompressionType = ReadInt(filein) ImageSize = ReadInt(filein) XpixelsPerMeter = ReadInt(filein) YpixelsPerMeter = ReadInt(filein) ColorsUsed = ReadInt(filein) ColorsImportant = ReadInt(filein) ;set data NumColors = 2^BitsPerPixel ;read in color table if necessary If BitsPerPixel <= 8 Then ;read in color table For iter = 0 To NumColors-1 ColorTable(iter, 0) = ReadByte(filein) ColorTable(iter, 1) = ReadByte(filein) ColorTable(iter, 2) = ReadByte(filein) ReadByte(filein) ;unused Next EndIf ;read in raster data ;select compression type If CompressionType = 0 ;No compression Select BitsPerPixel Case 1 SeekFile(filein, DataOffset) align = 3 - (width Mod 4) ;If align > 0 And align < 3 Then align = 3 - align For y = Height To 1 Step -1 x = 8 While x < Width pixels = ReadByte(filein) pixel = (pixels And $80) Shr 7 Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x, y pixel = pixels And $40 Shr 6 Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x+1, y pixel = (pixels And $20) Shr 5 Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x+2, y pixel = pixels And $10 Shr 4 Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x+3, y pixel = pixels And $08 Shr 3 Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x+4, y pixel = (pixels And $04) Shr 2 Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x+5, y pixel = pixels And $02 Shr 1 Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x+6, y pixel = pixels And $01 Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x+7, y x = x + 8 Wend If x > Width pixels = ReadByte(filein) For iter = 1 To x - Width Pixel = (Pixels And ($01 Shl (8-iter))) Shr (8-iter) Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x, y Next EndIf For iter = 1 To align ReadByte(filein) Next Next Case 4 SeekFile(filein, DataOffset) align = 3 - (width Mod 4) If align > 0 And align < 3 Then align = 3 - align For y = Height To 1 Step -1 x = 2 While x < Width pixels = ReadByte(filein) pixel = (pixels And $F0) Shr 4 Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x, y pixel = pixels And $0F Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x+1, y x = x + 2 Wend If x > Width pixel = (ReadByte(filein) And $F0) Shr 4 Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x, y EndIf For iter = 1 To align ReadByte(filein) Next Next Case 8 SeekFile(filein, DataOffset) align = 4 - (Width Mod 4) If align = 4 Then align = 0 For y = Height To 1 Step -1 For x = 1 To Width pixel = ReadByte(filein) Color ColorTable(pixel, 0), ColorTable(pixel, 1), ColorTable(pixel, 2) Plot x, y Next For iter = 1 To align ReadByte(filein) Next Next Case 16 SeekFile(filein, DataOffset) align = Width Mod 2 For y = Height To 1 Step -1 For x = 1 To Width pixel = ReadShort(filein) b = pixel And $001F pixel = pixel Shr 5 g = pixel And $003F pixel = pixel Shr 6 r = pixel And $001F Color r, g, b Plot x, y Next For iter = 1 To align ReadShort(filein) Next Next Case 24 SeekFile(filein, DataOffset) align = Width Mod 4 For y = Height To 1 Step -1 For x = 1 To Width b = ReadByte(filein) g = ReadByte(filein) r = ReadByte(filein) Color r, g, b Plot x, y Next For iter = 1 To align ReadByte(filein) Next Next Default RuntimeError("Image format (bits per pixel "+BitsPerPixel+") unknown.") End Select ElseIf CompressionType = 1 ;4bit/16color compression Print "4bit/16color RLE bitmap decompression not implemented yet." ElseIf CompressionType = 2 ;8bit/256color compression Print "8bit/256color RLE bitmap decompression not implemented yet." Else RuntimeError("Image format (compression level "+CompressionType+") unknown.") EndIf WaitKey() Goto beginning End ;Bitmap Information ; ; ;Basic Description ; ;This file format is the MS-Windows standard format. It holds black&white-, 16-Color, 256-Color and Truecolor images. ;The palletized 16-Color and 256-Color images may be compressed via run length encoding. Notice there is also an ;OS/2-BMP format. ; ; ;-------------------------------------------------------------------------------- ; ;Basic File Format ; ; Name Size Description ; ;Header 14 bytes Windows Structure: BITMAPFILEHEADER ; Signature 2 bytes 'BM' ; FileSize 4 bytes File size in bytes ; reserved 4 bytes unused (=0) ; DataOffset 4 bytes File offset To Raster Data ; ;InfoHeader 40 bytes Windows Structure: BITMAPINFOHEADER ; Size 4 bytes Size of InfoHeader =40 ; Width 4 bytes Bitmap Width ; Height 4 bytes Bitmap Height ; Planes 2 bytes Number of Planes (=1) ; BitCount 2 bytes Bits per Pixel ; 1 = monochrome palette. NumColors = 2 ; 4 = 4bit palletized. NumColors = 16 ; 8 = 8bit palletized. NumColors = 256 ; 16 = 16bit RGB. NumColors = 65536 ; 24 = 24bit RGB. NumColors = 16M ; Compression 4 bytes Type of Compression ; 0 = BI_RGB no compression ; 1 = BI_RLE8 8bit RLE encoding ; 2 = BI_RLE4 4bit RLE encoding ; ImageSize 4 bytes (compressed) Size of Image ; It is valid to set this =0 if Compression = 0 ; XpixelsPerM 4 bytes horizontal resolution: Pixels/meter ; YpixelsPerM 4 bytes vertical resolution: Pixels/meter ; ColorsUsed 4 bytes Number of actually used colors ; ColorsImportant 4 bytes Number of important colors ; 0 = all ; ;ColorTable 4 * NumColors bytes Present only if Info.BitsPerPixel <= 8 ; colors should be ordered by importance ; Red 1 byte Red intensity ; Green 1 byte Green intensity ; Blue 1 byte Blue intensity ; reserved 1 byte unused (=0) ; repeated NumColors times ; ;Raster Data Info.ImageSize bytes The pixel Data ; ; ; ;-------------------------------------------------------------------------------- ; ;Raster Data encoding ; ;Depending on the image's BitCount and on the Compression flag there are 6 different encoding schemes. All of them ;share the following: ;Pixels are stored bottom-up, left-to-right. Pixel lines are padded with zeros to end on a 32bit (4byte) boundary. ;For uncompressed formats every line will have the same number of bytes. Color indices are zero based, meaning a ;pixel color of 0 represents the first color table entry, a pixel color of 255 (If there are that many) represents ;the 256th entry. For images with more than 256 colors there is no color table. ; ; ; ;Raster Data encoding for 1bit / black & white images ; ;BitCount = 1 Compression = 0 ;Every byte holds 8 pixels, its highest order bit representing the leftmost pixel of those. There are 2 color table ;entries. Some readers will ignore them though, and assume that 0 is black and 1 is white. If you are storing black ;and white pictures you should stick to this. With any other 2 colors this is not an issue. Remember padding with ;zeros up to a 32bit boundary (This can be up to 31 zeros/pixels!) ; ; ;Raster Data encoding for 4bit / 16 Color images ; ;BitCount = 4 Compression = 0 ;Every byte holds 2 pixels, its high order 4 bits representing the left of those. There are 16 Color table entries. ;These colors do not have to be the 16 MS-Windows standard colors. Padding each line with zeros up to a 32bit ;boundary will result in up to 28 zeros = 7 'wasted pixels'. ; ; ;Raster Data encoding for 8bit / 256 Color images ; ;BitCount = 8 Compression = 0 ;Every byte holds 1 pixel. There are 256 color table entries. Padding each line with zeros up to a 32bit boundary ;will result in up to 3 bytes of zeros = 3 'wasted pixels'. ; ; ;Raster Data encoding for 16bit / hicolor images ; ;BitCount = 16 Compression = 0 ;Every 2bytes / 16bit holds 1 pixel. ;<information missing: the 16 bit was introduced together with Video For Windows? Is it a memory-only-format?> ;The pixels are no color table pointers. There are no color table entries. Padding each line with zeros up to a ;16bit boundary will result in up to 2 zero bytes. ; ; ;Raster Data encoding for 24bit / truecolor images ; ;BitCount = 24 Compression = 0 ;Every 4bytes / 32bit holds 1 pixel. The first holds its red, the second its green, and the third its blue ;intensity. The fourth byte is reserved and should be zero. There are no color table entries. The pixels are no ;color table pointers. No zero padding necessary. ; ; ;Raster Data compression for 4bit / 16 Color images ; ;BitCount = 4 Compression = 2 ;The pixel data is stored in 2bytes / 16bit chunks. The first of these specifies the number of consecutive pixels ;with the same pair of color. The second byte defines two color indices. The resulting pixel pattern will be ;interleaved high-order 4bits and low order 4 bits (ABABA...). If the first byte is zero, the second defines an ;escape code. The end-of-Bitmap is zero padded to end on a 32bit boundary. Due to the 16bit-ness of this structure ;this will always be either two zero bytes or none. ; ; n (byte 1) c (Byte 2) Description ; ; >0 any n pixels are to be drawn. The 1st, 3rd, 5th, ... pixels' color is in c's ; high-order 4 bits, the even pixels' color is in c's low-order 4 bits. If both ; color indices are the same, it results in just n pixels of color c ; 0 0 End-of-Line ; 0 1 End-of-Bitmap ; 0 2 Delta. The following 2 bytes define an unsigned offset in x and y direction ; (y being up) The skipped pixels should get a color zero. ; 0 >=3 The following c bytes will be read as single pixel colors just as in ; uncompressed files. Up to 12 bits of zeros follow, to put the file/memory ; pointer on a 16bit boundary again. ; ; Example For 4bit RLE ; ; Compressed Data Expanded Data ; ; 03 04 0 4 0 ; 05 06 0 6 0 6 0 ; 00 06 45 56 67 00 4 5 5 6 6 7 ; 04 78 7 8 7 8 ; 00 02 05 01 Move 5 Right And 1 up. (Windows docs say down, which is wrong) ; 00 00 End-of-Line ; 09 1E 1 E 1 E 1 E 1 E 1 ; 00 01 EndofBitmap ; 00 00 Zero padding For 32bit boundary ; ; ; ;Raster Data compression For 8bit / 256 Color images ; ;BitCount = 8 Compression = 1 ;The pixel data is stored in 2bytes / 16bit chunks. The first of these specifies the number of consecutive pixels ;with the same color. The second byte defines their color index. If the first byte is zero, the second defines an ;escape code. The End-of-Bitmap is zero padded to end on a 32bit boundary. Due to the 16bit-ness of this structure ;this will always be either two zero bytes or none. ; ; n (byte 1) c (Byte 2) Description ; ; >0 any n pixels of color number c ; 0 0 End-of-Line ; 0 1 End-Of-Bitmap ; 0 2 Delta. The following 2 bytes define an unsigned offset in x and y direction ; (y being up) The skipped pixels should get a color zero. ; 0 >=3 The following c bytes will be read as single pixel colors just as in ; uncompressed files. A zero follows, If c is odd, putting the file/memory ; pointer on a 16bit boundary again. ; ; Example For 8bit RLE ; ; Compressed Data Expanded Data ; ; 03 04 04 04 04 ; 05 06 06 06 06 06 06 ; 00 03 45 56 67 00 45 56 67 ; 02 78 78 78 ; 00 02 05 01 Move 5 right and 1 up. (Windows docs say down, which is wrong) ; 00 00 End-of-Line ; 09 1E 1E 1E 1E 1E 1E 1E 1E 1E 1E ; 00 01 End-of-bitmap ; 00 00 Zero padding for 32bit boundary ; ; ; ;-------------------------------------------------------------------------------- ; ;Portability ;Although BMPs were invented by Microsoft for its Windows platform, a lot of programs on other platforms are ;capable of reading and writing them. Notice the Intel order in 2byte and 4-byte integer values (Least significant ;byte first). The 16bit BMPs have been introduced to Windows after the others, still puzzling many applications. ; ; ;end of file |
| ||
Maybe a stupid question, but why don't you simply use: img=loadimage(path$) savebuffer imagebuffer(img),path2$ |
| ||
>Maybe a stupid question, but why don't you simply use: Because fitting a 4GB BMP in 512MB doesn't work, and none of my otherwise excellent imagemanipulation programs can cope without killing Windows. But an adaptation of the above works, so now I can process the entire image witot killing Windows. It does take a while though. Andy |
| ||
That's one biiiiig bitmap. What's it for? :-) |
| ||
4G -- roffl use png or jpg lol |
| ||
>That's one biiiiig bitmap. What's it for? :-) Heh... If I told ya, I would have to kill ya! Seriously, I am trying to map all land on the earth, from a giant BMP. The funny thing is that now I need to do the same on a png, so I have to go make a png load routine in Blitz... Andy |