Skip to content

Commit c29a2db

Browse files
author
MaximDude
committed
Foolproofed BMP saving
1 parent d9b1bb0 commit c29a2db

File tree

1 file changed

+98
-93
lines changed

1 file changed

+98
-93
lines changed

cccp-bender-main.bmx

Lines changed: 98 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -45,102 +45,107 @@ Type TBitmapIndex
4545

4646
'Indexed Bitmap File Writer
4747
Function FPixmapToIndexedBitmap(image:TPixmap,filename:String)
48-
'Variables
49-
Local paletteIndex:Int
50-
Local bmpWidth:Int, bmpWidthM4:Int
51-
Local bmpHeight:Int
52-
Local bmpSizeTotal:Int, bmpSizeTotalM4:Int
53-
54-
'Dimensions calc
55-
bmpWidth = PixmapWidth(image)
56-
bmpWidthM4 = ((bmpWidth + 3) / 4) * 4
57-
bmpHeight = PixmapHeight(image)
58-
59-
'Filesize calc
60-
bmpSizeTotal = (14 + 40) + (256 * 4) + (bmpWidthM4 * bmpHeight)
61-
bmpSizeTotalM4 = ((bmpSizeTotal + 3) / 4) * 4
62-
63-
'Begin writing BMP file manually
64-
dataStream = WriteFile(filename)
65-
66-
'------ Bitmap File Header
67-
'Data is stored in little-endian format (least-significant byte first)
68-
dataStream = LittleEndianStream(dataStream)
69-
70-
WriteShort(dataStream,19778) 'File ID (2 bytes (short)) - 19778 (deci) or 42 4D (hex) or BM (ascii) for bitmap
71-
WriteInt(dataStream,bmpSizeTotalM4) 'File Size (4 bytes (signed int))
72-
WriteShort(dataStream,0) 'Reserved (2 bytes)
73-
WriteShort(dataStream,0) 'Reserved (2 bytes)
74-
WriteInt(dataStream,54) 'Pixel Array Offset (4 bytes) - pixel array starts at 54th byte
75-
76-
'------ DIB Header (File Info)
77-
WriteInt(dataStream,40) 'DIB Header Size (4 bytes) - 40 bytes
78-
WriteInt(dataStream,bmpWidth) 'Bitmap Width (4 bytes)
79-
WriteInt(dataStream,bmpHeight) 'Bitmap Height (4 bytes)
80-
WriteShort(dataStream,1) 'Color Planes (2 bytes) - Must be 1
81-
WriteShort(dataStream,8) 'Color Depth (2 bytes) - Bits Per Pixel
82-
WriteInt(dataStream,0) 'Compression Method (4 bytes) - 0 equals BI_RGB (no compression), 1 equals BI_RLE8 (lossless run-length encoding)
83-
WriteInt(dataStream,bmpSizeTotalM4) 'Size of the raw bitmap data (4 bytes) - 0 can be given for BI_RGB bitmaps
84-
WriteInt(dataStream,2835) 'Horizontal resolution of the image (4 bytes) - Pixels Per Metre (2835 PPM equals 72.009 DPI/PPI)
85-
WriteInt(dataStream,2835) 'Vertical resolution of the image (4 bytes) - Pixels Per Metre (2835 PPM equals 72.009 DPI/PPI)
86-
WriteInt(dataStream,256) 'Number of colors in the color palette (4 bytes)
87-
WriteInt(dataStream,0) 'Number of important colors (4 bytes) - 0 when every color is important
88-
89-
'------ Color Table
90-
For paletteIndex = 0 To 255
91-
WriteByte(dataStream,palB[paletteIndex]) 'Blue (4 bytes) - offset 54
92-
WriteByte(dataStream,palG[paletteIndex]) 'Green (4 bytes) - offset 58
93-
WriteByte(dataStream,palR[paletteIndex]) 'Red (4 bytes) - offset 62
94-
WriteByte(dataStream,0) 'Alpha (4 bytes) - offset 66
95-
Next
48+
'Foolproofing
49+
If filename = "" Then
50+
TAppFileIO.FRevertPrep()
51+
Else
52+
'Variables
53+
Local paletteIndex:Int
54+
Local bmpWidth:Int, bmpWidthM4:Int
55+
Local bmpHeight:Int
56+
Local bmpSizeTotal:Int, bmpSizeTotalM4:Int
9657

97-
'------ Pixel Array
98-
Local px:Int, py:Int
99-
Local pixelData:Long
100-
Local bestIndex:Int = 0
101-
Local magenta:Int = 16711935
102-
For py = bmpHeight -1 To 0 Step -1
103-
For px = 0 To bmpWidthM4 -1
104-
'if a valid pixel on canvas
105-
If px < bmpWidth
106-
'Read pixel data
107-
pixelData = ReadPixel(image,px,py)
108-
'skip diffing magenta
109-
If pixelData = 16711935 Then
110-
WriteByte(dataStream,1)
58+
'Dimensions calc
59+
bmpWidth = PixmapWidth(image)
60+
bmpWidthM4 = ((bmpWidth + 3) / 4) * 4
61+
bmpHeight = PixmapHeight(image)
62+
63+
'Filesize calc
64+
bmpSizeTotal = (14 + 40) + (256 * 4) + (bmpWidthM4 * bmpHeight)
65+
bmpSizeTotalM4 = ((bmpSizeTotal + 3) / 4) * 4
66+
67+
'Begin writing BMP file manually
68+
dataStream = WriteFile(filename)
69+
70+
'------ Bitmap File Header
71+
'Data is stored in little-endian format (least-significant byte first)
72+
dataStream = LittleEndianStream(dataStream)
73+
74+
WriteShort(dataStream,19778) 'File ID (2 bytes (short)) - 19778 (deci) or 42 4D (hex) or BM (ascii) for bitmap
75+
WriteInt(dataStream,bmpSizeTotalM4) 'File Size (4 bytes (signed int))
76+
WriteShort(dataStream,0) 'Reserved (2 bytes)
77+
WriteShort(dataStream,0) 'Reserved (2 bytes)
78+
WriteInt(dataStream,54) 'Pixel Array Offset (4 bytes) - pixel array starts at 54th byte
79+
80+
'------ DIB Header (File Info)
81+
WriteInt(dataStream,40) 'DIB Header Size (4 bytes) - 40 bytes
82+
WriteInt(dataStream,bmpWidth) 'Bitmap Width (4 bytes)
83+
WriteInt(dataStream,bmpHeight) 'Bitmap Height (4 bytes)
84+
WriteShort(dataStream,1) 'Color Planes (2 bytes) - Must be 1
85+
WriteShort(dataStream,8) 'Color Depth (2 bytes) - Bits Per Pixel
86+
WriteInt(dataStream,0) 'Compression Method (4 bytes) - 0 equals BI_RGB (no compression)
87+
WriteInt(dataStream,bmpSizeTotalM4) 'Size of the raw bitmap data (4 bytes) - 0 can be given for BI_RGB bitmaps
88+
WriteInt(dataStream,2835) 'Horizontal resolution of the image (4 bytes) - Pixels Per Metre (2835 PPM equals 72.009 DPI/PPI)
89+
WriteInt(dataStream,2835) 'Vertical resolution of the image (4 bytes) - Pixels Per Metre (2835 PPM equals 72.009 DPI/PPI)
90+
WriteInt(dataStream,256) 'Number of colors in the color palette (4 bytes)
91+
WriteInt(dataStream,0) 'Number of important colors (4 bytes) - 0 when every color is important
92+
93+
'------ Color Table
94+
For paletteIndex = 0 To 255
95+
WriteByte(dataStream,palB[paletteIndex]) 'Blue (4 bytes) - offset 54
96+
WriteByte(dataStream,palG[paletteIndex]) 'Green (4 bytes) - offset 58
97+
WriteByte(dataStream,palR[paletteIndex]) 'Red (4 bytes) - offset 62
98+
WriteByte(dataStream,0) 'Alpha (4 bytes) - offset 66
99+
Next
100+
101+
'------ Pixel Array
102+
Local px:Int, py:Int
103+
Local pixelData:Long
104+
Local bestIndex:Int = 0
105+
Local magenta:Int = 16711935
106+
For py = bmpHeight -1 To 0 Step -1
107+
For px = 0 To bmpWidthM4 -1
108+
'if a valid pixel on canvas
109+
If px < bmpWidth
110+
'Read pixel data
111+
pixelData = ReadPixel(image,px,py)
112+
'skip diffing magenta
113+
If pixelData = 16711935 Then
114+
WriteByte(dataStream,1)
115+
Else
116+
'Check all color indexes for best match by pythagora
117+
Local R:Int, G:Int, B:Int
118+
Local RDIFF:Int, GDIFF:Int, BDIFF:Int
119+
Local bestDistance:Int = 17000000
120+
Local distance:Int = 0
121+
For paletteIndex = 0 To 255
122+
R = (pixelData & $00FF0000) Shr 16
123+
G = (pixelData & $FF00) Shr 8
124+
B = (pixelData & $FF)
125+
RDIFF = Abs(R - palR[paletteIndex])
126+
GDIFF = Abs(G - palG[paletteIndex])
127+
BDIFF = Abs(B - palB[paletteIndex])
128+
distance = (RDIFF^2 + GDIFF^2 + BDIFF^2)
129+
If distance <= bestDistance Then
130+
bestIndex = paletteIndex
131+
bestDistance = distance
132+
EndIf
133+
Next
134+
EndIf
135+
WriteByte(dataStream,bestIndex)
111136
Else
112-
'Check all color indexes for best match by pythagora
113-
Local R:Int, G:Int, B:Int
114-
Local RDIFF:Int, GDIFF:Int, BDIFF:Int
115-
Local bestDistance:Int = 17000000
116-
Local distance:Int = 0
117-
For paletteIndex = 0 To 255
118-
R = (pixelData & $00FF0000) Shr 16
119-
G = (pixelData & $FF00) Shr 8
120-
B = (pixelData & $FF)
121-
RDIFF = Abs(R - palR[paletteIndex])
122-
GDIFF = Abs(G - palG[paletteIndex])
123-
BDIFF = Abs(B - palB[paletteIndex])
124-
distance = (RDIFF^2 + GDIFF^2 + BDIFF^2)
125-
If distance <= bestDistance Then
126-
bestIndex = paletteIndex
127-
bestDistance = distance
128-
EndIf
129-
Next
137+
WriteByte(dataStream,0) 'line padding
130138
EndIf
131-
WriteByte(dataStream,bestIndex)
132-
Else
133-
WriteByte(dataStream,0) 'line padding
134-
EndIf
139+
Next
135140
Next
136-
Next
137-
For paletteIndex = 1 To bmpSizeTotalM4 - bmpSizeTotal 'eof padding
138-
WriteByte(dataStream,0)
139-
Next
140-
141-
CloseStream(dataStream)
141+
'eof padding
142+
For paletteIndex = 1 To bmpSizeTotalM4 - bmpSizeTotal
143+
WriteByte(dataStream,0)
144+
Next
145+
'Writing file finished, close stream
146+
CloseStream(dataStream)
147+
EndIf
142148
EndFunction
143-
144149
EndType
145150

146151
Rem
@@ -157,7 +162,7 @@ Type TAppFileIO
157162
Global rdyForSave:Int = False
158163
Global runOnce:Int = False
159164
'File Filters
160-
Global fileFilers:String = "Image Files:png,jpg,bmp"
165+
Global fileFilers:String = "Image Files:png,bmp,jpg"
161166
'Output copy for saving
162167
Global tempOutputImage:TPixmap
163168

@@ -203,7 +208,7 @@ Type TAppFileIO
203208
ElseIf exportedFile <> importedFile Then
204209
'Writing new file
205210
'SavePixmapPNG(tempOutputImage,exportedFile)
206-
TBitmapIndex.FPixmapToIndexedBitmap(tempOutputImage,exportedFile+".bmp")
211+
TBitmapIndex.FPixmapToIndexedBitmap(tempOutputImage,exportedFile)
207212
FRevertPrep()
208213
Else
209214
'On Cancel

0 commit comments

Comments
 (0)