summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2017-08-13 15:53:36 +1000
committer Vas Crabb <vas@vastheman.com>2017-08-13 15:53:36 +1000
commit44bc3ffa43cdd4cdd886d025d2aacd4da3d357da (patch)
tree639f9ab71f86c6fde652408c594e903f18d2fa81 /src/lib
parent90593ab006312549a9e523df732eada10125eee3 (diff)
png: support 16-bit samples
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/util/png.cpp56
1 files changed, 35 insertions, 21 deletions
diff --git a/src/lib/util/png.cpp b/src/lib/util/png.cpp
index fbc2eca2180..d344c1b72e8 100644
--- a/src/lib/util/png.cpp
+++ b/src/lib/util/png.cpp
@@ -145,16 +145,20 @@ public:
png_error copy_to_bitmap(bitmap_argb32 &bitmap, bool &hasalpha) const
{
// do some basic checks for unsupported images
+ if ((8 > pnginfo.bit_depth) || (pnginfo.bit_depth % 8))
+ return PNGERR_UNSUPPORTED_FORMAT; // only do multiples of 8bps here - expand lower bit depth first
if ((ARRAY_LENGTH(samples) <= pnginfo.color_type) || !samples[pnginfo.color_type])
return PNGERR_UNSUPPORTED_FORMAT; // unknown colour sample format
if ((0 != pnginfo.interlace_method) && (1 != pnginfo.interlace_method))
return PNGERR_UNSUPPORTED_FORMAT; // unknown interlace method
- if (8 != pnginfo.bit_depth)
- return PNGERR_UNSUPPORTED_FORMAT; // only do 8bpp here - expand lower bit depth first
+ if ((3 == pnginfo.color_type) && (8 != pnginfo.bit_depth))
+ return PNGERR_UNSUPPORTED_FORMAT; // indexed colour must be exactly 8bpp
// everything looks sane, allocate the bitmap and deinterlace into it
bitmap.allocate(pnginfo.width, pnginfo.height);
std::uint8_t accumalpha(0xff);
+ uint32_t const bps(pnginfo.bit_depth >> 3);
+ uint32_t const bpp(bps * samples[pnginfo.color_type]);
unsigned const pass_count(get_pass_count());
std::uint32_t pass_offset[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
for (unsigned pass = 0; pass_count > pass; ++pass)
@@ -173,7 +177,7 @@ public:
// handle 8bpp palettized case
for (std::uint32_t y = 0; dimensions.second > y; ++y)
{
- for (std::uint32_t x = 0; dimensions.first > x; ++x, ++src)
+ for (std::uint32_t x = 0; dimensions.first > x; ++x, src += bpp)
{
// determine alpha and expand to 32bpp
std::uint8_t const alpha((*src < pnginfo.num_trans) ? pnginfo.trans[*src] : 0xff);
@@ -186,10 +190,11 @@ public:
}
else if (0 == pnginfo.color_type)
{
- // handle 8bpp grayscale non-alpha case
+ // handle grayscale non-alpha case
+ uint32_t const bpp(pnginfo.bit_depth >> 3);
for (std::uint32_t y = 0; dimensions.second > y; ++y)
{
- for (std::uint32_t x = 0; dimensions.first > x; ++x, ++src)
+ for (std::uint32_t x = 0; dimensions.first > x; ++x, src += bpp)
{
rgb_t const pix(0xff, src[0], src[0], src[0]);
bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
@@ -198,38 +203,47 @@ public:
}
else if (4 == pnginfo.color_type)
{
- // handle 8bpp grayscale alpha case
+ // handle grayscale alpha case
+ uint32_t const i(0 * bps);
+ uint32_t const a(1 * bps);
for (std::uint32_t y = 0; dimensions.second > y; ++y)
{
- for (std::uint32_t x = 0; dimensions.first > x; ++x, src += 2)
+ for (std::uint32_t x = 0; dimensions.first > x; ++x, src += bpp)
{
- accumalpha &= src[1];
- rgb_t const pix(src[1], src[0], src[0], src[0]);
+ accumalpha &= src[a];
+ rgb_t const pix(src[a], src[i], src[i], src[i]);
bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
}
}
}
else if (2 == pnginfo.color_type)
{
- // handle 32bpp non-alpha case
+ // handle RGB non-alpha case
+ uint32_t const r(0 * bps);
+ uint32_t const g(1 * bps);
+ uint32_t const b(2 * bps);
for (std::uint32_t y = 0; dimensions.second > y; ++y)
{
- for (std::uint32_t x = 0; dimensions.first > x; ++x, src += 3)
+ for (std::uint32_t x = 0; dimensions.first > x; ++x, src += bpp)
{
- rgb_t const pix(0xff, src[0], src[1], src[2]);
+ rgb_t const pix(0xff, src[r], src[g], src[b]);
bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
}
}
}
else
{
- // handle 32bpp alpha case
+ // handle RGB alpha case
+ uint32_t const r(0 * bps);
+ uint32_t const g(1 * bps);
+ uint32_t const b(2 * bps);
+ uint32_t const a(3 * bps);
for (std::uint32_t y = 0; dimensions.second > y; ++y)
{
- for (std::uint32_t x = 0; dimensions.first > x; ++x, src += 4)
+ for (std::uint32_t x = 0; dimensions.first > x; ++x, src += bpp)
{
- accumalpha &= src[3];
- rgb_t const pix(src[3], src[0], src[1], src[2]);
+ accumalpha &= src[a];
+ rgb_t const pix(src[a], src[r], src[g], src[b]);
bitmap.pix32((y << y_shift) + y_offs, (x << x_shift) + x_offs) = pix;
}
}
@@ -248,12 +262,12 @@ public:
return PNGERR_NONE;
// do some basic checks for unsupported images
+ if (!pnginfo.bit_depth || (8 % pnginfo.bit_depth))
+ return PNGERR_UNSUPPORTED_FORMAT; // bit depth must be a factor of eight
if ((0 != pnginfo.color_type) && (3 != pnginfo.color_type))
- return PNGERR_UNSUPPORTED_FORMAT; // unknown colour sample format
+ return PNGERR_UNSUPPORTED_FORMAT; // only upsample monochrome and indexed colour
if ((0 != pnginfo.interlace_method) && (1 != pnginfo.interlace_method))
return PNGERR_UNSUPPORTED_FORMAT; // unknown interlace method
- if (!pnginfo.bit_depth || (8 % pnginfo.bit_depth))
- return PNGERR_UNSUPPORTED_FORMAT; // bit depth must be a factor of eight
// calculate the offset for each pass of the interlace on the input and output
unsigned const pass_count(get_pass_count());
@@ -368,8 +382,8 @@ private:
png_error process(std::list<image_data_chunk> const &idata)
{
// do some basic checks for unsupported images
- if ((ARRAY_LENGTH(samples) <= pnginfo.color_type) || !samples[pnginfo.color_type])
- return PNGERR_UNSUPPORTED_FORMAT; // unknown colour sample format
+ if (!pnginfo.bit_depth || (ARRAY_LENGTH(samples) <= pnginfo.color_type) || !samples[pnginfo.color_type])
+ return PNGERR_UNSUPPORTED_FORMAT; // unknown colour format
if ((0 != pnginfo.interlace_method) && (1 != pnginfo.interlace_method))
return PNGERR_UNSUPPORTED_FORMAT; // unknown interlace method