blob: 3aaf2205e0f9ac2774f2c32fd59e6464ad186c7f [file] [log] [blame]
/* pngwtran.c - transforms the data in a row for PNG writers
*
* Last changed in libpng 1.7.0 [(PENDING RELEASE)]
* Copyright (c) 1998-2002,2004,2006-2016 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_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 */