From 9f39c256b6ee3fcdb676f8042b8d43bf4fd60820 Mon Sep 17 00:00:00 2001 From: Brendan Duncan Date: Mon, 15 Jan 2024 16:31:15 -0700 Subject: [PATCH] 2 channel images map to 4 channe --- lib/src/image/pixel_uint8.dart | 41 ++++++++++++++++++++++----------- lib/src/util/color_util.dart | 27 +++++++++++++++++----- test/_data/png/png_LA.png | Bin 0 -> 6318 bytes test/formats/png_test.dart | 7 ++++++ 4 files changed, 55 insertions(+), 20 deletions(-) create mode 100644 test/_data/png/png_LA.png diff --git a/lib/src/image/pixel_uint8.dart b/lib/src/image/pixel_uint8.dart index b54f514d..b71d13e0 100644 --- a/lib/src/image/pixel_uint8.dart +++ b/lib/src/image/pixel_uint8.dart @@ -158,42 +158,54 @@ class PixelUint8 extends Iterable implements Pixel { @override num get g => palette == null - ? numChannels > 1 - ? data[_index + 1] - : 0 + ? numChannels == 2 + ? data[_index] + : numChannels > 1 + ? data[_index + 1] + : 0 : palette!.getGreen(data[_index]); @override set g(num g) { - if (image.numChannels > 1) { + if (numChannels == 2) { + data[_index] = g.clamp(0, 255).toInt(); + } else if (image.numChannels > 1) { data[_index + 1] = g.clamp(0, 255).toInt(); } } @override num get b => palette == null - ? numChannels > 2 - ? data[_index + 2] - : 0 + ? numChannels == 2 + ? data[_index] + : numChannels > 2 + ? data[_index + 2] + : 0 : palette!.getBlue(data[_index]); @override set b(num b) { - if (image.numChannels > 2) { + if (numChannels == 2) { + data[_index] = b.clamp(0, 255).toInt(); + } else if (image.numChannels > 2) { data[_index + 2] = b.clamp(0, 255).toInt(); } } @override num get a => palette == null - ? numChannels > 3 - ? data[_index + 3] - : 255 + ? numChannels == 2 + ? data[_index + 1] + : numChannels > 3 + ? data[_index + 3] + : 255 : palette!.getAlpha(data[_index]); @override set a(num a) { - if (image.numChannels > 3) { + if (numChannels == 2) { + data[_index + 1] = a.clamp(0, 255).toInt(); + } else if (image.numChannels > 3) { data[_index + 3] = a.clamp(0, 255).toInt(); } } @@ -219,9 +231,10 @@ class PixelUint8 extends Iterable implements Pixel { set aNormalized(num v) => a = v * maxChannelValue; @override - num get luminance => getLuminance(this); + num get luminance => numChannels == 2 ? r : getLuminance(this); @override - num get luminanceNormalized => getLuminanceNormalized(this); + num get luminanceNormalized => + numChannels == 2 ? rNormalized : getLuminanceNormalized(this); @override num getChannel(Channel channel) => channel == Channel.luminance diff --git a/lib/src/util/color_util.dart b/lib/src/util/color_util.dart index 496e437e..23137c40 100644 --- a/lib/src/util/color_util.dart +++ b/lib/src/util/color_util.dart @@ -44,12 +44,27 @@ Color _convertColor(Color c, Color c2, num a) { c2[ci] = convertFormatValue(c[ci], fromFormat, format); } } else { - for (var ci = 0; ci < cl; ++ci) { - c2[ci] = convertFormatValue(c[ci], fromFormat, format); - } - final v = cl == 1 ? c2[0] : 0; - for (var ci = cl; ci < numChannels; ++ci) { - c2[ci] = ci == 3 ? a : v; + if (cl == 2) { + final l = convertFormatValue(c[0], fromFormat, format); + if (numChannels == 3) { + c2[0] = l; + c2[1] = l; + c2[2] = l; + } else { + final a = convertFormatValue(c[1], fromFormat, format); + c2[0] = l; + c2[1] = l; + c2[2] = l; + c2[3] = a; + } + } else { + for (var ci = 0; ci < cl; ++ci) { + c2[ci] = convertFormatValue(c[ci], fromFormat, format); + } + final v = cl == 1 ? c2[0] : 0; + for (var ci = cl; ci < numChannels; ++ci) { + c2[ci] = ci == 3 ? a : v; + } } } return c2; diff --git a/test/_data/png/png_LA.png b/test/_data/png/png_LA.png new file mode 100644 index 0000000000000000000000000000000000000000..fd1c2db82779e99c1c9332cef9c8936dda007a6a GIT binary patch literal 6318 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 O2=qUDn&=zz)BggmHn=SS literal 0 HcmV?d00001 diff --git a/test/formats/png_test.dart b/test/formats/png_test.dart index d58dfc8b..bbc47ecc 100644 --- a/test/formats/png_test.dart +++ b/test/formats/png_test.dart @@ -10,6 +10,13 @@ void main() { const buck24Hash = 817446904; Image? buck24Image; + test('luminanceAlpha', () async { + final png = (await decodePngFile('test/_data/png/png_LA.png'))!; + expect(png.numChannels, equals(2)); + final rgba = png.convert(numChannels: 4); + await encodePngFile('$testOutputPath/png/png_LA_rgba.png', rgba); + }); + test('hungry_180', () async { final png = (await decodePngFile('test/_data/png/hungry_180.png'))!; flip(png, direction: FlipDirection.horizontal);