encode dibs for windows clipboard
This commit is contained in:
parent
5f4c15c45c
commit
29b84d7d8e
|
@ -6,7 +6,9 @@ import bitops, chroma, flatty/binny, pixie/common, pixie/images
|
||||||
# https://stackoverflow.com/questions/61788908/windows-clipboard-getclipboarddata-for-cf-dibv5-causes-the-image-on-the-clip
|
# https://stackoverflow.com/questions/61788908/windows-clipboard-getclipboarddata-for-cf-dibv5-causes-the-image-on-the-clip
|
||||||
# https://stackoverflow.com/questions/44177115/copying-from-and-to-clipboard-loses-image-transparency/46424800#46424800
|
# https://stackoverflow.com/questions/44177115/copying-from-and-to-clipboard-loses-image-transparency/46424800#46424800
|
||||||
|
|
||||||
const bmpSignature* = "BM"
|
const
|
||||||
|
bmpSignature* = "BM"
|
||||||
|
LCS_sRGB = 0x73524742
|
||||||
|
|
||||||
template failInvalid() =
|
template failInvalid() =
|
||||||
raise newException(PixieError, "Invalid BMP buffer, unable to load")
|
raise newException(PixieError, "Invalid BMP buffer, unable to load")
|
||||||
|
@ -17,8 +19,7 @@ proc colorMaskShift(color, mask: uint32): uint8 {.inline.} =
|
||||||
proc decodeDib*(
|
proc decodeDib*(
|
||||||
data: pointer, len: int, lpBitmapInfo = false
|
data: pointer, len: int, lpBitmapInfo = false
|
||||||
): Image {.raises: [PixieError].} =
|
): Image {.raises: [PixieError].} =
|
||||||
## Decodes DIB data into an Image.
|
## Decodes DIB data into an image.
|
||||||
|
|
||||||
if len < 40:
|
if len < 40:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
|
@ -216,8 +217,7 @@ proc decodeDib*(
|
||||||
result.flipVertical()
|
result.flipVertical()
|
||||||
|
|
||||||
proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
proc decodeBmp*(data: string): Image {.raises: [PixieError].} =
|
||||||
## Decodes bitmap data into an Image.
|
## Decodes bitmap data into an image.
|
||||||
|
|
||||||
if data.len < 14:
|
if data.len < 14:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
|
@ -231,7 +231,6 @@ proc decodeBmpDimensions*(
|
||||||
data: string
|
data: string
|
||||||
): ImageDimensions {.raises: [PixieError].} =
|
): ImageDimensions {.raises: [PixieError].} =
|
||||||
## Decodes the BMP dimensions.
|
## Decodes the BMP dimensions.
|
||||||
|
|
||||||
if data.len < 26:
|
if data.len < 26:
|
||||||
failInvalid()
|
failInvalid()
|
||||||
|
|
||||||
|
@ -242,42 +241,47 @@ proc decodeBmpDimensions*(
|
||||||
result.width = data.readInt32(18).int
|
result.width = data.readInt32(18).int
|
||||||
result.height = abs(data.readInt32(22)).int
|
result.height = abs(data.readInt32(22)).int
|
||||||
|
|
||||||
proc encodeBmp*(image: Image): string {.raises: [].} =
|
proc encodeDib*(image: Image): string {.raises: [].} =
|
||||||
## Encodes an image into the BMP file format.
|
## Encodes an image into a DIB.
|
||||||
|
|
||||||
# BMP Header
|
# BITMAPINFO containing BITMAPV5HEADER
|
||||||
result.add("BM") # The header field used to identify the BMP
|
result.addUint32(124) # Size of this header
|
||||||
result.addUint32(0) # The size of the BMP file in bytes.
|
result.addInt32(image.width.int32) # Signed integer
|
||||||
result.addUint16(0) # Reserved.
|
result.addInt32(image.height.int32) # Signed integer
|
||||||
result.addUint16(0) # Reserved.
|
result.addUint16(1) # Must be 1 (color planes)
|
||||||
result.addUint32(122) # The offset to the pixel array.
|
result.addUint16(32) # Bits per pixels, only support RGBA
|
||||||
|
|
||||||
# DIB Header
|
|
||||||
result.addUint32(108) # Size of this header
|
|
||||||
result.addInt32(image.width.int32) # Signed integer.
|
|
||||||
result.addInt32(image.height.int32) # Signed integer.
|
|
||||||
result.addUint16(1) # Must be 1 (color planes).
|
|
||||||
result.addUint16(32) # Bits per pixels, only support RGBA.
|
|
||||||
result.addUint32(3) # BI_BITFIELDS, no pixel array compression used
|
result.addUint32(3) # BI_BITFIELDS, no pixel array compression used
|
||||||
result.addUint32(32) # Size of the raw bitmap data (including padding)
|
result.addUint32(32) # Size of the raw bitmap data (including padding)
|
||||||
result.addUint32(2835) # Print resolution of the image
|
result.addUint32(2835) # Print resolution of the image
|
||||||
result.addUint32(2835) # Print resolution of the image
|
result.addUint32(2835) # Print resolution of the image
|
||||||
result.addUint32(0) # Number of colors in the palette
|
result.addUint32(0) # Number of colors in the palette
|
||||||
result.addUint32(0) # 0 means all colors are important
|
result.addUint32(0) # 0 means all colors are important
|
||||||
result.addUint32(uint32(0x000000FF)) # Red channel.
|
result.addUint32(uint32(0x000000FF)) # Red channel
|
||||||
result.addUint32(uint32(0x0000FF00)) # Green channel.
|
result.addUint32(uint32(0x0000FF00)) # Green channel
|
||||||
result.addUint32(uint32(0x00FF0000)) # Blue channel.
|
result.addUint32(uint32(0x00FF0000)) # Blue channel
|
||||||
result.addUint32(uint32(0xFF000000)) # Alpha channel.
|
result.addUint32(uint32(0xFF000000)) # Alpha channel
|
||||||
result.add("Win ") # little-endian.
|
result.addUint32(LCS_sRGB) # Color space
|
||||||
for i in 0 ..< 48:
|
result.setLen(result.len + 64) # Unused
|
||||||
result.addUint8(0) # Unused
|
result.addUint32(0) # BITMAPINFO bmiColors 0
|
||||||
|
result.addUint32(0) # BITMAPINFO bmiColors 1
|
||||||
|
result.addUint32(0) # BITMAPINFO bmiColors 2
|
||||||
|
|
||||||
for y in 0 ..< image.height:
|
for y in 0 ..< image.height:
|
||||||
for x in 0 ..< image.width:
|
for x in 0 ..< image.width:
|
||||||
let rgba = image[x, image.height - y - 1].rgba()
|
let rgba = image[x, image.height - y - 1].rgba()
|
||||||
result.addUint8(rgba.r)
|
result.addUint32(cast[uint32](rgba))
|
||||||
result.addUint8(rgba.g)
|
|
||||||
result.addUint8(rgba.b)
|
|
||||||
result.addUint8(rgba.a)
|
|
||||||
|
|
||||||
result.writeUInt32(2, result.len.uint32)
|
proc encodeBmp*(image: Image): string {.raises: [].} =
|
||||||
|
## Encodes an image into the BMP file format.
|
||||||
|
|
||||||
|
# BMP Header
|
||||||
|
result.add("BM") # The header field used to identify the BMP
|
||||||
|
result.addUint32(0) # The size of the BMP file in bytes
|
||||||
|
result.addUint16(0) # Reserved
|
||||||
|
result.addUint16(0) # Reserved
|
||||||
|
result.addUint32(14 + 12 + 124) # The offset to the pixel array
|
||||||
|
|
||||||
|
# DIB
|
||||||
|
result.add(encodeDib(image))
|
||||||
|
|
||||||
|
result.writeUint32(2, result.len.uint32)
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 890 B After Width: | Height: | Size: 918 B |
Binary file not shown.
Before Width: | Height: | Size: 890 B After Width: | Height: | Size: 918 B |
Binary file not shown.
Before Width: | Height: | Size: 900 KiB After Width: | Height: | Size: 900 KiB |
|
@ -1,4 +1,4 @@
|
||||||
import os, pixie/fileformats/bmp
|
import os, pixie, pixie/fileformats/bmp
|
||||||
|
|
||||||
# block:
|
# block:
|
||||||
# var image = newImage(4, 2)
|
# var image = newImage(4, 2)
|
||||||
|
@ -52,3 +52,13 @@ block:
|
||||||
#image.writeFile(file.replace("bmpsuite", "output") & ".png")
|
#image.writeFile(file.replace("bmpsuite", "output") & ".png")
|
||||||
doAssert image.width == dimensions.width
|
doAssert image.width == dimensions.width
|
||||||
doAssert image.height == dimensions.height
|
doAssert image.height == dimensions.height
|
||||||
|
|
||||||
|
block:
|
||||||
|
let image = newImage(100, 100)
|
||||||
|
image.fill(color(1, 0, 0, 1))
|
||||||
|
|
||||||
|
let
|
||||||
|
encoded = encodeDib(image)
|
||||||
|
decoded = decodeDib(encoded.cstring, encoded.len, true)
|
||||||
|
|
||||||
|
doAssert image.data == decoded.data
|
||||||
|
|
Loading…
Reference in a new issue