blob: 56ff95053509ce7519af516d9b015cae8c6b7fec [file] [log] [blame]
/* pngwtran.c - transforms the data in a row for PNG writers
*
* Last changed in libpng 1.6.17 [(PENDING RELEASE)]
* Copyright (c) 1998-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
*/
#include "pngpriv.h"
#define PNG_SRC_FILE PNG_SRC_FILE_pngwtran
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
/* Pick out the correct pixels for the interlace pass.
* The basic idea here is to go through the row with a source
* pointer and a destination pointer (sp and dp), and copy the
* correct pixels for the pass. As the row gets compacted,
* sp will always be >= dp, so we should never overwrite anything.
* See the default: case for the easiest code to understand.
*/
static void
png_do_write_interlace_lbd(png_transformp *transform, png_transform_controlp tc)
{
const png_const_structrp png_ptr = tc->png_ptr;
const unsigned int pass = png_ptr->pass;
const png_uint_32 row_width = tc->width;
const png_uint_32 output_width = PNG_PASS_COLS(row_width, pass);
png_uint_32 i = PNG_PASS_START_COL(pass);
png_debug(1, "in png_do_write_interlace");
debug(!tc->init);
/* The data can be used in place (tc->sp) if the width isn't changed or
* the first pixel in the output is the first in the input and there is
* only one pixel in the output; this covers the last pass (PNG pass 7,
* libpng 6) and PNG passes 1, 3 and 5 with narrow images.
*/
tc->width = output_width;
if (row_width != output_width && (output_width != 1 || i > 0))
{
/* For passes before the last the pixels must be picked from the input
* row (tc->sp) and placed into the output row (tc->dp).
*/
png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
png_bytep dp = png_voidcast(png_bytep, tc->dp);
const unsigned int inc = PNG_PASS_COL_OFFSET(pass);
unsigned int B = (*transform)->args & 0x3; /* 0, 1 or 2 */
/* The row data will be moved, so do this now before 'dp' is advanced:
*/
tc->sp = dp;
/* For pixels less than one byte wide the correct pixels have to be
* extracted from the input bytes. Because we are reading data in
* the application memory format we cannot rely on the PNG big
* endian order. Notice that this was apparently broken before
* 1.7.0.
*
* In libpng 1.7.0 libpng uses a classic bit-pump to optimize the
* extraction. In all passes before the last (6/7) no two pixels
* are adjacent in the input, so we are always extracting 1 bit.
* At present the code uses an 8-bit buffer to avoid coding for
* different byte sexes, but this could easily be changed.
*
* 'i' is the bit-index of bit in the input (sp[]), so,
* considering the 1-bit per pixel case, sp[i>>3] is the byte
* and the bit is bit (i&7) (0 lowest) on swapped (little endian)
* data or 7-(i&7) on PNG default (big-endian) data.
*
* Define these macros, where:
*
* B: the log2 bit depth (0, 1, 2 for 1bpp, 2bpp or 4bpp) of
* the data; this should be a constant.
* sp: the source pointer (sp) (a png_const_bytep)
* i: the pixel index in the input (png_uint_32)
* j: the bit index in the output (unsigned int)
*
* Unlike 'i', 'j' is interpreted directly; for LSB bytes it counts
* up, for MSB it counts down.
*
* NOTE: this could all be expanded to eliminate the code below by
* the time honoured copy'n'paste into three separate functions. This
* might be worth doing in the future.
*/
# define PIXEL_MASK ((1U << (1<<B))-1U)
# define BIT_MASK ((1U << (3-(B)))-1U) /* within a byte */
# define SP_BYTE (sp[i>>(3-(B))]) /* byte to use */
# define SP_OFFSET_LSB ((BIT_MASK & i) << (B))
# define SP_OFFSET_MSB ((BIT_MASK & ~i) << (B))
# define SP_PIXEL(sex) ((SP_BYTE >> SP_OFFSET_ ## sex) & PIXEL_MASK)
{
unsigned int j;
unsigned int d;
# ifdef PNG_WRITE_PACKSWAP_SUPPORTED
if (tc->format & PNG_FORMAT_FLAG_SWAPPED)
for (j = 0, d = 0; i < row_width; i += inc)
{ /* little-endian */
d |= SP_PIXEL(LSB) << j;
j += 1<<B;
if (j == 8) *dp++ = png_check_byte(png_ptr, d), j = 0, d = 0;
}
else
# endif /* WRITE_PACKSWAP */
for (j = 8, d = 0; i < row_width; i += inc)
{ /* big-endian */
j -= 1<<B;
d |= SP_PIXEL(MSB) << j;
if (j == 0) *dp++ = png_check_byte(png_ptr, d), j = 8, d = 0;
}
/* The end condition: if j is not 0 the last byte was not
* written:
*/
if (j != 0) *dp = png_check_byte(png_ptr, d);
}
# undef PIXEL_MASK
# undef BIT_MASK
# undef SP_BYTE
# undef SP_OFFSET_MSB
# undef SP_OFFSET_LSB
# undef SP_PIXEL
}
/* The transform is removed on the last pass. It can be removed earlier
* in other cases if the row width (the image width) is only 1, however
* this does not seem worth the overhead to check; PNG pass 5(4) happens
* if there are just three rows.
*/
else /* the source can be used in place */ if (pass == 6)
(*transform)->fn = NULL; /* remove me to caller */
}
static void
png_do_write_interlace_byte(png_transformp *transform,
png_transform_controlp tc)
{
const png_const_structrp png_ptr = tc->png_ptr;
const unsigned int pass = png_ptr->pass;
const png_uint_32 row_width = tc->width;
const png_uint_32 output_width = PNG_PASS_COLS(row_width, pass);
png_uint_32 i = PNG_PASS_START_COL(pass);
png_debug(1, "in png_do_write_interlace");
debug(!tc->init);
/* The data can be used in place (tc->sp) if the width isn't changed or
* the first pixel in the output is the first in the input and there is
* only one pixel in the output; this covers the last pass (PNG pass 7,
* libpng 6) and PNG passes 1, 3 and 5 with narrow images.
*/
tc->width = output_width;
if (row_width != output_width && (output_width != 1 || i > 0))
{
/* For passes before the last the pixels must be picked from the input
* row (tc->sp) and placed into the output row (tc->dp).
*/
png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
png_bytep dp = png_voidcast(png_bytep, tc->dp);
const unsigned int inc = PNG_PASS_COL_OFFSET(pass);
unsigned int cbytes = (*transform)->args;
/* The row data will be moved, so do this now before 'dp' is advanced:
*/
tc->sp = dp;
/* Loop through the input copying each pixel to the correct place
* in the output. Note that the loop may be executed 0 times if
* this is called on a narrow image that does not contain this
* pass.
*/
for (sp += i * cbytes; i < row_width;
i += inc, sp += inc * cbytes, dp += cbytes)
if (dp != sp) /* cannot happen in practice */
memcpy(dp, sp, cbytes);
}
/* The transform is removed on the last pass. It can be removed earlier
* in other cases if the row width (the image width) is only 1, however
* this does not seem worth the overhead to check; PNG pass 5(4) happens
* if there are just three rows.
*/
else /* the source can be used in place */ if (pass == 6)
(*transform)->fn = NULL; /* remove me to caller */
}
static void
png_init_write_interlace(png_transformp *transform, png_transform_controlp tc)
{
# define png_ptr (tc->png_ptr)
png_debug(1, "in png_do_write_interlace");
debug(tc->init);
/* Do nothing on PNG_TC_INIT_FORMAT because we don't change the format, bit
* depth or gamma of the data.
*/
if (tc->init == PNG_TC_INIT_FINAL)
{
png_transformp tf = *transform;
unsigned int pixel_depth = PNG_TC_PIXEL_DEPTH(*tc);
png_uint_16 B = 0;
switch (pixel_depth)
{
case 4: /* B == 2 */
++B;
/* FALL THROUGH */
case 2: /* B == 1 */
++B;
/* FALL THROUGH */
case 1: /* B == 0 */
/* This is the low bit depth case: */
tf->args = B;
tf->fn = png_do_write_interlace_lbd;
break;
default:
affirm((pixel_depth & 7) == 0);
pixel_depth >>= 3;
affirm(pixel_depth > 0 && pixel_depth <= 8);
tf->args = pixel_depth & 0xf;
tf->fn = png_do_write_interlace_byte;
break;
}
}
# undef png_ptr
}
void /* PRIVATE */
png_set_write_interlace(png_structrp png_ptr)
{
/* This is checked in the caller: */
debug(png_ptr->interlaced == PNG_INTERLACE_ADAM7);
png_add_transform(png_ptr, 0, png_init_write_interlace, PNG_TR_INTERLACE);
}
#endif /* WRITE_INTERLACING */
#ifdef PNG_WRITE_PACK_SUPPORTED
/* Pack pixels into bytes. */
static void
png_do_write_pack(png_transformp *transform, png_transform_controlp tc)
{
png_alloc_size_t rowbytes = PNG_TC_ROWBYTES(*tc);
png_const_bytep sp = png_voidcast(png_const_bytep, tc->sp);
png_const_bytep ep = png_upcast(png_const_bytep, tc->sp) + rowbytes;
png_bytep dp = png_voidcast(png_bytep, tc->dp);
png_debug(1, "in png_do_pack");
# define png_ptr tc->png_ptr
switch ((*transform)->args)
{
case 1:
{
unsigned int mask = 0x80, v = 0;
while (sp < ep)
{
if (*sp++ != 0)
v |= mask;
mask >>= 1;
if (mask == 0)
{
mask = 0x80;
*dp++ = PNG_BYTE(v);
v = 0;
}
}
if (mask != 0x80)
*dp++ = PNG_BYTE(v);
break;
}
case 2:
{
unsigned int shift = 8, v = 0;
while (sp < ep)
{
shift -= 2;
v |= (*sp++ & 0x3) << shift;
if (shift == 0)
{
shift = 8;
*dp++ = PNG_BYTE(v);
v = 0;
}
}
if (shift != 8)
*dp++ = PNG_BYTE(v);
break;
}
case 4:
{
unsigned int shift = 8, v = 0;
while (sp < ep)
{
shift -= 4;
v |= ((*sp++ & 0xf) << shift);
if (shift == 0)
{
shift = 8;
*dp++ = PNG_BYTE(v);
v = 0;
}
}
if (shift != 8)
*dp++ = PNG_BYTE(v);
break;
}
default:
impossible("bit depth");
}
if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0 &&
--(tc->range) == 0)
tc->format &= PNG_BIC_MASK(PNG_FORMAT_FLAG_RANGE);
tc->bit_depth = (*transform)->args;
tc->sp = tc->dp;
# undef png_ptr
}
void /* PRIVATE */
png_init_write_pack(png_transformp *transform, png_transform_controlp tc)
{
# define png_ptr tc->png_ptr
debug(tc->init);
# undef png_ptr
/* The init routine is called *forward* so the transform control we get has
* the required bit depth and the transform routine will increase it to 8
* bits per channel. The code doesn't really care how many channels there
* are, but the only way to get a channel depth of less than 8 is to have
* just one channel.
*/
if (tc->bit_depth < 8) /* else no packing/unpacking */
{
if (tc->init == PNG_TC_INIT_FINAL)
{
(*transform)->fn = png_do_write_pack;
/* Record this for the backwards run: */
(*transform)->args = tc->bit_depth & 0xf;
}
if ((tc->format & PNG_FORMAT_FLAG_COLORMAP) == 0)
{
tc->range++;
tc->format |= PNG_FORMAT_FLAG_RANGE; /* forwards: backwards cancels */
}
tc->bit_depth = 8;
}
else /* the transform is not applicable */
(*transform)->fn = NULL;
}
#endif /* WRITE_PACK */