@@ -6,7 +6,9 @@ import bitops, chroma, flatty/binny, pixie/common, pixie/images
66# https://stackoverflow.com/questions/61788908/windows-clipboard-getclipboarddata-for-cf-dibv5-causes-the-image-on-the-clip
77# https://stackoverflow.com/questions/44177115/copying-from-and-to-clipboard-loses-image-transparency/46424800#46424800
88
9- const bmpSignature* = " BM"
9+ const
10+ bmpSignature* = " BM"
11+ LCS_sRGB = 0x 73524742
1012
1113template failInvalid () =
1214 raise newException (PixieError , " Invalid BMP buffer, unable to load" )
@@ -17,8 +19,7 @@ proc colorMaskShift(color, mask: uint32): uint8 {.inline.} =
1719proc decodeDib * (
1820 data: pointer , len: int , lpBitmapInfo = false
1921): Image {.raises : [PixieError ].} =
20- # # Decodes DIB data into an Image.
21-
22+ # # Decodes DIB data into an image.
2223 if len < 40 :
2324 failInvalid ()
2425
@@ -216,8 +217,7 @@ proc decodeDib*(
216217 result .flipVertical ()
217218
218219proc decodeBmp * (data: string ): Image {.raises : [PixieError ].} =
219- # # Decodes bitmap data into an Image.
220-
220+ # # Decodes bitmap data into an image.
221221 if data.len < 14 :
222222 failInvalid ()
223223
@@ -231,7 +231,6 @@ proc decodeBmpDimensions*(
231231 data: string
232232): ImageDimensions {.raises : [PixieError ].} =
233233 # # Decodes the BMP dimensions.
234-
235234 if data.len < 26 :
236235 failInvalid ()
237236
@@ -242,42 +241,47 @@ proc decodeBmpDimensions*(
242241 result .width = data.readInt32 (18 ).int
243242 result .height = abs (data.readInt32 (22 )).int
244243
245- proc encodeBmp * (image: Image ): string {.raises : [].} =
246- # # Encodes an image into the BMP file format .
244+ proc encodeDib * (image: Image ): string {.raises : [].} =
245+ # # Encodes an image into a DIB .
247246
248- # BMP Header
249- result .add (" BM" ) # The header field used to identify the BMP
250- result .addUint32 (0 ) # The size of the BMP file in bytes.
251- result .addUint16 (0 ) # Reserved.
252- result .addUint16 (0 ) # Reserved.
253- result .addUint32 (122 ) # The offset to the pixel array.
254-
255- # DIB Header
256- result .addUint32 (108 ) # Size of this header
257- result .addInt32 (image.width.int32 ) # Signed integer.
258- result .addInt32 (image.height.int32 ) # Signed integer.
259- result .addUint16 (1 ) # Must be 1 (color planes).
260- result .addUint16 (32 ) # Bits per pixels, only support RGBA.
247+ # BITMAPINFO containing BITMAPV5HEADER
248+ result .addUint32 (124 ) # Size of this header
249+ result .addInt32 (image.width.int32 ) # Signed integer
250+ result .addInt32 (image.height.int32 ) # Signed integer
251+ result .addUint16 (1 ) # Must be 1 (color planes)
252+ result .addUint16 (32 ) # Bits per pixels, only support RGBA
261253 result .addUint32 (3 ) # BI_BITFIELDS, no pixel array compression used
262254 result .addUint32 (32 ) # Size of the raw bitmap data (including padding)
263255 result .addUint32 (2835 ) # Print resolution of the image
264256 result .addUint32 (2835 ) # Print resolution of the image
265257 result .addUint32 (0 ) # Number of colors in the palette
266258 result .addUint32 (0 ) # 0 means all colors are important
267- result .addUint32 (uint32 (0x 000000FF )) # Red channel.
268- result .addUint32 (uint32 (0x 0000FF00 )) # Green channel.
269- result .addUint32 (uint32 (0x 00FF0000 )) # Blue channel.
270- result .addUint32 (uint32 (0x FF000000 )) # Alpha channel.
271- result .add (" Win " ) # little-endian.
272- for i in 0 ..< 48 :
273- result .addUint8 (0 ) # Unused
259+ result .addUint32 (uint32 (0x 000000FF )) # Red channel
260+ result .addUint32 (uint32 (0x 0000FF00 )) # Green channel
261+ result .addUint32 (uint32 (0x 00FF0000 )) # Blue channel
262+ result .addUint32 (uint32 (0x FF000000 )) # Alpha channel
263+ result .addUint32 (LCS_sRGB) # Color space
264+ result .setLen (result .len + 64 ) # Unused
265+ result .addUint32 (0 ) # BITMAPINFO bmiColors 0
266+ result .addUint32 (0 ) # BITMAPINFO bmiColors 1
267+ result .addUint32 (0 ) # BITMAPINFO bmiColors 2
274268
275269 for y in 0 ..< image.height:
276270 for x in 0 ..< image.width:
277271 let rgba = image[x, image.height - y - 1 ].rgba ()
278- result .addUint8 (rgba.r)
279- result .addUint8 (rgba.g)
280- result .addUint8 (rgba.b)
281- result .addUint8 (rgba.a)
272+ result .addUint32 (cast [uint32 ](rgba))
273+
274+ proc encodeBmp * (image: Image ): string {.raises : [].} =
275+ # # Encodes an image into the BMP file format.
276+
277+ # BMP Header
278+ result .add (" BM" ) # The header field used to identify the BMP
279+ result .addUint32 (0 ) # The size of the BMP file in bytes
280+ result .addUint16 (0 ) # Reserved
281+ result .addUint16 (0 ) # Reserved
282+ result .addUint32 (14 + 12 + 124 ) # The offset to the pixel array
283+
284+ # DIB
285+ result .add (encodeDib (image))
282286
283- result .writeUInt32 (2 , result .len.uint32 )
287+ result .writeUint32 (2 , result .len.uint32 )
0 commit comments