Exemplo n.º 1
0
/*
 * Invalidate the unsafe-to-copy metadata that cannot reliably remain
 * after transformations.
 */
static void
opng_transform_invalidate_meta(png_structp libpng_ptr, png_infop info_ptr)
{
    int color_type;

    color_type = png_get_color_type(libpng_ptr, info_ptr);
    if (!(color_type & PNG_COLOR_MASK_PALETTE))
    {
        /* PLTE, if it exists in this situation, has the same role as sPLT. */
        png_set_invalid(libpng_ptr, info_ptr, PNG_INFO_PLTE);
    }
#ifdef PNG_sPLT_SUPPORTED
    png_set_invalid(libpng_ptr, info_ptr, PNG_INFO_sPLT);
#endif
#ifdef PNG_hIST_SUPPORTED
    png_set_invalid(libpng_ptr, info_ptr, PNG_INFO_hIST);
#endif
#ifdef PNG_sBIT_SUPPORTED
    png_set_invalid(libpng_ptr, info_ptr, PNG_INFO_hIST);
#endif
    /* FIXME: Invalidate the unknown unsafe-to-copy chunks. */
}
/*
 * Reduce the palette. (Only the fast method is implemented.)
 * The parameter reductions indicates the intended reductions.
 * The function returns the successful reductions.
 */
static png_uint_32 opng_reduce_palette(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions)
{
   png_colorp palette;
   png_bytep trans_alpha;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type, compression_type, filter_type;
   int num_palette, num_trans;
   int last_color_index, last_trans_index;
   png_byte crt_trans_value, last_trans_value;
   png_byte is_used[256];
   png_color_16 gray_trans;
   png_uint_32 result = OPNG_REDUCE_NONE;

   png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
      &color_type, &interlace_type, &compression_type, &filter_type);
  if (!height || !width){
    return OPNG_REDUCE_NONE;
  }
   png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr);
   if (!png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette))
   {
      palette = 0;
      num_palette = 0;
   }
   if (!png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, 0))
   {
      trans_alpha = 0;
      num_trans = 0;
   }
   else
      OPNG_ASSERT(trans_alpha && num_trans > 0);

   opng_analyze_sample_usage(png_ptr, info_ptr, is_used);
   /* Palette-to-gray does not work (yet) if the bit depth is below 8. */
   int is_gray = (reductions & OPNG_REDUCE_PALETTE_TO_GRAY) && (bit_depth == 8);
   last_color_index = last_trans_index = -1;
    int k;
   for (k= 0; k < 256; ++k)
   {
      if (!is_used[k])
         continue;
      last_color_index = k;
      if (k < num_trans && trans_alpha[k] < 255)
         last_trans_index = k;
      if (is_gray)
         if (palette[k].red != palette[k].green ||
             palette[k].red != palette[k].blue)
            is_gray = 0;
   }
   OPNG_ASSERT(last_color_index >= 0);
   OPNG_ASSERT(last_color_index >= last_trans_index);

   /* Check the integrity of PLTE and tRNS. */
   if (last_color_index >= num_palette)
   {
      png_warning(png_ptr, "Too few colors in PLTE");
      /* Fix the palette by adding blank entries at the end. */
      opng_realloc_PLTE(png_ptr, info_ptr, last_color_index + 1);
      png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
      OPNG_ASSERT(num_palette == last_color_index + 1);
      result |= OPNG_REDUCE_REPAIR;
   }
   if (num_trans > num_palette)
   {
      png_warning(png_ptr, "Too many alpha values in tRNS");
      /* Transparency will be fixed further below. */
      result |= OPNG_REDUCE_REPAIR;
   }

   /* Check if tRNS can be reduced to grayscale. */
   if (is_gray && last_trans_index >= 0)
   {
      gray_trans.gray = palette[last_trans_index].red;
      last_trans_value = trans_alpha[last_trans_index];
      for (k = 0; k <= last_color_index; ++k)
      {
         if (!is_used[k])
            continue;
         if (k <= last_trans_index)
         {
            crt_trans_value = trans_alpha[k];
            /* Cannot reduce if different colors have transparency. */
            if (crt_trans_value < 255 && palette[k].red != gray_trans.gray)
            {
               is_gray = 0;
               break;
            }
         }
         else
            crt_trans_value = 255;
         /* Cannot reduce if same color has multiple transparency levels. */
         if (palette[k].red == gray_trans.gray &&
             crt_trans_value != last_trans_value)
         {
            is_gray = 0;
            break;
         }
      }
   }

   /* Remove tRNS if it is entirely sterile. */
   if (num_trans > 0 && last_trans_index < 0)
   {
      num_trans = 0;
      png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
      png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS);
      result |= OPNG_REDUCE_PALETTE_FAST;
   }

   if (reductions & OPNG_REDUCE_PALETTE_FAST)
   {
      if (num_palette != last_color_index + 1)
      {
         /* Reduce PLTE. */
         /* hIST is reduced automatically. */
         opng_realloc_PLTE(png_ptr, info_ptr, last_color_index + 1);
         png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
         OPNG_ASSERT(num_palette == last_color_index + 1);
         result |= OPNG_REDUCE_PALETTE_FAST;
      }

      if (num_trans > 0 && num_trans != last_trans_index + 1)
      {
         /* Reduce tRNS. */
         opng_realloc_tRNS(png_ptr, info_ptr, last_trans_index + 1);
         png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, 0);
         OPNG_ASSERT(num_trans == last_trans_index + 1);
         result |= OPNG_REDUCE_PALETTE_FAST;
      }
   }

   if (reductions & OPNG_REDUCE_8_TO_4_2_1)
   {
      result |= opng_reduce_palette_bits(png_ptr, info_ptr, reductions);
      /* Refresh the image information. */
      bit_depth = png_get_bit_depth(png_ptr, info_ptr);
   }
   if ((bit_depth < 8) || !is_gray)
      return result;

   /* Reduce palette --> grayscale. */
   for (png_uint_32 i = 0; i < height; ++i)
   {
      for (png_uint_32 j = 0; j < width; ++j)
         row_ptr[i][j] = palette[row_ptr[i][j]].red;
   }

   /* Update the ancillary information. */
   if (num_trans > 0)
      png_set_tRNS(png_ptr, info_ptr, 0, 0, &gray_trans);
#ifdef PNG_bKGD_SUPPORTED
    png_color_16p background;
   if (png_get_bKGD(png_ptr, info_ptr, &background))
      background->gray = palette[background->index].red;
#endif
#ifdef PNG_hIST_SUPPORTED
    png_uint_16p hist;
   if (png_get_hIST(png_ptr, info_ptr, &hist))
   {
      png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, -1);
      png_set_invalid(png_ptr, info_ptr, PNG_INFO_hIST);
   }
#endif
#ifdef PNG_sBIT_SUPPORTED
    png_color_8p sig_bits;
   if (png_get_sBIT(png_ptr, info_ptr, &sig_bits))
   {
      png_byte max_sig_bits = sig_bits->red;
      if (max_sig_bits < sig_bits->green)
         max_sig_bits = sig_bits->green;
      if (max_sig_bits < sig_bits->blue)
         max_sig_bits = sig_bits->blue;
      sig_bits->gray = max_sig_bits;
   }
#endif

   /* Update the image information. */
   png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
      PNG_COLOR_TYPE_GRAY, interlace_type, compression_type, filter_type);
   png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, -1);
   png_set_invalid(png_ptr, info_ptr, PNG_INFO_PLTE);
   return OPNG_REDUCE_PALETTE_TO_GRAY;  /* ignore the former result */
}
/*
 * Reduce the image type to a lower bit depth and color type,
 * by removing redundant bits.
 * Possible reductions: 16bpp to 8bpp; RGB to gray; strip alpha.
 * The parameter reductions indicates the intended reductions.
 * The function returns the successful reductions.
 * All reductions are performed in a single step.
 */
static png_uint_32  opng_reduce_bits(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions)
{
   png_bytep src_ptr, dest_ptr;
   png_uint_32 width, height;
   int interlace_type, compression_type, filter_type, src_bit_depth, dest_bit_depth, src_color_type;
   /* See which reductions may be performed. */
   reductions = opng_analyze_bits(png_ptr, info_ptr, reductions);
   if (reductions == OPNG_REDUCE_NONE)
      return OPNG_REDUCE_NONE;  /* exit early */

   png_get_IHDR(png_ptr, info_ptr, &width, &height,
      &src_bit_depth, &src_color_type,
      &interlace_type, &compression_type, &filter_type);
  if (!height || !width){
    return OPNG_REDUCE_NONE;
  }
   /* Compute the new image parameters bit_depth, color_type, etc. */
   OPNG_ASSERT(src_bit_depth >= 8);
   if (reductions & OPNG_REDUCE_16_TO_8)
   {
      OPNG_ASSERT(src_bit_depth == 16);
      dest_bit_depth = 8;
   }
   else
      dest_bit_depth = src_bit_depth;

   int src_byte_depth = src_bit_depth / 8;
   int dest_byte_depth = dest_bit_depth / 8;

   int dest_color_type = src_color_type;
   if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
   {
      OPNG_ASSERT(src_color_type & PNG_COLOR_MASK_COLOR);
      dest_color_type &= ~PNG_COLOR_MASK_COLOR;
   }
   if (reductions & OPNG_REDUCE_STRIP_ALPHA)
   {
      OPNG_ASSERT(src_color_type & PNG_COLOR_MASK_ALPHA);
      dest_color_type &= ~PNG_COLOR_MASK_ALPHA;
   }

   int src_channels = png_get_channels(png_ptr, info_ptr);
   int dest_channels =
      ((dest_color_type & PNG_COLOR_MASK_COLOR) ? 3 : 1) +
      ((dest_color_type & PNG_COLOR_MASK_ALPHA) ? 1 : 0);

   int src_sample_size = src_channels * src_byte_depth;
   int dest_sample_size = dest_channels * dest_byte_depth;

   /* Pre-compute the intra-sample translation table. */
   int k;
   int tran_tbl[8];
   for (k = 0; k < 4 * dest_byte_depth; ++k)
      tran_tbl[k] = k * src_bit_depth / dest_bit_depth;
   /* If rgb --> gray, shift the alpha component two positions to the left. */
   if ((reductions & OPNG_REDUCE_RGB_TO_GRAY) &&
       (dest_color_type & PNG_COLOR_MASK_ALPHA))
   {
      tran_tbl[dest_byte_depth] = tran_tbl[3 * dest_byte_depth];
      if (dest_byte_depth == 2)
         tran_tbl[dest_byte_depth + 1] = tran_tbl[3 * dest_byte_depth + 1];
   }

   /* Translate the samples to the new image type. */
   OPNG_ASSERT(src_sample_size > dest_sample_size);
   png_bytepp row_ptr = png_get_rows(png_ptr, info_ptr);
   for (png_uint_32 i = 0; i < height; ++i, ++row_ptr)
   {
      src_ptr = dest_ptr = *row_ptr;
      for (png_uint_32 j = 0; j < width; ++j)
      {
         for (k = 0; k < dest_sample_size; ++k)
            dest_ptr[k] = src_ptr[tran_tbl[k]];
         src_ptr += src_sample_size;
         dest_ptr += dest_sample_size;
      }
   }
   png_color_16p trans_color;
   /* Update the ancillary information. */
   if (png_get_tRNS(png_ptr, info_ptr, 0, 0, &trans_color))
   {
      if (reductions & OPNG_REDUCE_16_TO_8)
      {
         if (trans_color->red   % 257 == 0 &&
             trans_color->green % 257 == 0 &&
             trans_color->blue  % 257 == 0 &&
             trans_color->gray  % 257 == 0)
         {
            trans_color->red   &= 255;
            trans_color->green &= 255;
            trans_color->blue  &= 255;
            trans_color->gray  &= 255;
         }
         else
         {
            /* 16-bit tRNS in 8-bit samples: all pixels are 100% opaque. */
            png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
            png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS);
         }
      }
      if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
      {
         if (trans_color->red == trans_color->green ||
             trans_color->red == trans_color->blue)
            trans_color->gray = trans_color->red;
         else
         {
            /* Non-gray tRNS in grayscale image: all pixels are 100% opaque. */
            png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1);
            png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS);
         }
      }
   }
#ifdef PNG_bKGD_SUPPORTED
   png_color_16p background;
   if (png_get_bKGD(png_ptr, info_ptr, &background))
   {
      if (reductions & OPNG_REDUCE_16_TO_8)
      {
         background->red   &= 255;
         background->green &= 255;
         background->blue  &= 255;
         background->gray  &= 255;
      }
      if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
         background->gray = background->red;
   }
#endif
#ifdef PNG_sBIT_SUPPORTED
    png_color_8p sig_bits;
   if (png_get_sBIT(png_ptr, info_ptr, &sig_bits))
   {
      if (reductions & OPNG_REDUCE_16_TO_8)
      {
         if (sig_bits->red > 8)
            sig_bits->red = 8;
         if (sig_bits->green > 8)
            sig_bits->green = 8;
         if (sig_bits->blue > 8)
            sig_bits->blue = 8;
         if (sig_bits->gray > 8)
            sig_bits->gray = 8;
         if (sig_bits->alpha > 8)
            sig_bits->alpha = 8;
      }
      if (reductions & OPNG_REDUCE_RGB_TO_GRAY)
      {
         png_byte max_sig_bits = sig_bits->red;
         if (max_sig_bits < sig_bits->green)
            max_sig_bits = sig_bits->green;
         if (max_sig_bits < sig_bits->blue)
            max_sig_bits = sig_bits->blue;
         sig_bits->gray = max_sig_bits;
      }
   }
#endif

   /* Update the image information. */
   png_set_IHDR(png_ptr, info_ptr, width, height,
      dest_bit_depth, dest_color_type,
      interlace_type, compression_type, filter_type);

   return reductions;
}
Exemplo n.º 4
0
BOOL OutputPNG::OutputPNGHeader(CCLexFile *File, LPBITMAPINFOHEADER pInfo,
                                BOOL InterlaceState, INT32 TransparentColour,
                                LPLOGPALETTE pPalette, LPRGBQUAD pQuadPalette)
{
    ERROR2IF(File==NULL,FALSE,"OutputPNG::OutputPNGHeader File pointer is null");
    if (pInfo == NULL)
        pInfo = &(DestBitmapInfo->bmiHeader);
    ERROR2IF(pInfo==NULL,FALSE,"OutputPNG::OutputPNGHeader BitmapInfo pointer is null");
    //ERROR2IF(pPalette==NULL && pQuadPalette==NULL,FALSE,"OutputPNG::OutputPNGHeader Bitmap palette pointer is null");

    TRACEUSER( "Jonathan", _T("PNG write: Interlace: %s\n"), InterlaceState ? _T("Yes") : _T("No"));

    // Note file in our class variable as used by all the low level routines
    OutputFile = File;

    // Note the specified transparency and interlace states in our class variables
    Interlace = InterlaceState;
    if (TransparentColour != -1)
        Transparent = TRUE;
    else
        Transparent = FALSE;

    // We are just about to start so set the PNG exception handling up with our CCFile pointer
    PNGUtil::SetCCFilePointer(File);

    // Must set the exception throwing flag to True and force reporting of errors to False.
    // This means that the caller must report an error if the function returns False.
    // Any calls to CCFile::GotError will now throw a file exception and should fall into
    // the catch handler at the end of the function.
    // Replaces the goto's that handled this before.
    BOOL OldThrowingState = File->SetThrowExceptions( TRUE );
    BOOL OldReportingState = File->SetReportErrors( FALSE );

    // PNG related items (NOTE: p at end means pointer and hence implied *)
    png_ptr		= NULL;
    info_ptr	= NULL;

    palette = NULL;

    try
    {
        // Work out the palette size
        INT32 PalSize = pInfo->biClrUsed;		// How many entries in palette
        TRACEUSER( "Jonathan", _T("PNG write: PalSize = %d\n"),PalSize);

        // Set up the class variables
        // First the width/height of the bitmap
        Width = pInfo->biWidth;
        Height = pInfo->biHeight;
        TRACEUSER( "Jonathan", _T("PNG write: Width = %d Height = %d\n"),Width,Height);

        BitsPerPixel = pInfo->biBitCount;

        // Start up the PNG writing code

        // allocate the necessary structures
        // Use the default handlers
        png_ptr = png_create_write_struct_2(
                      PNG_LIBPNG_VER_STRING,	// libpng version
                      0,						// Optional pointer to be sent with errors
                      camelot_png_error,		// Function called in case of error
                      camelot_png_warning,	// Function called for warnings
                      0,						// Optional pointer to be sent with mem ops
                      camelot_png_malloc,		// Function called to alloc memory
                      camelot_png_free		// Function called to free memory
                  );

        if (!png_ptr)
            File->GotError( _R(IDS_OUT_OF_MEMORY) );

        info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr)
        {
            png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
            File->GotError( _R(IDS_OUT_OF_MEMORY) );
        }

        // set up the input control to the fstream class
        // If not a disk file then panic for the present moment
        // Could use the memfile functions for reading and writing as they give us what
        // we want. Use the io_ptr and
        iostream* pFStream = File->GetIOFile();
        if (pFStream == NULL)
        {
            TRACEUSER( "Jonathan", _T("PNG write: OutputPNG::OutputPNGHeader No access to IOStream!"));
            File->GotError( _R(IDS_UNKNOWN_PNG_ERROR) );
        }

        // Should use our own function
        png_set_write_fn(png_ptr, pFStream, camelot_png_write_data, camelot_png_flush_data);
        // png_init_io(png_ptr, pFStream);

        // You now have the option of modifying how the compression library
        // will run.  The following functions are mainly for testing, but
        // may be useful in certain special cases, like if you need to
        // write png files extremely fast and are willing to give up some
        // compression, or if you want to get the maximum possible compression
        // at the expense of slower writing.  If you have no special needs
        // in this area, let the library do what it wants, as it has been
        // carefully tuned to deliver the best speed/compression ratio.
        // See the compression library for more details.

        // turn on or off filtering (1 or 0)
        //png_set_filtering(png_ptr, 1);

        // compression level (0 - none, 6 - default, 9 - maximum)
        //png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
        //png_set_compression_mem_level(png_ptr, 8);
        //png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
        //png_set_compression_window_bits(png_ptr, 15);
        //png_set_compression_method(png_ptr, 8);

        // - this describes which optional chunks to write to the
        // file.  Note that if you are writing a
        // PNG_COLOR_TYPE_PALETTE file, the PLTE chunk is not
        // optional, but must still be marked for writing.  To
        // mark chunks for writing, OR valid with the
        // appropriate PNG_INFO_<chunk name> define.
        png_get_valid(png_ptr, info_ptr, 0);

        // resolution of image
        png_set_invalid(png_ptr, info_ptr, PNG_INFO_pHYs);
        png_set_pHYs(png_ptr, info_ptr,
                     pInfo->biXPelsPerMeter,
                     pInfo->biYPelsPerMeter,
                     1); //meter
        TRACEUSER( "Jonathan", _T("PNG write: x,y px per cm = %d %d\n"),
                   png_get_x_pixels_per_meter(png_ptr, info_ptr) / 1000,
                   png_get_y_pixels_per_meter(png_ptr, info_ptr) / 1000);

        BitsPerPixel				= pInfo->biBitCount;
        TRACEUSER( "Jonathan", _T("PNG write: Bitdepth = %d\n"), BitsPerPixel);
        palette		= NULL;
        num_palette	= 0;
        trans		= NULL;	// - array of transparent entries for paletted images
        num_trans	= 0;	// - number of transparent entries
        TRACEUSER( "Jonathan", _T("PNG write: TransColour = %d\n"), TransparentColour);
        if ( BitsPerPixel <= 8 )
        {
            png_set_IHDR(png_ptr, info_ptr,
                         Width,
                         Height,
                         BitsPerPixel,
                         PNG_COLOR_TYPE_PALETTE,
                         PNG_INTERLACE_NONE,
                         PNG_COMPRESSION_TYPE_BASE,
                         PNG_FILTER_TYPE_BASE);

            // set the palette if there is one
            png_set_invalid(png_ptr, info_ptr, PNG_INFO_PLTE);
            INT32 PaletteEntries = pInfo->biClrUsed;

            palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color));
            if (palette == NULL)
                File->GotError( _R(IDS_OUT_OF_MEMORY) );

            png_set_PLTE(png_ptr, info_ptr, palette, num_palette);
            png_color_struct * pPNGPalette = palette;
            // ... set palette colors ...
            if (pQuadPalette && PaletteEntries > 0)
            {
                // Palette supplied in RGBQUAD form
                for (INT32 i = 0; i < PaletteEntries; i++)
                {
                    pPNGPalette->red 	= pQuadPalette->rgbRed;
                    pPNGPalette->green 	= pQuadPalette->rgbGreen;
                    pPNGPalette->blue 	= pQuadPalette->rgbBlue;
                    // skip to the next palette entry
                    pQuadPalette++;
                    pPNGPalette++;
                }
            }
            else if (pPalette && PaletteEntries > 0)
            {
                // Palette supplied in LOGPALETTE form
                for (INT32 i = 0; i < PaletteEntries; i++)
                {
                    pPNGPalette->red  	= pPalette->palPalEntry[i].peRed;
                    pPNGPalette->green 	= pPalette->palPalEntry[i].peGreen;
                    pPNGPalette->blue 	= pPalette->palPalEntry[i].peBlue;
                    pPNGPalette++;
                }
            }
            else
                File->GotError(_R(IDS_PNG_ERR_WRITE_PALETTE));

            // Now check to see if transparency is present or not
            if (TransparentColour >= 0 && TransparentColour <= PaletteEntries )
            {
                // Create the array of transparent entries for this palette
                // 0 is fully transparent, 255 is fully opaque, regardless of image bit depth
                // We will only create as many as we require, i.e. up to the transparent colour entry
                // rather a full palettes worth
                INT32 NumEntries = TransparentColour + 1;
                trans = (png_byte*)png_malloc(png_ptr, NumEntries * sizeof (png_byte));
                if (trans)
                {
                    // Set the number of transparent entries
                    num_trans			= NumEntries;
                    png_byte * pTransEntry		= trans;
                    png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS);
                    for (INT32 i = 0; i < TransparentColour; i++)
                    {
                        *pTransEntry = 255;	// set it fully opaque
                        pTransEntry++;
                    }
                    // We should now be at the transparent entry so set it fully transparent
                    *pTransEntry = 0;
                }
            }
        }
        else if (BitsPerPixel == 24)
        {
            png_set_IHDR(png_ptr, info_ptr,
                         Width,
                         Height,
                         8, /* bit_depth */
                         PNG_COLOR_TYPE_RGB,
                         PNG_INTERLACE_NONE,
                         PNG_COMPRESSION_TYPE_BASE,
                         PNG_FILTER_TYPE_BASE);
        }
        else if (BitsPerPixel == 32)
        {
            png_set_IHDR(png_ptr, info_ptr,
                         Width,
                         Height,
                         8, /* bit_depth */
                         PNG_COLOR_TYPE_RGB_ALPHA,
                         PNG_INTERLACE_NONE,
                         PNG_COMPRESSION_TYPE_BASE,
                         PNG_FILTER_TYPE_BASE);
        }
        else
            ERROR2(FALSE,"OutputPNG::OutputPNGHeader Unknown bit depth");

        TRACEUSER( "Jonathan", _T("PNG write: bit_depth = %d color_type = %d\n"),
                   png_get_bit_depth(png_ptr, info_ptr),
                   png_get_color_type(png_ptr, info_ptr));

        // Could use:-
        // if we are dealing with a grayscale image then
        //info_ptr->sig_bit.gray = true_bit_depth;

        png_set_hIST(png_ptr, info_ptr, NULL);
        png_set_text(png_ptr, info_ptr, NULL, 0);


        // write the file information
        png_write_info(png_ptr, info_ptr);

        TRACEUSER( "Jonathan", _T("PNG write: pixel_depth %d channels %d\n"),
                   png_get_bit_depth(png_ptr, info_ptr),
                   png_get_channels(png_ptr, info_ptr));
        TRACEUSER( "Jonathan", _T("PNG write: rowbytes %d color_type %d\n"),
                   png_get_rowbytes(png_ptr, info_ptr),
                   png_get_color_type(png_ptr, info_ptr));
        // Set up the transformations you want.
        // Note: that these are all optional.  Only call them if you want them

        // invert monocrome pixels
        //png_set_invert(png_ptr);

        // shift the pixels up to a legal bit depth and fill in as appropriate
        // to correctly scale the image
        //png_set_shift(png_ptr, &(info_ptr->sig_bit));

        // pack pixels into bytes
        //png_set_packing(png_ptr);

        png_set_bgr(png_ptr);

        // swap bytes of 16 bit files to most significant bit first
        png_set_swap(png_ptr);

        // Must set the exception throwing and reporting flags back to their entry states
        File->SetThrowExceptions( OldThrowingState );
        File->SetReportErrors( OldReportingState );

        // er, we seem to have finished OK so say so
        return TRUE;
    }

    catch (...)
    {
        // catch our form of a file exception
        TRACE( _T("OutputPNG::OutputPNGHeader CC catch handler\n"));

        // Call up function to clean up the png structures
        CleanUpPngStructures();

        // Must set the exception throwing and reporting flags back to their entry states
        File->SetThrowExceptions( OldThrowingState );
        File->SetReportErrors( OldReportingState );

        // We have finished so reset the PNG exception handling
        PNGUtil::SetCCFilePointer(NULL);

        return FALSE;
    }

    ERROR2( FALSE, "Escaped exception clause somehow" );
}
Exemplo n.º 5
0
/*
 * Sets the precision of the alpha channel to a given value;
 * if this value is 0, resets (i.e. sets to MAX) the alpha channel.
 * Returns 1 if this operation is applied, or 0 otherwise.
 */
static int
opng_transform_set_alpha_precision(png_structp libpng_ptr, png_infop info_ptr,
                                   int alpha_precision)
{
    int result;
    png_uint_32 width, height;
    int bit_depth, color_type;
    png_bytep trans_alpha;
    int num_trans;
    png_bytepp row_ptr;
    png_bytep alpha_ptr;
    unsigned int num_channels, channel_size, pixel_size;
    unsigned int alpha_offset;
    png_uint_32 i, j;
    int k;

    void (*set_precision_fn)(png_bytep, int);

    png_get_IHDR(libpng_ptr, info_ptr,
                 &width, &height, &bit_depth, &color_type, NULL, NULL, NULL);
    if (bit_depth <= 8)
    {
        if (alpha_precision >= 8)
            return 0;
        set_precision_fn = opng_set_precision8;
    }
    else
    {
        if (alpha_precision >= 16)
            return 0;
        set_precision_fn = opng_set_precision16;
    }

    result = 0;

    if (png_get_valid(libpng_ptr, info_ptr, PNG_INFO_tRNS))
    {
        if (alpha_precision > 0)
        {
            /* Set the precision of tRNS samples. */
            png_get_tRNS(libpng_ptr, info_ptr, &trans_alpha, &num_trans, NULL);
            if (trans_alpha != NULL)
            {
                for (k = 0; k < num_trans; ++k)
                    opng_set_precision8(trans_alpha + k, alpha_precision);
                result = 1;
            }
            /* trans_color needs no transformation */
        }
        else  /* alpha_precision == 0 */
        {
            /* Invalidate tRNS. */
            png_set_invalid(libpng_ptr, info_ptr, PNG_INFO_tRNS);
            result = 1;
        }
        /* Continue regardless whether PLTE is present.
         * PLTE may exist even if the color type is not palette.
         */
    }

    if (color_type & PNG_COLOR_MASK_ALPHA)
    {
        row_ptr = png_get_rows(libpng_ptr, info_ptr);
        channel_size = (bit_depth > 8) ? 2 : 1;
        num_channels = png_get_channels(libpng_ptr, info_ptr);
        pixel_size = num_channels * channel_size;
        alpha_offset = pixel_size - channel_size;
        if (alpha_precision > 0)
        {
            /* Set the precision of the alpha channel. */
            for (i = 0; i < height; ++i, ++row_ptr)
            {
                alpha_ptr = *row_ptr + alpha_offset;
                for (j = 0; j < width; ++j, alpha_ptr += pixel_size)
                    (*set_precision_fn)(alpha_ptr, alpha_precision);
            }
        }
        else  /* alpha_precision == 0 */
        {
            /* Set the alpha channel to opaque. */
            for (i = 0; i < height; ++i, ++row_ptr)
            {
                alpha_ptr = *row_ptr + alpha_offset;
                for (j = 0; j < width; ++j, alpha_ptr += pixel_size)
                {
                    alpha_ptr[0] = 255;
                    alpha_ptr[channel_size - 1] = 255;
                }
            }
        }
        result = 1;
    }

    return result;
}