From 033c4b5455daed346875c6ef41ea0bc58d0c1a85 Mon Sep 17 00:00:00 2001 From: Ryan Oldenburg Date: Sun, 12 Jun 2022 11:23:13 -0500 Subject: [PATCH] convertToImage alternative to newImage for straight alpha image formats --- src/pixie.nim | 6 +++--- src/pixie/fileformats/png.nim | 14 ++++++++++++++ src/pixie/fileformats/qoi.nim | 16 +++++++++++++++- tests/benchmark_png.nim | 10 +++++----- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/pixie.nim b/src/pixie.nim index 3b8c5dd..c98d950 100644 --- a/src/pixie.nim +++ b/src/pixie.nim @@ -40,7 +40,7 @@ proc decodeImageDimensions*( proc decodeImage*(data: string): Image {.raises: [PixieError].} = ## Loads an image from memory. if data.len > 8 and data.readUint64(0) == cast[uint64](pngSignature): - newImage(decodePng(data)) + decodePng(data).convertToImage() elif data.len > 2 and data.readUint16(0) == cast[uint16](jpegStartOfImage): decodeJpeg(data) elif data.len > 2 and data.readStr(0, 2) == bmpSignature: @@ -51,7 +51,7 @@ proc decodeImage*(data: string): Image {.raises: [PixieError].} = elif data.len > 6 and data.readStr(0, 6) in gifSignatures: decodeGif(data) elif data.len > (14+8) and data.readStr(0, 4) == qoiSignature: - newImage(decodeQoi(data)) + decodeQoi(data).convertToImage() elif data.len > 9 and data.readStr(0, 2) in ppmSignatures: decodePpm(data) else: @@ -60,7 +60,7 @@ proc decodeImage*(data: string): Image {.raises: [PixieError].} = proc decodeMask*(data: string): Mask {.raises: [PixieError].} = ## Loads a mask from memory. if data.len > 8 and data.readUint64(0) == cast[uint64](pngSignature): - newMask(newImage(decodePng(data))) + newMask(decodePng(data).convertToImage()) else: raise newException(PixieError, "Unsupported mask file format") diff --git a/src/pixie/fileformats/png.nim b/src/pixie/fileformats/png.nim index 7f2f717..7cc98e3 100644 --- a/src/pixie/fileformats/png.nim +++ b/src/pixie/fileformats/png.nim @@ -338,10 +338,24 @@ proc decodeImageData( discard # Not possible, parseHeader validates proc newImage*(png: Png): Image {.raises: [PixieError].} = + ## Creates a new Image from the PNG. result = newImage(png.width, png.height) copyMem(result.data[0].addr, png.data[0].addr, png.data.len * 4) result.data.toPremultipliedAlpha() +proc convertToImage*(png: Png): Image {.raises: [].} = + ## Converts a PNG into an Image by moving the data. This is faster but can + ## only be done once. + type Movable = ref object + width, height, channels: int + data: seq[ColorRGBX] + + result = Image() + result.width = png.width + result.height = png.height + result.data = move cast[Movable](png).data + result.data.toPremultipliedAlpha() + proc decodePngDimensions*( data: pointer, len: int ): ImageDimensions {.raises: [PixieError].} = diff --git a/src/pixie/fileformats/qoi.nim b/src/pixie/fileformats/qoi.nim index 1d6fa4e..5395f6b 100644 --- a/src/pixie/fileformats/qoi.nim +++ b/src/pixie/fileformats/qoi.nim @@ -30,11 +30,25 @@ proc hash(p: ColorRGBA): int = (p.r.int * 3 + p.g.int * 5 + p.b.int * 7 + p.a.int * 11) mod indexLen proc newImage*(qoi: Qoi): Image = - ## Converts raw QOI data to `Image`. + ## Creates a new Image from the QOI. result = newImage(qoi.width, qoi.height) copyMem(result.data[0].addr, qoi.data[0].addr, qoi.data.len * 4) result.data.toPremultipliedAlpha() +proc convertToImage*(qoi: Qoi): Image {.raises: [].} = + ## Converts a QOI into an Image by moving the data. This is faster but can + ## only be done once. + type Movable = ref object + width, height, channels: int + colorspace: Colorspace + data: seq[ColorRGBX] + + result = Image() + result.width = qoi.width + result.height = qoi.height + result.data = move cast[Movable](qoi).data + result.data.toPremultipliedAlpha() + proc decodeQoi*(data: string): Qoi {.raises: [PixieError].} = ## Decompress QOI file format data. if data.len <= 14 or data[0 .. 3] != qoiSignature: diff --git a/tests/benchmark_png.nim b/tests/benchmark_png.nim index 81fcf76..39f2bbc 100644 --- a/tests/benchmark_png.nim +++ b/tests/benchmark_png.nim @@ -13,12 +13,12 @@ block: timeIt "pixie decode": discard decodePng(data) + timeIt "pixie decode + alpha": + discard decodePng(data).convertToImage() + timeIt "pixie encode": discard encodePng(decodedPng) - timeIt "pixie decode + alpha": - discard newImage(decodePng(data)) - timeIt "pixie encode + alpha": discard encodePng(decodedImage) @@ -55,9 +55,9 @@ block: block: timeIt "cairo decode": - discard imageSurfaceCreateFromPng(filePath) + discard imageSurfaceCreateFromPng(filePath.cstring) - let decoded = imageSurfaceCreateFromPng(filePath) + let decoded = imageSurfaceCreateFromPng(filePath.cstring) timeIt "cairo encode": var write: WriteFunc = proc(closure: pointer, data: cstring, len: int32): Status {.cdecl.} =