Add bmp file format.
This commit is contained in:
parent
cb50a1cb86
commit
f8ea6c3717
67
src/pixie/fileformats/bmp.nim
Normal file
67
src/pixie/fileformats/bmp.nim
Normal file
|
@ -0,0 +1,67 @@
|
|||
import ../images, flatty/binny, flatty/hexPrint, chroma, sequtils
|
||||
|
||||
# See: https://en.wikipedia.org/wiki/BMP_file_format
|
||||
|
||||
proc decodeBmp*(data: string): Image =
|
||||
## Decodes bitmap data into an Image.
|
||||
|
||||
# BMP Header
|
||||
doAssert data[0..1] == "BM"
|
||||
let
|
||||
width = data.readInt32(0x12).int
|
||||
height = data.readInt32(0x16).int
|
||||
# TODO: Handle masks.
|
||||
var
|
||||
offset = data.readUInt32(0xA).int
|
||||
|
||||
result = newImage(width, height)
|
||||
|
||||
for y in 0 ..< result.height:
|
||||
for x in 0 ..< result.width:
|
||||
var rgba: ColorRGBA
|
||||
rgba.r = data.readUint8(offset+0)
|
||||
rgba.g = data.readUint8(offset+1)
|
||||
rgba.b = data.readUint8(offset+2)
|
||||
rgba.a = data.readUint8(offset+3)
|
||||
result[x, result.height - y - 1] = rgba
|
||||
offset += 4
|
||||
|
||||
proc encodeBmp*(image: Image): string =
|
||||
## Encodes an image into bitmap data.
|
||||
|
||||
# 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(122) # The offset to the pixel array.
|
||||
|
||||
# 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(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(0) # Number of colors in the palette
|
||||
result.addUint32(0) # 0 means all colors are important
|
||||
result.addUint32(uint32(0x000000FF)) # Red channel.
|
||||
result.addUint32(uint32(0x0000FF00)) # Green channel.
|
||||
result.addUint32(uint32(0x00FF0000)) # Blue channel.
|
||||
result.addUint32(uint32(0xFF000000)) # Alpha channel.
|
||||
result.add("Win ") # little-endian.
|
||||
for i in 0 ..< 48:
|
||||
result.addUint8(0) # Unused
|
||||
|
||||
for y in 0 ..< image.height:
|
||||
for x in 0 ..< image.width:
|
||||
let rgba = image[x, image.height - y - 1]
|
||||
result.addUint8(rgba.r)
|
||||
result.addUint8(rgba.g)
|
||||
result.addUint8(rgba.b)
|
||||
result.addUint8(rgba.a)
|
||||
|
||||
result.writeUInt32(2, result.len.uint32)
|
|
@ -296,4 +296,8 @@ proc draw*(
|
|||
## Thoughts
|
||||
## single draw function that takes a matrix
|
||||
## if matrix is simple integer translation -> fast pass
|
||||
## if blend mode is copy -> even faster path
|
||||
## if matrix is a simple flip -> fast path
|
||||
## if blend mode is copy -> fast path
|
||||
##
|
||||
## Helper function that takes x,y
|
||||
## Helper function that takes x,y and rotation.
|
||||
|
|
BIN
tests/images/bmp/test16x16.bmp
Normal file
BIN
tests/images/bmp/test16x16.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
tests/images/bmp/test4x2.bmp
Normal file
BIN
tests/images/bmp/test4x2.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 154 B |
31
tests/testbmp.nim
Normal file
31
tests/testbmp.nim
Normal file
|
@ -0,0 +1,31 @@
|
|||
import pixie, pixie/fileformats/bmp, chroma, flatty/hexPrint
|
||||
|
||||
block:
|
||||
var image = newImage(4, 2)
|
||||
|
||||
image[0, 0] = rgba(0, 0, 255, 255)
|
||||
image[1, 0] = rgba(0, 255, 0, 255)
|
||||
image[2, 0] = rgba(255, 0, 0, 255)
|
||||
image[3, 0] = rgba(255, 255, 255, 255)
|
||||
|
||||
image[0, 1] = rgba(0, 0, 255, 127)
|
||||
image[1, 1] = rgba(0, 255, 0, 127)
|
||||
image[2, 1] = rgba(255, 0, 0, 127)
|
||||
image[3, 1] = rgba(255, 255, 255, 127)
|
||||
|
||||
writeFile("images/bmp/test4x2.bmp", encodeBmp(image))
|
||||
|
||||
var image2 = decodeBmp(encodeBmp(image))
|
||||
doAssert image2.width == image.width
|
||||
doAssert image2.height == image.height
|
||||
doAssert image2.data == image.data
|
||||
|
||||
block:
|
||||
var image = newImage(16, 16)
|
||||
image.fill(rgba(255, 0, 0, 127))
|
||||
writeFile("images/bmp/test16x16.bmp", encodeBmp(image))
|
||||
|
||||
var image2 = decodeBmp(encodeBmp(image))
|
||||
doAssert image2.width == image.width
|
||||
doAssert image2.height == image.height
|
||||
doAssert image2.data == image.data
|
Loading…
Reference in a new issue