1- import chroma, flatty/ binny, ../ common, ../ images, ../ internal
1+ import chroma, flatty/ binny, math, ../ common, ../ images, ../ internal
22
33# See: https://qoiformat.org/qoi-specification.pdf
44
2929proc hash (p: ColorRGBA ): int =
3030 (p.r.int * 3 + p.g.int * 5 + p.b.int * 7 + p.a.int * 11 ) mod indexLen
3131
32+ proc srgbToLinear (value: uint8 ): uint8 {.inline .} =
33+ let c = value.float32 / 255
34+ let linear =
35+ if c <= 0.04045 :
36+ c / 12.92
37+ else :
38+ pow ((c + 0.055 ) / 1.055 , 2.4 )
39+ round (linear * 255 ).uint8
40+
41+ proc srgbToLinear (color: var ColorRGBA ) {.inline .} =
42+ color.r = color.r.srgbToLinear ()
43+ color.g = color.g.srgbToLinear ()
44+ color.b = color.b.srgbToLinear ()
45+
46+ proc srgbToLinear (color: var ColorRGBX ) {.inline .} =
47+ color.r = color.r.srgbToLinear ()
48+ color.g = color.g.srgbToLinear ()
49+ color.b = color.b.srgbToLinear ()
50+
51+ proc srgbToLinear (data: var seq [ColorRGBX ]) =
52+ for color in data.mitems:
53+ color.srgbToLinear ()
54+
55+ proc linearPixel (qoi: Qoi , px: ColorRGBA ): ColorRGBA {.inline .} =
56+ result = px
57+ if qoi.colorspace == sRBG:
58+ result .srgbToLinear ()
59+
3260proc newImage * (qoi: Qoi ): Image =
3361 # # Creates a new Image from the QOI.
3462 result = newImage (qoi.width, qoi.height)
3563 copyMem (result .data[0 ].addr , qoi.data[0 ].addr , qoi.data.len * 4 )
64+ if qoi.colorspace == sRBG:
65+ result .data.srgbToLinear ()
3666 result .data.toPremultipliedAlpha ()
3767
3868proc convertToImage * (qoi: Qoi ): Image {.raises : [].} =
@@ -47,6 +77,8 @@ proc convertToImage*(qoi: Qoi): Image {.raises: [].} =
4777 result .width = qoi.width
4878 result .height = qoi.height
4979 result .data = move cast [Movable ](qoi).data
80+ if qoi.colorspace == sRBG:
81+ result .data.srgbToLinear ()
5082 result .data.toPremultipliedAlpha ()
5183
5284proc decodeQoi * (data: string ): Qoi {.raises : [PixieError ].} =
@@ -166,13 +198,14 @@ proc encodeQoi*(qoi: Qoi): string {.raises: [PixieError].} =
166198 result .addUint32 (qoi.width.uint32 .swap ())
167199 result .addUint32 (qoi.height.uint32 .swap ())
168200 result .addUint8 (qoi.channels.uint8 )
169- result .addUint8 (qoi.colorspace .uint8 )
201+ result .addUint8 (Linear .uint8 )
170202
171203 var
172204 index: Index
173205 run: uint8
174206 pxPrev = rgba (0 , 0 , 0 , 255 )
175- for off, px in qoi.data:
207+ for off, qoiPx in qoi.data:
208+ let px = qoi.linearPixel (qoiPx)
176209 if px == pxPrev:
177210 inc run
178211 if run == 62 or off == qoi.data.high:
@@ -231,6 +264,7 @@ proc encodeQoi*(image: Image): string {.raises: [PixieError].} =
231264 qoi.width = image.width
232265 qoi.height = image.height
233266 qoi.channels = 4
267+ qoi.colorspace = Linear
234268 qoi.data.setLen (image.data.len)
235269
236270 copyMem (qoi.data[0 ].addr , image.data[0 ].addr , image.data.len * 4 )
0 commit comments