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