| |
| /* 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_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 */ |