Esempio n. 1
0
static int
ReadPNG(char *Path, unsigned char **ImgData, int *width, int *length)
{
  FILE *f;
  unsigned char *tmpRow = NULL;
  unsigned char *Tempstr = NULL;
  png_structp png_ptr;
  png_infop info_ptr;
  png_uint_32 png_width, png_height, scanline_width;
  int bit_depth, color_type, interlace_type, row;
  int channels;

  f = fopen(Path, "r");

  if (!f)
    return (FALSE);

/* we have to load the first 4 bytes of the png file, this contains png version info */
  Tempstr = calloc(1, 4);
  if (fread(Tempstr, 1, 4, f) != 4)
  {
    free(Tempstr);
    fclose(f);
    return (FALSE);
  }

/* check if valid png */
  if (png_sig_cmp(Tempstr, (png_size_t) 0, 4))
    printf("%s not a png?\n", Path);
  /* create the png reading structure, errors go to stderr */
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (png_ptr == NULL)
  {
    fclose(f);
    free(Tempstr);
    return (FALSE);
  }


  /* allocate info struct */
  info_ptr = png_create_info_struct(png_ptr);
  if (info_ptr == NULL)
  {
    fclose(f);
    png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
    free(Tempstr);
    return (FALSE);
  }

  /* set error handling */
#if PNG_LIBPNG_VER_SONUM >= 15
  if (setjmp(png_jmpbuf(png_ptr)))
#else /*PNG_LIBPNG_VER_SONUM >= 15*/
  if (setjmp(png_ptr->jmpbuf))
#endif /*PNG_LIBPNG_VER_SONUM >= 15*/
  {
    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
    free(Tempstr);
    fclose(f);
    return (FALSE);
  }


  /* prepare the reader to ignore all recognized chunks whose data isn't
   * going to be used, i.e., all chunks recognized by libpng except for
   * IHDR, PLTE, IDAT, IEND, tRNS, bKGD, gAMA, and sRGB : */

  {
#ifndef HANDLE_CHUNK_NEVER

/* prior to libpng-1.2.5, this macro was internal, so we define it here. */
# define HANDLE_CHUNK_NEVER 1
#endif
    /* these byte strings were copied from png.h.
     * If a future libpng version recognizes more chunks, add them
     * to this list.  If a future version of readpng2.c recognizes
     * more chunks, delete them from this list. */
    png_byte png_chunk_types_to_ignore[] = { 99, 72, 82, 77, '\0',	/* cHRM */
      104, 73, 83, 84, '\0',	/* hIST */
      105, 67, 67, 80, '\0',	/* iCCP */
      105, 84, 88, 116, '\0',	/* iTXt */
      111, 70, 70, 115, '\0',	/* oFFs */
      112, 67, 65, 76, '\0',	/* pCAL */
      115, 67, 65, 76, '\0',	/* sCAL */
      112, 72, 89, 115, '\0',	/* pHYs */
      115, 66, 73, 84, '\0',	/* sBIT */
      115, 80, 76, 84, '\0',	/* sPLT */
      116, 69, 88, 116, '\0',	/* tEXt */
      116, 73, 77, 69, '\0',	/* tIME */
      122, 84, 88, 116, '\0'
    };				/* zTXt */
#define NUM_PNG_CHUNK_TYPES_TO_IGNORE 13

    png_set_keep_unknown_chunks(png_ptr, HANDLE_CHUNK_NEVER, png_chunk_types_to_ignore, NUM_PNG_CHUNK_TYPES_TO_IGNORE);
  }


  /* set input method */
  png_init_io(png_ptr, f);

  /* tell libpng we have already read some bytes */
  png_set_sig_bytes(png_ptr, 4);
  /* read all info */
  png_read_info(png_ptr, info_ptr);
  /* get some characteristics of the file */
  png_get_IHDR(png_ptr, info_ptr, &png_width, &png_height, &bit_depth, &color_type, &interlace_type, NULL, NULL);

  *width = (int)png_width;
  *length = (int)png_height;

  /*expand bit depth */
  png_set_expand(png_ptr);
  png_set_interlace_handling(png_ptr);
  png_read_update_info(png_ptr, info_ptr);

  /* get size of scanline */
  scanline_width = png_get_rowbytes(png_ptr, info_ptr);

  channels = png_get_channels(png_ptr, info_ptr);

/* allocate texture memory */
  *ImgData = (unsigned char *)malloc(png_width * png_height * 4);
  if (channels == 3)
    tmpRow = (unsigned char *)malloc(scanline_width * sizeof(unsigned char));

  /* read the image line by line into the user's buffer */
  for (row = 0; row < png_height; row++)
  {
    if (channels == 3)
    {
      Read3ByteRow(png_ptr, tmpRow, *ImgData, row, png_width);
    }
    else
      png_read_row(png_ptr, (unsigned char *)((*ImgData) + (row * scanline_width)), NULL);
  }


  /* finish reading the file */
  png_read_end(png_ptr, NULL);

  png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

  fclose(f);

  free(Tempstr);
  if (tmpRow)
    free(tmpRow);

  return (TRUE);
}
Esempio n. 2
0
bool GReadBitmapFromFile(const char path[], GBitmap* bitmap) {
    FILE* file = fopen(path, "rb");
    if (NULL == file) {
        return always_false();
    }
    GAutoFClose afc(file);

    uint8_t signature[SIGNATURE_BYTES];
    if (SIGNATURE_BYTES != fread(signature, 1, SIGNATURE_BYTES, file)) {
        return always_false();
    }
    if (png_sig_cmp(signature, 0, SIGNATURE_BYTES)) {
        return always_false();
    }
        
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                                 NULL, NULL, NULL);
    if (NULL == png_ptr) {
        return always_false();
    }
    
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (NULL == info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return always_false();
    }
    
    GAutoPNGReader reader(png_ptr, info_ptr);
    
    if (setjmp(png_jmpbuf(png_ptr))) {
        return always_false();
    }
    
    png_init_io(png_ptr, file);
    png_set_sig_bytes(png_ptr, SIGNATURE_BYTES);
    png_read_info(png_ptr, info_ptr);

    png_uint_32 width, height;
    int bitDepth, colorType;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bitDepth, &colorType,
                 NULL, NULL, NULL);

    if (8 != bitDepth) {
        return always_false();   // TODO: handle other formats
    }
    if (png_set_interlace_handling(png_ptr) > 1) {
        return always_false();   // TODO: support interleave
    }

    swizzle_row_proc row_proc = NULL;
    switch (colorType) {
        case PNG_COLOR_TYPE_RGB:
            row_proc = swizzle_rgb_row;
            break;
        case PNG_COLOR_TYPE_RGB_ALPHA:
            row_proc = swizzle_rgba_row;
            break;
        default:
            return always_false();
    }

    png_read_update_info(png_ptr, info_ptr);

    GAutoFree rowStorage(malloc(png_get_rowbytes(png_ptr, info_ptr)));
    png_bytep srcRow = (png_bytep)rowStorage.get();
    if (!srcRow) {
        return always_false();
    }

    GAutoFree pixelStorage(malloc(height * width * 4));
    GPixel* dstRow = (GPixel*)pixelStorage.get();
    if (NULL == dstRow) {
        return always_false();
    }

    for (int y = 0; y < height; y++) {
        uint8_t* tmp = srcRow;
        png_read_rows(png_ptr, &tmp, NULL, 1);
        row_proc(dstRow, srcRow, width);
        dstRow += width;
    }

    bitmap->fWidth = width;
    bitmap->fHeight = height;
    bitmap->fRowBytes = width * 4;
    bitmap->fPixels = (GPixel*)pixelStorage.detach();
    return true;
}
Esempio n. 3
0
bool  PngDecoder::readData( Mat& img )
{
    bool result = false;
    AutoBuffer<uchar*> _buffer(m_height);
    uchar** buffer = _buffer;
    int color = img.channels() > 1;
    uchar* data = img.data;
    int step = (int)img.step;

    if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
    {
        png_structp png_ptr = (png_structp)m_png_ptr;
        png_infop info_ptr = (png_infop)m_info_ptr;
        png_infop end_info = (png_infop)m_end_info;

        if( setjmp( png_jmpbuf ( png_ptr ) ) == 0 )
        {
            int y;

            if( img.depth() == CV_8U && m_bit_depth == 16 )
                png_set_strip_16( png_ptr );
            else if( !isBigEndian() )
                png_set_swap( png_ptr );

            if(img.channels() < 4)
            {
                /* observation: png_read_image() writes 400 bytes beyond
                 * end of data when reading a 400x118 color png
                 * "mpplus_sand.png".  OpenCV crashes even with demo
                 * programs.  Looking at the loaded image I'd say we get 4
                 * bytes per pixel instead of 3 bytes per pixel.  Test
                 * indicate that it is a good idea to always ask for
                 * stripping alpha..  18.11.2004 Axel Walthelm
                 */
                 png_set_strip_alpha( png_ptr );
            }

            if( m_color_type == PNG_COLOR_TYPE_PALETTE )
                png_set_palette_to_rgb( png_ptr );

            if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 )
#if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \
    (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18)
                png_set_expand_gray_1_2_4_to_8( png_ptr );
#else
                png_set_gray_1_2_4_to_8( png_ptr );
#endif

            if( CV_MAT_CN(m_type) > 1 && color )
                png_set_bgr( png_ptr ); // convert RGB to BGR
            else if( color )
                png_set_gray_to_rgb( png_ptr ); // Gray->RGB
            else
                png_set_rgb_to_gray( png_ptr, 1, 0.299, 0.587 ); // RGB->Gray

            png_set_interlace_handling( png_ptr );
            png_read_update_info( png_ptr, info_ptr );

            for( y = 0; y < m_height; y++ )
                buffer[y] = data + y*step;

            png_read_image( png_ptr, buffer );
            png_read_end( png_ptr, end_info );

            result = true;
        }
    }

    close();
    return result;
}
Esempio n. 4
0
  Load_SBit_Png( FT_GlyphSlot     slot,
                 FT_Int           x_offset,
                 FT_Int           y_offset,
                 FT_Int           pix_bits,
                 TT_SBit_Metrics  metrics,
                 FT_Memory        memory,
                 FT_Byte*         data,
                 FT_UInt          png_len,
                 FT_Bool          populate_map_and_metrics,
                 FT_Bool          metrics_only )
  {
    FT_Bitmap    *map   = &slot->bitmap;
    FT_Error      error = FT_Err_Ok;
    FT_StreamRec  stream;

    png_structp  png;
    png_infop    info;
    png_uint_32  imgWidth, imgHeight;

    int         bitdepth, color_type, interlace;
    FT_Int      i;
    png_byte*  *rows = NULL; /* pacify compiler */


    if ( x_offset < 0 ||
         y_offset < 0 )
    {
      error = FT_THROW( Invalid_Argument );
      goto Exit;
    }

    if ( !populate_map_and_metrics                            &&
         ( x_offset + metrics->width  > map->width ||
           y_offset + metrics->height > map->rows  ||
           pix_bits != 32                          ||
           map->pixel_mode != FT_PIXEL_MODE_BGRA   ) )
    {
      error = FT_THROW( Invalid_Argument );
      goto Exit;
    }

    FT_Stream_OpenMemory( &stream, data, png_len );

    png = png_create_read_struct( PNG_LIBPNG_VER_STRING,
                                  &error,
                                  error_callback,
                                  warning_callback );
    if ( !png )
    {
      error = FT_THROW( Out_Of_Memory );
      goto Exit;
    }

    info = png_create_info_struct( png );
    if ( !info )
    {
      error = FT_THROW( Out_Of_Memory );
      png_destroy_read_struct( &png, NULL, NULL );
      goto Exit;
    }

    if ( ft_setjmp( png_jmpbuf( png ) ) )
    {
      error = FT_THROW( Invalid_File_Format );
      goto DestroyExit;
    }

    png_set_read_fn( png, &stream, read_data_from_FT_Stream );

    png_read_info( png, info );
    png_get_IHDR( png, info,
                  &imgWidth, &imgHeight,
                  &bitdepth, &color_type, &interlace,
                  NULL, NULL );

    if ( error                                        ||
         ( !populate_map_and_metrics                &&
           ( (FT_Int)imgWidth  != metrics->width  ||
             (FT_Int)imgHeight != metrics->height ) ) )
      goto DestroyExit;

    if ( populate_map_and_metrics )
    {
      metrics->width  = (FT_UShort)imgWidth;
      metrics->height = (FT_UShort)imgHeight;

      map->width      = metrics->width;
      map->rows       = metrics->height;
      map->pixel_mode = FT_PIXEL_MODE_BGRA;
      map->pitch      = (int)( map->width * 4 );
      map->num_grays  = 256;

      /* reject too large bitmaps similarly to the rasterizer */
      if ( map->rows > 0x4FFF || map->width > 0x4FFF )
      {
        error = FT_THROW( Array_Too_Large );
        goto DestroyExit;
      }
    }

    /* convert palette/gray image to rgb */
    if ( color_type == PNG_COLOR_TYPE_PALETTE )
      png_set_palette_to_rgb( png );

    /* expand gray bit depth if needed */
    if ( color_type == PNG_COLOR_TYPE_GRAY )
    {
#if PNG_LIBPNG_VER >= 10209
      png_set_expand_gray_1_2_4_to_8( png );
#else
      png_set_gray_1_2_4_to_8( png );
#endif
    }

    /* transform transparency to alpha */
    if ( png_get_valid(png, info, PNG_INFO_tRNS ) )
      png_set_tRNS_to_alpha( png );

    if ( bitdepth == 16 )
      png_set_strip_16( png );

    if ( bitdepth < 8 )
      png_set_packing( png );

    /* convert grayscale to RGB */
    if ( color_type == PNG_COLOR_TYPE_GRAY       ||
         color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
      png_set_gray_to_rgb( png );

    if ( interlace != PNG_INTERLACE_NONE )
      png_set_interlace_handling( png );

    png_set_filler( png, 0xFF, PNG_FILLER_AFTER );

    /* recheck header after setting EXPAND options */
    png_read_update_info(png, info );
    png_get_IHDR( png, info,
                  &imgWidth, &imgHeight,
                  &bitdepth, &color_type, &interlace,
                  NULL, NULL );

    if ( bitdepth != 8                              ||
        !( color_type == PNG_COLOR_TYPE_RGB       ||
           color_type == PNG_COLOR_TYPE_RGB_ALPHA ) )
    {
      error = FT_THROW( Invalid_File_Format );
      goto DestroyExit;
    }

    if ( metrics_only )
      goto DestroyExit;

    switch ( color_type )
    {
    default:
      /* Shouldn't happen, but fall through. */

    case PNG_COLOR_TYPE_RGB_ALPHA:
      png_set_read_user_transform_fn( png, premultiply_data );
      break;

    case PNG_COLOR_TYPE_RGB:
      /* Humm, this smells.  Carry on though. */
      png_set_read_user_transform_fn( png, convert_bytes_to_data );
      break;
    }

    if ( populate_map_and_metrics )
    {
      /* this doesn't overflow: 0x4FFF * 0x4FFF * 4 < 2^31 */
      FT_ULong  size = map->rows * (FT_ULong)map->pitch;


      error = ft_glyphslot_alloc_bitmap( slot, size );
      if ( error )
        goto DestroyExit;
    }

    if ( FT_NEW_ARRAY( rows, imgHeight ) )
    {
      error = FT_THROW( Out_Of_Memory );
      goto DestroyExit;
    }

    for ( i = 0; i < (FT_Int)imgHeight; i++ )
      rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4;

    png_read_image( png, rows );

    FT_FREE( rows );

    png_read_end( png, info );

  DestroyExit:
    png_destroy_read_struct( &png, &info, NULL );
    FT_Stream_Close( &stream );

  Exit:
    return error;
  }
Esempio n. 5
0
  static FT_Error
  Load_SBit_Png( FT_Bitmap*       map,
                 FT_Int           x_offset,
                 FT_Int           y_offset,
                 FT_Int           pix_bits,
                 TT_SBit_Metrics  metrics,
                 FT_Memory        memory,
                 FT_Byte*         data,
                 FT_UInt          png_len )
  {
    FT_Error      error = FT_Err_Ok;
    FT_StreamRec  stream;

    png_structp  png;
    png_infop    info;
    png_uint_32  imgWidth, imgHeight;

    int         bitdepth, color_type, interlace;
    FT_Int      i;
    png_byte*  *rows;


    if ( x_offset < 0 || x_offset + metrics->width  > map->width ||
         y_offset < 0 || y_offset + metrics->height > map->rows  ||
         pix_bits != 32 || map->pixel_mode != FT_PIXEL_MODE_BGRA )
    {
      error = FT_THROW( Invalid_Argument );
      goto Exit;
    }

    FT_Stream_OpenMemory( &stream, data, png_len );

    png = png_create_read_struct( PNG_LIBPNG_VER_STRING,
                                  &error,
                                  error_callback,
                                  warning_callback );
    if ( !png )
    {
      error = FT_THROW( Out_Of_Memory );
      goto Exit;
    }

    info = png_create_info_struct( png );
    if ( !info )
    {
      error = FT_THROW( Out_Of_Memory );
      png_destroy_read_struct( &png, NULL, NULL );
      goto Exit;
    }

    if ( ft_setjmp( png_jmpbuf( png ) ) )
    {
      error = FT_THROW( Invalid_File_Format );
      goto DestroyExit;
    }

    png_set_read_fn( png, &stream, read_data_from_FT_Stream );

    png_read_info( png, info );
    png_get_IHDR( png, info,
                  &imgWidth, &imgHeight,
                  &bitdepth, &color_type, &interlace,
                  NULL, NULL );

    if ( error != FT_Err_Ok                   ||
         (FT_Int)imgWidth  != metrics->width  ||
         (FT_Int)imgHeight != metrics->height )
      goto DestroyExit;

    /* convert palette/gray image to rgb */
    if ( color_type == PNG_COLOR_TYPE_PALETTE )
      png_set_palette_to_rgb( png );

    /* expand gray bit depth if needed */
    if ( color_type == PNG_COLOR_TYPE_GRAY )
    {
#if PNG_LIBPNG_VER >= 10209
      png_set_expand_gray_1_2_4_to_8( png );
#else
      png_set_gray_1_2_4_to_8( png );
#endif
    }

    /* transform transparency to alpha */
    if ( png_get_valid(png, info, PNG_INFO_tRNS ) )
      png_set_tRNS_to_alpha( png );

    if ( bitdepth == 16 )
      png_set_strip_16( png );

    if ( bitdepth < 8 )
      png_set_packing( png );

    /* convert grayscale to RGB */
    if ( color_type == PNG_COLOR_TYPE_GRAY       ||
         color_type == PNG_COLOR_TYPE_GRAY_ALPHA )
      png_set_gray_to_rgb( png );

    if ( interlace != PNG_INTERLACE_NONE )
      png_set_interlace_handling( png );

    png_set_filler( png, 0xFF, PNG_FILLER_AFTER );

    /* recheck header after setting EXPAND options */
    png_read_update_info(png, info );
    png_get_IHDR( png, info,
                  &imgWidth, &imgHeight,
                  &bitdepth, &color_type, &interlace,
                  NULL, NULL );

    if ( bitdepth != 8                              ||
        !( color_type == PNG_COLOR_TYPE_RGB       ||
           color_type == PNG_COLOR_TYPE_RGB_ALPHA ) )
    {
      error = FT_THROW( Invalid_File_Format );
      goto DestroyExit;
    }

    switch ( color_type )
    {
    default:
      /* Shouldn't happen, but fall through. */

    case PNG_COLOR_TYPE_RGB_ALPHA:
      png_set_read_user_transform_fn( png, premultiply_data );
      break;

    case PNG_COLOR_TYPE_RGB:
      /* Humm, this smells.  Carry on though. */
      png_set_read_user_transform_fn( png, convert_bytes_to_data );
      break;
    }

    if ( FT_NEW_ARRAY( rows, imgHeight ) )
    {
      error = FT_THROW( Out_Of_Memory );
      goto DestroyExit;
    }

    for ( i = 0; i < (FT_Int)imgHeight; i++ )
      rows[i] = map->buffer + ( y_offset + i ) * map->pitch + x_offset * 4;

    png_read_image( png, rows );

    FT_FREE( rows );

    png_read_end( png, info );

  DestroyExit:
    png_destroy_read_struct( &png, &info, NULL );
    FT_Stream_Close( &stream );

  Exit:
    return error;
  }
Esempio n. 6
0
//
// In order to avoid CRT mismatches, we override all CRT functions libpng uses
// with our own. The alternative, using fopen and fread in our code and then
// passing a FILE* into libpng, isn't reliable because it crashes if libpng was
// compiled with a different CRT than lsapi.dll
//
HBITMAP LoadFromPNG(LPCSTR pszFilename)
{
    HBITMAP hDibSection = NULL;
    
    if (pszFilename != NULL)
    {
        FILE * hFile = fopen(pszFilename, "rb");
        
        if (hFile)
        {
            const size_t num_sig_bytes = 8;
            unsigned char sig[num_sig_bytes];
            
            fread(sig, 1, num_sig_bytes, hFile);
            
            if (png_check_sig(sig, num_sig_bytes))
            {
                PNGERROR PngError = { 0 };
                
                PngError.Wnd = GetForegroundWindow();
                
                png_structp Read = png_create_read_struct_2(
                    PNG_LIBPNG_VER_STRING, &PngError, PNGErrorHandler, NULL,
                    NULL, ls_png_malloc, ls_png_free);
                
                if (Read)
                {
                    png_infop Info = png_create_info_struct(Read);
                    
                    if (Info)
                    {
                        if (!setjmp(PngError.ErrorJump))
                        {
                            png_set_read_fn(Read, hFile, ls_png_read_data);
                            png_set_sig_bytes(Read, num_sig_bytes);
                            png_read_info(Read, Info);
                            
                            const unsigned char bit_depth = png_get_bit_depth(Read, Info);
                            const unsigned char color_type = png_get_color_type(Read, Info);
                            
                            if (color_type == PNG_COLOR_TYPE_PALETTE)
                            {
                                png_set_palette_to_rgb(Read);
                            }
                            
                            if ((color_type == PNG_COLOR_TYPE_GRAY) ||
                                (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
                            {
                                if (bit_depth < 8)
                                {
                                    png_set_gray_1_2_4_to_8(Read);
                                }
                                png_set_gray_to_rgb(Read);
                            }
                            
                            if (png_get_valid(Read, Info, PNG_INFO_tRNS))
                            {
                                png_set_tRNS_to_alpha(Read);
                            }
                            
                            if (color_type & PNG_COLOR_MASK_COLOR)
                            {
                                png_set_bgr(Read);
                            }
                            
                            if (bit_depth == 16)
                            {
                                png_set_strip_16(Read);
                            }
                            
                            double image_gamma = 1 / 2.2;
                            png_get_gAMA(Read, Info, &image_gamma);
                            png_set_gamma(Read, 2.2, image_gamma);
                            
                            const int num_passes = png_set_interlace_handling(Read);
                            
                            png_read_update_info(Read, Info);
                            
                            BITMAPINFO bmi = { {0} };
                            bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
                            bmi.bmiHeader.biWidth = (LONG)png_get_image_width(Read, Info);
                            bmi.bmiHeader.biHeight = -(LONG)png_get_image_height(Read, Info);
                            bmi.bmiHeader.biBitCount = (WORD)(png_get_channels(Read, Info) * png_get_bit_depth(Read, Info));
                            bmi.bmiHeader.biPlanes = 1;
                            bmi.bmiHeader.biCompression = BI_RGB;
                            
                            unsigned char* bits;
                            hDibSection = CreateDIBSection(NULL, &bmi, 0,
                                reinterpret_cast<LPVOID*>(&bits), NULL, 0);
                            
                            if (!bits)
                            {
                                longjmp(PngError.ErrorJump, 1);
                            }
                            
                            unsigned int dib_bytes_per_scanline = \
                                (((bmi.bmiHeader.biWidth * bmi.bmiHeader.biBitCount) + 31) & ~31) >> 3;
                            
                            for (int Pass = 0; Pass < num_passes; ++Pass)
                            {
                                for (int y = 0; y < -bmi.bmiHeader.biHeight; ++y)
                                {
                                    unsigned char* Scanline = \
                                        reinterpret_cast<unsigned char*>(bits + (y * dib_bytes_per_scanline));
                                    
                                    png_read_row(Read, Scanline, NULL);
                                }
                            }
                            
                            png_read_end(Read, Info);
                            png_destroy_read_struct(&Read, &Info, NULL);
                        }
                        else
                        {
                            png_destroy_read_struct(&Read, &Info, NULL);
                        }
                    }
                    else
                    {
                        png_destroy_read_struct(&Read, NULL, NULL);
                    }
                }
Esempio n. 7
0
int image_png_load(MediaScanImage *i) {
  int bit_depth, color_type, num_passes, x, y;
  int ofs;
  volatile unsigned char *ptr = NULL; // volatile = won't be rolled back if longjmp is called
  PNGData *p = (PNGData *)i->_png;

  if (setjmp(png_jmpbuf(p->png_ptr))) {
    if (ptr != NULL)
      free((void *)ptr);
    image_png_destroy(i);
    return 0;
  }

  // XXX If reusing the object a second time, we need to completely create a new png struct

  bit_depth = png_get_bit_depth(p->png_ptr, p->info_ptr);
  color_type = png_get_color_type(p->png_ptr, p->info_ptr);

  if (color_type == PNG_COLOR_TYPE_PALETTE) {
    png_set_expand(p->png_ptr); // png_set_palette_to_rgb(p->png_ptr);
    i->channels = 4;
  }
  else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    png_set_expand(p->png_ptr); // png_set_expand_gray_1_2_4_to_8(p->png_ptr);
  else if (png_get_valid(p->png_ptr, p->info_ptr, PNG_INFO_tRNS))
    png_set_expand(p->png_ptr); // png_set_tRNS_to_alpha(p->png_ptr);

  if (bit_depth == 16)
    png_set_strip_16(p->png_ptr);
  else if (bit_depth < 8)
    png_set_packing(p->png_ptr);

  // Make non-alpha RGB/Palette 32-bit and Gray 16-bit for easier handling
  if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
    png_set_add_alpha(p->png_ptr, 0xFF, PNG_FILLER_AFTER);
  }

  num_passes = png_set_interlace_handling(p->png_ptr);

  LOG_DEBUG("png bit_depth %d, color_type %d, channels %d, num_passes %d\n",
            bit_depth, color_type, i->channels, num_passes);

  png_read_update_info(p->png_ptr, p->info_ptr);

  image_alloc_pixbuf(i, i->width, i->height);

  ptr = (unsigned char *)malloc(png_get_rowbytes(p->png_ptr, p->info_ptr));

  ofs = 0;

  if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { // Grayscale (Alpha)
    if (num_passes == 1) {      // Non-interlaced
      for (y = 0; y < i->height; y++) {
        png_read_row(p->png_ptr, (unsigned char *)ptr, NULL);
        for (x = 0; x < i->width; x++) {
          i->_pixbuf[ofs++] = COL_FULL(ptr[x * 2], ptr[x * 2], ptr[x * 2], ptr[x * 2 + 1]);
        }
      }
    }
    else if (num_passes == 7) { // Interlaced
      image_png_interlace_pass_gray(i, (unsigned char *)ptr, 0, 8, 0, 8);
      image_png_interlace_pass_gray(i, (unsigned char *)ptr, 0, 8, 4, 8);
      image_png_interlace_pass_gray(i, (unsigned char *)ptr, 4, 8, 0, 4);
      image_png_interlace_pass_gray(i, (unsigned char *)ptr, 0, 4, 2, 4);
      image_png_interlace_pass_gray(i, (unsigned char *)ptr, 2, 4, 0, 2);
      image_png_interlace_pass_gray(i, (unsigned char *)ptr, 0, 2, 1, 2);
      image_png_interlace_pass_gray(i, (unsigned char *)ptr, 1, 2, 0, 1);
    }
  }
  else {                        // RGB(A)
    if (num_passes == 1) {      // Non-interlaced
      for (y = 0; y < i->height; y++) {
        png_read_row(p->png_ptr, (unsigned char *)ptr, NULL);
        for (x = 0; x < i->width; x++) {
          i->_pixbuf[ofs++] = COL_FULL(ptr[x * 4], ptr[x * 4 + 1], ptr[x * 4 + 2], ptr[x * 4 + 3]);
        }
      }
    }
    else if (num_passes == 7) { // Interlaced
      // The first pass will return an image 1/8 as wide as the entire image
      // (every 8th column starting in column 0)
      // and 1/8 as high as the original (every 8th row starting in row 0)
      image_png_interlace_pass(i, (unsigned char *)ptr, 0, 8, 0, 8);

      // The second will be 1/8 as wide (starting in column 4)
      // and 1/8 as high (also starting in row 0)
      image_png_interlace_pass(i, (unsigned char *)ptr, 0, 8, 4, 8);

      // The third pass will be 1/4 as wide (every 4th pixel starting in column 0)
      // and 1/8 as high (every 8th row starting in row 4)
      image_png_interlace_pass(i, (unsigned char *)ptr, 4, 8, 0, 4);

      // The fourth pass will be 1/4 as wide and 1/4 as high
      // (every 4th column starting in column 2, and every 4th row starting in row 0)
      image_png_interlace_pass(i, (unsigned char *)ptr, 0, 4, 2, 4);

      // The fifth pass will return an image 1/2 as wide,
      // and 1/4 as high (starting at column 0 and row 2)
      image_png_interlace_pass(i, (unsigned char *)ptr, 2, 4, 0, 2);

      // The sixth pass will be 1/2 as wide and 1/2 as high as the original
      // (starting in column 1 and row 0)
      image_png_interlace_pass(i, (unsigned char *)ptr, 0, 2, 1, 2);

      // The seventh pass will be as wide as the original, and 1/2 as high,
      // containing all of the odd numbered scanlines.
      image_png_interlace_pass(i, (unsigned char *)ptr, 1, 2, 0, 1);
    }
    else {
      FATAL("Unsupported PNG interlace type (%d passes)\n", num_passes);
    }
  }

  free((void *)ptr);

  // This is not required, so we can save some time by not reading post-image chunks
  //png_read_end(p->png_ptr, p->info_ptr);

  return 1;
}
Esempio n. 8
0
void ossimPngReader::restart()
{
   if ( m_str )
   {
      // Destroy the existing memory associated with png structs.
      if (m_pngReadPtr && m_pngReadInfoPtr)
      {
         png_destroy_read_struct(&m_pngReadPtr, &m_pngReadInfoPtr, NULL);
      }

      m_pngReadPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                            NULL,
                                            NULL,
                                            NULL);
      m_pngReadInfoPtr = png_create_info_struct(m_pngReadPtr);

      if ( setjmp( png_jmpbuf(m_pngReadPtr) ) )
      {
         ossimNotify(ossimNotifyLevel_WARN)
            << "Error while reading.  File corrupted?  "
            << theImageFile
            << std::endl;
      
         return;
      }

      // Reset the file pointer.
      m_str->seekg( m_restartPosition, std::ios_base::beg );
   
      //---
      // Pass the static read method to libpng to allow us to use our
      // c++ stream instead of doing "png_init_io (pp, ...);" with
      // c stream.
      //---
      png_set_read_fn( m_pngReadPtr,
                       (png_voidp)m_str,
                       (png_rw_ptr)&ossimPngReader::pngReadData );

      //---
      // Note we won't do png_set_sig_bytes(png_ptr, 8) here because we are not
      // rechecking for png signature.
      //---
      png_read_info(m_pngReadPtr, m_pngReadInfoPtr);

      //---
      // If png_set_expand used:
      // Expand data to 24-bit RGB, or 8-bit grayscale,
      // with alpha if available.
      //---
      bool expandFlag = false;

      if ( m_pngColorType == PNG_COLOR_TYPE_PALETTE )
      {
         expandFlag = true;
      }
      if ( (m_pngColorType == PNG_COLOR_TYPE_GRAY) && (m_bitDepth < 8) )
      {
         expandFlag = true;
      }
      if ( png_get_valid(m_pngReadPtr, m_pngReadInfoPtr, PNG_INFO_tRNS) )
      {
         expandFlag = true;
      }

      //---
      // If png_set_packing used:
      // Use 1 byte per pixel in 1, 2, or 4-bit depth files. */
      //---
      bool packingFlag = false;

      if ( (m_bitDepth < 8) && (m_pngColorType == PNG_COLOR_TYPE_GRAY) )
      {
         packingFlag = true;
      }

      if (expandFlag)
      {
         png_set_expand(m_pngReadPtr);
      }
      if (packingFlag)
      {
         png_set_packing(m_pngReadPtr);
      }

      // Gamma correction.
      //    ossim_float64 gamma;
      //    if (png_get_gAMA(m_pngReadPtr, m_pngReadInfoPtr, &gamma))
      //    {
      //       png_set_gamma(m_pngReadPtr, display_exponent, gamma);
      //    }

      //---
      // Turn on interlace handling... libpng returns just 1 (ie single pass)
      //  if the image is not interlaced
      //---
      png_set_interlace_handling (m_pngReadPtr);

      //---
      // Update the info structures after the transformations take effect
      //---
      png_read_update_info (m_pngReadPtr, m_pngReadInfoPtr);
   
      // We're back on row 0 or first line.
      m_currentRow = 0;
   }
}
Esempio n. 9
0
bool ossimPngReader::initReader()
{
   bool result = true;
   
   ossim_uint32 height    = png_get_image_height(m_pngReadPtr, m_pngReadInfoPtr);
   ossim_uint32 width     = png_get_image_width(m_pngReadPtr, m_pngReadInfoPtr);
   m_bitDepth            = png_get_bit_depth(m_pngReadPtr, m_pngReadInfoPtr);
   m_pngColorType        = png_get_color_type(m_pngReadPtr, m_pngReadInfoPtr);
   
   m_imageRect = ossimIrect(0, 0, width  - 1, height - 1);
   
   if (m_bitDepth == 16)
   {
      // png_set_strip_16 (m_pngReadPtr);
      m_bytePerPixelPerBand = 2;
      m_outputScalarType = OSSIM_UINT16;
   }
   else
   {
      m_bytePerPixelPerBand = 1;
   }

   // Set the read mode from scalar and color type.
   if (m_outputScalarType == OSSIM_UINT8)
   {
      if ( (m_pngColorType == PNG_COLOR_TYPE_RGB_ALPHA) ||
           (m_pngColorType == PNG_COLOR_TYPE_GRAY_ALPHA) )
      {
         m_readMode = ossimPngRead8a;
      }
      else
      {
         m_readMode = ossimPngRead8;
      }
   }
   else
   {
      if ( (m_pngColorType == PNG_COLOR_TYPE_RGB_ALPHA) ||
           (m_pngColorType == PNG_COLOR_TYPE_GRAY_ALPHA) )
      {
         m_readMode = ossimPngRead16a;
      }
      else
      {
         m_readMode = ossimPngRead16;
      }

      // Set the swap flag.  PNG stores data in network byte order(big endian).
      if(ossim::byteOrder() == OSSIM_LITTLE_ENDIAN)
      {
         m_swapFlag = true;
      }
   }
   
   //---
   // If png_set_expand used:
   // Expand data to 24-bit RGB, or 8-bit grayscale,
   // with alpha if available.
   //---
   bool expandFlag = false;

   if ( m_pngColorType == PNG_COLOR_TYPE_PALETTE )
   {
      expandFlag = true;
   }
   if ( (m_pngColorType == PNG_COLOR_TYPE_GRAY) && (m_bitDepth < 8) )
   {
      expandFlag = true;
   }
   if ( png_get_valid(m_pngReadPtr, m_pngReadInfoPtr, PNG_INFO_tRNS) )
   {
      expandFlag = true;
   }

   //---
   // If png_set_packing used:
   // Use 1 byte per pixel in 1, 2, or 4-bit depth files. */
   //---
   bool packingFlag = false;

   if ( (m_bitDepth < 8) && (m_pngColorType == PNG_COLOR_TYPE_GRAY) )
   {
      packingFlag = true;
   }

   if (expandFlag)
   {
       png_set_expand(m_pngReadPtr);
   }
   if (packingFlag)
   {
      png_set_packing(m_pngReadPtr);
   }

   // Gamma correction.
   // ossim_float64 gamma;
   // if (png_get_gAMA(m_pngReadPtr, m_pngReadInfoPtr, &gamma))
   // {
   //    png_set_gamma(png_ptr, display_exponent, gamma);
   // }

   //---
   // Turn on interlace handling... libpng returns just 1 (ie single pass)
   //  if the image is not interlaced
   //---
   m_interlacePasses = png_set_interlace_handling (m_pngReadPtr);

   //---
   // Update the info structures after the transformations take effect
   //---
   png_read_update_info (m_pngReadPtr, m_pngReadInfoPtr);

   // TODO:
   // Add check for image offsets.
   // Add check for resolution.
   // Add check for colormap.

   switch (m_pngColorType)
   {
      case PNG_COLOR_TYPE_RGB:           /* RGB */
      {
         m_numberOfInputBands  = 3;
         m_numberOfOutputBands = 3;
         break;
      }  
      case PNG_COLOR_TYPE_RGB_ALPHA:     /* RGBA */
      {
         m_numberOfInputBands  = 4;
         if (m_useAlphaChannelFlag)
         {
            m_numberOfOutputBands = 4;     
         }
         else
         {
            m_numberOfOutputBands = 3;    
         }         
         break;
      }
      case PNG_COLOR_TYPE_GRAY:          /* Grayscale */
      {
         m_numberOfInputBands = 1;
         m_numberOfOutputBands = 1;
         break;
      }  
      case PNG_COLOR_TYPE_GRAY_ALPHA:    /* Grayscale + alpha */
      {
         m_numberOfInputBands = 2;
         if (m_useAlphaChannelFlag)
         {
            m_numberOfOutputBands = 2;     
         }
         else
         {
            m_numberOfOutputBands = 1;
         }
        break;
      }
     case PNG_COLOR_TYPE_PALETTE:       /* Indexed */
     {
        m_numberOfInputBands  = 3;
        m_numberOfOutputBands = 3;
        break;
     }  
     default:                   /* Unknown type */
     {
        result = false;
     }
   }

   if ( result )
   {
      m_lineBufferSizeInBytes = png_get_rowbytes(m_pngReadPtr, m_pngReadInfoPtr);
      
      // Set the max pixel value.
      setMaxPixelValue();
      
      // Set to OSSIM_USHORT11 for use of specialized tile.
      if (m_maxPixelValue[0] == 2047.0)
      {
         m_outputScalarType = OSSIM_USHORT11;
      }

      // We're on row 0 or first line.
      m_currentRow = 0;
      
      if (traceDebug())
      {
         ossimNotify(ossimNotifyLevel_DEBUG)
            << "ossimPngReader::initReader DEBUG:"
            << "\nm_imageRect:                     " << m_imageRect
            << "\nm_bitDepth:                      " << int(m_bitDepth)
            << "\nm_pngColorType:                  "
            <<  getPngColorTypeString().c_str()
            << "\nm_numberOfInputBands:            " << m_numberOfInputBands
            << "\nm_numberOfOutputBands:           " << m_numberOfOutputBands
            << "\nm_bytePerPixelPerBand:           " << m_bytePerPixelPerBand
            << "\nm_lineBufferSizeInBytes:         " << m_lineBufferSizeInBytes
            << "\nm_interlacePasses:               " << m_interlacePasses
            << "\npalette expansion:                "
            << (expandFlag?"on":"off")
            << "\npacking (1,2,4 bit to one byte):  "
            << (packingFlag?"on":"off")
            << "\nm_readMode:                      " << m_readMode
            << "\nm_swapFlag:                      " << m_swapFlag
            << std::endl;
         
         for (ossim_uint32 band = 0; band < m_numberOfInputBands; ++band)
         {
            ossimNotify(ossimNotifyLevel_DEBUG)
               << "max[" << band << "]:  " << m_maxPixelValue[band]
               << std::endl;
         }
      }
   }

   return result;
   
} // End: ossimPngReader::initReader()
Esempio n. 10
0
void LoadPNG( const char *name, byte **pic, int *width, int *height,
	      int *numLayers, int *numMips, int *bits, byte alphaByte )
{
	int          bit_depth;
	int          color_type;
	png_uint_32  w;
	png_uint_32  h;
	unsigned int row;
	png_infop    info;
	png_structp  png;
	png_bytep    *row_pointers;
	byte         *data;
	byte         *out;

	// load png
	ri.FS_ReadFile( name, ( void ** ) &data );

	if ( !data )
	{
		return;
	}

	png = png_create_read_struct( PNG_LIBPNG_VER_STRING, ( png_voidp ) nullptr, png_user_error_fn, png_user_warning_fn );

	if ( !png )
	{
		ri.Printf( PRINT_WARNING, "LoadPNG: png_create_write_struct() failed for (%s)\n", name );
		ri.FS_FreeFile( data );
		return;
	}

	// allocate/initialize the memory for image information.  REQUIRED
	info = png_create_info_struct( png );

	if ( !info )
	{
		ri.Printf( PRINT_WARNING, "LoadPNG: png_create_info_struct() failed for (%s)\n", name );
		ri.FS_FreeFile( data );
		png_destroy_read_struct( &png, ( png_infopp ) nullptr, ( png_infopp ) nullptr );
		return;
	}

	/*
	 * Set error handling if you are using the setjmp/longjmp method (this is
	 * the common method of doing things with libpng).  REQUIRED unless you
	 * set up your own error handlers in the png_create_read_struct() earlier.
	 */
	if ( setjmp( png_jmpbuf( png ) ) )
	{
		// if we get here, we had a problem reading the file
		ri.Printf( PRINT_WARNING, "LoadPNG: first exception handler called for (%s)\n", name );
		ri.FS_FreeFile( data );
		png_destroy_read_struct( &png, ( png_infopp ) & info, ( png_infopp ) nullptr );
		return;
	}

	png_set_read_fn( png, data, png_read_data );

	png_set_sig_bytes( png, 0 );

	// The call to png_read_info() gives us all of the information from the
	// PNG file before the first IDAT (image data chunk).  REQUIRED
	png_read_info( png, info );

	// get picture info
	png_get_IHDR( png, info, ( png_uint_32 * ) &w, ( png_uint_32 * ) &h, &bit_depth, &color_type, nullptr, nullptr, nullptr );

	// tell libpng to strip 16 bit/color files down to 8 bits/color
	png_set_strip_16( png );

	// expand paletted images to RGB triplets
	if ( color_type & PNG_COLOR_MASK_PALETTE )
	{
		png_set_expand( png );
	}

	// expand gray-scaled images to RGB triplets
	if ( !( color_type & PNG_COLOR_MASK_COLOR ) )
	{
		png_set_gray_to_rgb( png );
	}

	// expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel

	// expand paletted or RGB images with transparency to full alpha channels
	// so the data will be available as RGBA quartets
	if ( png_get_valid( png, info, PNG_INFO_tRNS ) )
	{
		png_set_tRNS_to_alpha( png );
	}

	// if there is no alpha information, fill with alphaByte
	if ( !( color_type & PNG_COLOR_MASK_ALPHA ) )
	{
		png_set_filler( png, alphaByte, PNG_FILLER_AFTER );
	}

	// expand pictures with less than 8bpp to 8bpp
	if ( bit_depth < 8 )
	{
		png_set_packing( png );
	}

	png_set_interlace_handling( png );

	// update structure with the above settings
	png_read_update_info( png, info );

	// allocate the memory to hold the image
	*width = w;
	*height = h;
	*pic = out = ( byte * ) ri.Z_Malloc( w * h * 4 );

	row_pointers = ( png_bytep * ) ri.Hunk_AllocateTempMemory( sizeof( png_bytep ) * h );

	// set a new exception handler
	if ( setjmp( png_jmpbuf( png ) ) )
	{
		ri.Printf( PRINT_WARNING, "LoadPNG: second exception handler called for (%s)\n", name );
		ri.Hunk_FreeTempMemory( row_pointers );
		ri.FS_FreeFile( data );
		png_destroy_read_struct( &png, ( png_infopp ) & info, ( png_infopp ) nullptr );
		return;
	}

	for ( row = 0; row < h; row++ )
	{
		row_pointers[ row ] = ( png_bytep )( out + ( row * 4 * w ) );
	}

	// read image data
	png_read_image( png, row_pointers );

	// read rest of file, and get additional chunks in info
	png_read_end( png, info );

	// clean up after the read, and free any memory allocated
	png_destroy_read_struct( &png, &info, ( png_infopp ) nullptr );

	ri.Hunk_FreeTempMemory( row_pointers );
	ri.FS_FreeFile( data );
}
void RGBAUtilities::readPngFile(char* file_name)
{
    char header[8];    // 8 is the maximum size that can be checked
    
    /* open file and test for it being a png */
    FILE *fp = fopen(file_name, "rb");
    if (!fp)
        abort_("[read_png_file] File %s could not be opened for reading", file_name);
    fread(header, 1, 8, fp);
//    if (png_sig_cmp(header, 0, 8))
//        abort_("[read_png_file] File %s is not recognized as a PNG file", file_name);
//    
    
    /* initialize stuff */
    pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    
    if (!pngPtr)
        abort_("[read_png_file] png_create_read_struct failed");
    
    infoPtr = png_create_info_struct(pngPtr);
    if (!infoPtr)
        abort_("[read_png_file] png_create_info_struct failed");
    
    if (setjmp(png_jmpbuf(pngPtr)))
        abort_("[read_png_file] Error during init_io");
    
    png_init_io(pngPtr, fp);
    png_set_sig_bytes(pngPtr, 8);
    
    png_read_info(pngPtr, infoPtr);
    
    imageWidth = png_get_image_width(pngPtr, infoPtr);
    imageLength = png_get_image_height(pngPtr, infoPtr);
    config = png_get_color_type(pngPtr, infoPtr);
    bitsPerSample = png_get_bit_depth(pngPtr, infoPtr); // = 8 bits
        
    numberOfPasses = png_set_interlace_handling(pngPtr);
    png_read_update_info(pngPtr, infoPtr);
    
    imageWidth = png_get_image_width(pngPtr, infoPtr);
    imageLength = png_get_image_height(pngPtr, infoPtr);

    samplesPerPixel = png_get_channels(pngPtr, infoPtr); // = 4 bytes

    bitsPerPixel = samplesPerPixel*bitsPerSample;
    linebytes = samplesPerPixel * imageWidth; // = 640
    //linebytes = png_get_rowbytes(pngPtr, infoPtr); = 640
    imageBitSize = (sizeof(uint8) * imageWidth * imageLength * samplesPerPixel);
    imageSize = imageWidth * imageLength * samplesPerPixel;
    //printf("linebytes = %i, expected %i\n",linebytes,png_get_rowbytes(pngPtr, infoPtr));
    //printf("Image Height is %d", sizeof(png_bytep) * imageLength);

    
    /* read file */
    if (setjmp(png_jmpbuf(pngPtr)))
        abort_("[read_png_file] Error during read_image");
    
    rowPointers = (png_bytep*) malloc(sizeof(png_bytep) * imageLength);
    for (y=0; y<imageLength; y++)
        rowPointers[y] = (png_byte*) malloc(png_get_rowbytes(pngPtr,infoPtr));
    
    png_read_image(pngPtr, rowPointers);
    
    fclose(fp);
}
Esempio n. 12
0
errCode genTextures(const char *rootDir, const sFileList *files, sTex ***dynarrTextures){
	static const size_t BUFFLEN = 1024;

	int numTexs=0;
	int idxFile = files->num;
	sTex *refTex;

	if(idxFile <= 0 || rootDir == NULL || rootDir[0] == '\0' || dynarrTextures == NULL)
		return PROBLEM;

	size_t lenRootDir = strlen(rootDir);
	char filePath[BUFFLEN];
	FILE *handFile;
	png_byte header[PNGHEAD_SIZE];

	strncpy(filePath, rootDir, 1024);
	if(lenRootDir>0 && filePath[lenRootDir-1]!='/'){
		filePath[lenRootDir] = '/';
		lenRootDir += 1;
	}

	while(idxFile > 0){
		--idxFile;

		strncpy(&filePath[lenRootDir], files->dynarrFiles[idxFile], 1024 - lenRootDir);

		handFile = fopen(filePath, "rb");

		if(handFile == NULL){
			WARN("Can't open file %s", filePath);
			continue;
		}

		if(	fread(header, sizeof(png_byte), PNGHEAD_SIZE, handFile) == PNGHEAD_SIZE
			&& png_sig_cmp(header, 0, PNGHEAD_SIZE) == 0
		){
			XTRA_LOG("File %s opened as PNG", filePath);

		}else{
			WARN("File %s isn't a PNG", filePath);
			fclose(handFile);
			continue;
		}

		++numTexs;
		(*dynarrTextures) = (sTex**)realloc_chk((*dynarrTextures), (numTexs+1) * sizeof(sTex*));
		(*dynarrTextures)[numTexs]=NULL;

		refTex = (*dynarrTextures)[numTexs-1] = (sTex*)malloc_chk(sizeof(sTex));
		memset(refTex, 0, sizeof(sTex));

		refTex->pngptrData = png_create_read_struct(
			PNG_LIBPNG_VER_STRING, NULL, NULL, &myPNGWarnFoo
		);

		if(refTex->pngptrData == NULL){
			WARN("Unable to create png struct");
			fclose(handFile);
			continue;
		}

		if(setjmp(png_jmpbuf(refTex->pngptrData)) != 0){ 	/** jumps here on errors. */
			cleanupPNGImg(
				refTex->pngptrData,
				&refTex->dynarrRows
			);
			png_destroy_read_struct(
				&(refTex->pngptrData),
				&(refTex->pngptrInfo),
				NULL
			);
			refTex->h = refTex->w = 0;

		}else{
			refTex->pngptrInfo = png_create_info_struct(
				refTex->pngptrData
			);

			if(refTex->pngptrInfo == NULL){
				WARN("Unable to create png info struct");
				fclose(handFile);
				continue;
			}

			/** setup PNG decode */
			png_init_io(refTex->pngptrData, handFile);
			png_set_sig_bytes(refTex->pngptrData, PNGHEAD_SIZE);
			png_read_info(refTex->pngptrData, refTex->pngptrInfo);

			png_byte colorCurrent = png_get_color_type(
				refTex->pngptrData, refTex->pngptrInfo
			);

			png_set_filler(refTex->pngptrData, 0, PNG_FILLER_AFTER);
			png_set_packing(refTex->pngptrData);	/** if < 8 bits */

			{
				png_color_8p sig_bit;
				if (png_get_sBIT(refTex->pngptrData, refTex->pngptrInfo, &sig_bit))
					png_set_shift(refTex->pngptrData, sig_bit);
			}

			switch(colorCurrent){
				case PNG_COLOR_TYPE_RGB_ALPHA:
					/** already good */
				break;
				case PNG_COLOR_TYPE_RGB:
					png_set_tRNS_to_alpha(refTex->pngptrData);
				break;
				case PNG_COLOR_TYPE_PALETTE:
					png_set_palette_to_rgb( refTex->pngptrData );
					png_set_tRNS_to_alpha(refTex->pngptrData);
				break;
				case PNG_COLOR_TYPE_GRAY:
					png_set_expand_gray_1_2_4_to_8( refTex->pngptrData );
					png_set_tRNS_to_alpha(refTex->pngptrData);
				break;
				default:
					WARN("unsupported colour");
				break;
			}

			png_read_update_info(refTex->pngptrData, refTex->pngptrInfo);

			colorCurrent = png_get_color_type(
				refTex->pngptrData, refTex->pngptrInfo
			);

			if(colorCurrent != PNG_COLOR_TYPE_RGB_ALPHA){
				printf("<warning> %s didn't convert to the right colour type\n", files->dynarrFiles[idxFile]);
				png_destroy_read_struct(&refTex->pngptrData, &refTex->pngptrInfo, (png_infopp)NULL);
				fclose(handFile);
				continue;
			}

			refTex->colorType = colorCurrent;

			const int numPasses = png_set_interlace_handling( refTex->pngptrData );

			/** setup other data */
			copyString(&refTex->name, files->dynarrFiles[idxFile]);

			/** setup texture */
			unsigned int row;
			const png_uint_32 sizeRow = png_get_rowbytes( refTex->pngptrData, refTex->pngptrInfo );

			refTex->w = png_get_image_width(
				refTex->pngptrData, refTex->pngptrInfo
			);
			refTex->h = png_get_image_height(
				refTex->pngptrData, refTex->pngptrInfo
			);

			if(sizeRow/refTex->w != DEFAULT_BYTE_PP){
				WARN("%s didn't convert to the right bit depth", refTex->name);
				png_destroy_read_struct(&refTex->pngptrData, &refTex->pngptrInfo, (png_infopp)NULL);
				fclose(handFile);
				continue;
			}

			refTex->dynarrRows = calloc_chk((refTex->h +1), sizeof(png_byte*));
			refTex->dynarrRows[refTex->h] = NULL;

			for(row = 0; row < refTex->h; ++row)
				refTex->dynarrRows[row] = png_malloc(refTex->pngptrData, sizeRow);

			unsigned int pass;
			for(pass=0; pass < numPasses; ++pass){
				for(row = 0; row < refTex->h; ++row){
					png_read_rows(
						refTex->pngptrData,
						&refTex->dynarrRows[row],
						NULL,
						1
					);
				}
			}

			png_read_end(refTex->pngptrData, refTex->pngptrInfo);
		}

		fclose(handFile);
	}
	return NOPROB;
}
void PNGImageDecoder::headerAvailable()
{
    png_structp png = m_reader->pngPtr();
    png_infop info = m_reader->infoPtr();
    png_uint_32 width = png_get_image_width(png, info);
    png_uint_32 height = png_get_image_height(png, info);
    
    // Protect against large images.
    if (width > cMaxPNGSize || height > cMaxPNGSize) {
        longjmp(JMPBUF(png), 1);
        return;
    }
    
    // We can fill in the size now that the header is available.  Avoid memory
    // corruption issues by neutering setFailed() during this call; if we don't
    // do this, failures will cause |m_reader| to be deleted, and our jmpbuf
    // will cease to exist.  Note that we'll still properly set the failure flag
    // in this case as soon as we longjmp().
    m_doNothingOnFailure = true;
    bool result = setSize(width, height);
    m_doNothingOnFailure = false;
    if (!result) {
        longjmp(JMPBUF(png), 1);
        return;
    }

    int bitDepth, colorType, interlaceType, compressionType, filterType, channels;
    png_get_IHDR(png, info, &width, &height, &bitDepth, &colorType, &interlaceType, &compressionType, &filterType);

    if ((colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_RGB_ALPHA) && !m_ignoreGammaAndColorProfile) {
        // We currently support color profiles only for RGB and RGBA PNGs.  Supporting
        // color profiles for gray-scale images is slightly tricky, at least using the
        // CoreGraphics ICC library, because we expand gray-scale images to RGB but we
        // don't similarly transform the color profile.  We'd either need to transform
        // the color profile or we'd need to decode into a gray-scale image buffer and
        // hand that to CoreGraphics.
        m_colorProfile = readColorProfile(png, info);
    }

    // The options we set here match what Mozilla does.

    // Expand to ensure we use 24-bit for RGB and 32-bit for RGBA.
    if (colorType == PNG_COLOR_TYPE_PALETTE || (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8))
        png_set_expand(png);
    
    png_bytep trns = 0;
    int trnsCount = 0;
    if (png_get_valid(png, info, PNG_INFO_tRNS)) {
        png_get_tRNS(png, info, &trns, &trnsCount, 0);
        png_set_expand(png);
    }

    if (bitDepth == 16)
        png_set_strip_16(png);

    if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png);

    // Deal with gamma and keep it under our control.
    double gamma;
    if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) {
        if ((gamma <= 0.0) || (gamma > cMaxGamma)) {
            gamma = cInverseGamma;
            png_set_gAMA(png, info, gamma);
        }
        png_set_gamma(png, cDefaultGamma, gamma);
    } else
        png_set_gamma(png, cDefaultGamma, cInverseGamma);

    // Tell libpng to send us rows for interlaced pngs.
    if (interlaceType == PNG_INTERLACE_ADAM7)
        png_set_interlace_handling(png);

    // Update our info now.
    png_read_update_info(png, info);
    channels = png_get_channels(png, info);
    ASSERT(channels == 3 || channels == 4);

    m_reader->setHasAlpha(channels == 4);

    if (m_reader->decodingSizeOnly()) {
        // If we only needed the size, halt the reader.
#if defined(PNG_LIBPNG_VER_MAJOR) && defined(PNG_LIBPNG_VER_MINOR) && (PNG_LIBPNG_VER_MAJOR > 1 || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 5))
        // '0' argument to png_process_data_pause means: Do not cache unprocessed data.
        m_reader->setReadOffset(m_reader->currentBufferSize() - png_process_data_pause(png, 0));
#else
        m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size);
        png->buffer_size = 0;
#endif
    }
}
Esempio n. 14
0
/* Write a VIPS image to PNG.
 */
static int
write_vips( Write *write, 
	int compress, int interlace, const char *profile,
	VipsForeignPngFilter filter, gboolean strip,
	gboolean palette, int colours, int Q, double dither )
{
	VipsImage *in = write->in;

	int bit_depth;
	int color_type;
	int interlace_type;
	int i, nb_passes;

        g_assert( in->BandFmt == VIPS_FORMAT_UCHAR || 
		in->BandFmt == VIPS_FORMAT_USHORT );
	g_assert( in->Coding == VIPS_CODING_NONE );
        g_assert( in->Bands > 0 && in->Bands < 5 );

	/* Catch PNG errors.
	 */
	if( setjmp( png_jmpbuf( write->pPng ) ) ) 
		return( -1 );

	/* Check input image. If we are writing interlaced, we need to make 7
	 * passes over the image. We advertise ourselves as seq, so to ensure
	 * we only suck once from upstream, switch to WIO. 
	 */
	if( interlace ) {
		if( !(write->memory = vips_image_copy_memory( in )) )
			return( -1 );
		in = write->memory;
	}
	else {
		if( vips_image_pio_input( in ) )
			return( -1 );
	}
	if( compress < 0 || compress > 9 ) {
		vips_error( "vips2png", 
			"%s", _( "compress should be in [0,9]" ) );
		return( -1 );
	}

	/* Set compression parameters.
	 */
	png_set_compression_level( write->pPng, compress );

	/* Set row filter.
	 */
	png_set_filter( write->pPng, 0, filter );

	bit_depth = in->BandFmt == VIPS_FORMAT_UCHAR ? 8 : 16;

	switch( in->Bands ) {
	case 1: color_type = PNG_COLOR_TYPE_GRAY; break;
	case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break;
	case 3: color_type = PNG_COLOR_TYPE_RGB; break;
	case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break;

	default:
		vips_error( "vips2png", 
			_( "can't save %d band image as png" ), in->Bands );
		return( -1 );
	}

#ifdef HAVE_IMAGEQUANT
	/* Enable image quantisation to paletted 8bpp PNG if colours is set.
	 */
	if( palette ) {
		g_assert( colours >= 2 && 
			colours <= 256 );
		bit_depth = 8;
		color_type = PNG_COLOR_TYPE_PALETTE;
	}
#else
	if( palette )
		g_warning( "%s",
			_( "ignoring palette (no quantisation support)" ) );
#endif /*HAVE_IMAGEQUANT*/

	interlace_type = interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;

	png_set_IHDR( write->pPng, write->pInfo, 
		in->Xsize, in->Ysize, bit_depth, color_type, interlace_type, 
		PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT );

	/* Set resolution. libpng uses pixels per meter.
	 */
	png_set_pHYs( write->pPng, write->pInfo, 
		VIPS_RINT( in->Xres * 1000 ), VIPS_RINT( in->Yres * 1000 ), 
		PNG_RESOLUTION_METER );

	/* Set ICC Profile.
	 */
	if( profile && 
		!strip ) {
		if( strcmp( profile, "none" ) != 0 ) { 
			void *data;
			size_t length;

			if( !(data = vips__file_read_name( profile, 
				vips__icc_dir(), &length )) ) 
				return( -1 );

#ifdef DEBUG
			printf( "write_vips: "
				"attaching %zd bytes of ICC profile\n",
				length );
#endif /*DEBUG*/

			png_set_iCCP( write->pPng, write->pInfo, "icc", 
				PNG_COMPRESSION_TYPE_BASE, data, length );
		}
	}
	else if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) &&
		!strip ) {
		void *data;
		size_t length;

		if( vips_image_get_blob( in, VIPS_META_ICC_NAME, 
			&data, &length ) ) 
			return( -1 ); 

#ifdef DEBUG
		printf( "write_vips: attaching %zd bytes of ICC profile\n",
			length );
#endif /*DEBUG*/

		png_set_iCCP( write->pPng, write->pInfo, "icc", 
			PNG_COMPRESSION_TYPE_BASE, data, length );
	}

	if( vips_image_get_typeof( in, VIPS_META_XMP_NAME ) ) {
		const char *str;

		if( vips_image_get_string( in, VIPS_META_XMP_NAME, &str ) )
			return( -1 );

		vips__png_set_text( write->pPng, write->pInfo, 
			"XML:com.adobe.xmp", str );
	}

	/* Set any "png-comment-xx-yyy" metadata items.
	 */
	if( vips_image_map( in, 
		write_png_comment, write ) )
		return( -1 );

#ifdef HAVE_IMAGEQUANT
	if( palette ) {
		VipsImage *im_index;
		VipsImage *im_palette;
		int palette_count;
		png_color *png_palette;
		png_byte *png_trans;
		int trans_count;

		if( vips__quantise_image( in, &im_index, &im_palette, 
			colours, Q, dither ) ) 
			return( -1 );

		palette_count = im_palette->Xsize;

		g_assert( palette_count <= PNG_MAX_PALETTE_LENGTH );

		png_palette = (png_color *) png_malloc( write->pPng,
			palette_count * sizeof( png_color ) );
		png_trans = (png_byte *) png_malloc( write->pPng,
			palette_count * sizeof( png_byte ) );
		trans_count = 0;
		for( i = 0; i < palette_count; i++ ) {
			VipsPel *p = (VipsPel *) 
				VIPS_IMAGE_ADDR( im_palette, i, 0 );
			png_color *col = &png_palette[i];

			col->red = p[0];
			col->green = p[1];
			col->blue = p[2];
			png_trans[i] = p[3];
			if( p[3] != 255 )
				trans_count = i + 1;
#ifdef DEBUG
			printf( "write_vips: palette[%d] %d %d %d %d\n",
				i + 1, p[0], p[1], p[2], p[3] );
#endif /*DEBUG*/
		}

#ifdef DEBUG
		printf( "write_vips: attaching %d color palette\n",
			palette_count );
#endif /*DEBUG*/
		png_set_PLTE( write->pPng, write->pInfo, png_palette,
			palette_count );
		if( trans_count ) {
#ifdef DEBUG
			printf( "write_vips: attaching %d alpha values\n",
				trans_count );
#endif /*DEBUG*/
			png_set_tRNS( write->pPng, write->pInfo, png_trans,
				trans_count, NULL );
		}

		png_free( write->pPng, (void *) png_palette );
		png_free( write->pPng, (void *) png_trans );

		VIPS_UNREF( im_palette );

		VIPS_UNREF( write->memory );
		write->memory = im_index;
		in = write->memory;
	}
#endif /*HAVE_IMAGEQUANT*/

	png_write_info( write->pPng, write->pInfo );

	/* If we're an intel byte order CPU and this is a 16bit image, we need
	 * to swap bytes.
	 */
	if( bit_depth > 8 && 
		!vips_amiMSBfirst() ) 
		png_set_swap( write->pPng ); 

	if( interlace )	
		nb_passes = png_set_interlace_handling( write->pPng );
	else
		nb_passes = 1;

	/* Write data.
	 */
	for( i = 0; i < nb_passes; i++ ) 
		if( vips_sink_disc( in, write_png_block, write ) )
			return( -1 );

	/* The setjmp() was held by our background writer: reset it.
	 */
	if( setjmp( png_jmpbuf( write->pPng ) ) ) 
		return( -1 );

	png_write_end( write->pPng, write->pInfo );

	return( 0 );
}
Esempio n. 15
0
static void png_info_callback(png_structp png_ptr, png_infop info_ptr)
{
	int bit_depth, color_type, intent;
	double gamma;
	unsigned char bytes_per_pixel=3;
	struct cached_image *cimg;

	cimg=global_cimg;

	bit_depth=png_get_bit_depth(png_ptr, info_ptr);
	color_type=png_get_color_type(png_ptr, info_ptr);
	if (color_type == PNG_COLOR_TYPE_PALETTE)
		png_set_expand(png_ptr);
	if (color_type == PNG_COLOR_TYPE_GRAY &&
		bit_depth < 8) png_set_expand(png_ptr);
	if (png_get_valid(png_ptr, info_ptr,
		PNG_INFO_tRNS)){
		png_set_expand(png_ptr); /* Legacy version of
		png_set_tRNS_to_alpha(png_ptr); */
		bytes_per_pixel++;
	}
	if (color_type == PNG_COLOR_TYPE_GRAY ||
		color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
		png_set_gray_to_rgb(png_ptr);
	if (bit_depth==16){
#ifndef REPACK_16
#ifdef C_LITTLE_ENDIAN
		/* We use native endianity only if unsigned short is 2-byte
		 * because otherwise we have to reassemble the buffer so we
		 * will leave in the libpng-native big endian.
		 */
		png_set_swap(png_ptr);
#endif /* #ifdef C_LITTLE_ENDIAN */
#endif /* #ifndef REPACK_16 */
		bytes_per_pixel*=(int)sizeof(unsigned short);
	}
	png_set_interlace_handling(png_ptr);
	if (color_type==PNG_COLOR_TYPE_RGB_ALPHA
		||color_type==PNG_COLOR_TYPE_GRAY_ALPHA){
		if (bytes_per_pixel==3
			||bytes_per_pixel==3*sizeof(unsigned short))
			bytes_per_pixel=4*bytes_per_pixel/3;
	}
	cimg->width=(int)png_get_image_width(png_ptr,info_ptr);
	cimg->height=(int)png_get_image_height(png_ptr,info_ptr);
	cimg->buffer_bytes_per_pixel=bytes_per_pixel;
	if (png_get_sRGB(png_ptr, info_ptr, &intent)){
		gamma=sRGB_gamma;
	}
	else
	{
		if (!png_get_gAMA(png_ptr, info_ptr, &gamma)){
			gamma=sRGB_gamma;
		}
	}
	if (gamma < 0.01 || gamma > 100)
		gamma = sRGB_gamma;
	cimg->red_gamma=(float)gamma;
	cimg->green_gamma=(float)gamma;
	cimg->blue_gamma=(float)gamma;
	png_read_update_info(png_ptr,info_ptr);
	cimg->strip_optimized=0;
	if (header_dimensions_known(cimg))
		img_my_png_error(png_ptr, "bad image size");
}
Esempio n. 16
0
static FtkBitmap* load_png (const char *filename)
{
	FtkColor  bg = {0};
	unsigned int x = 0;
	unsigned int y = 0;
	png_byte bit_depth = 0;
	unsigned int width = 0;
	unsigned int height = 0;
	int number_of_passes = 0;
	png_byte color_type = 0;

	png_infop info_ptr = NULL;
	png_structp png_ptr = NULL;
	png_bytep * row_pointers = NULL;
	
	char header[8];	   // 8 is the maximum size that can be checked
	int rowbytes = 0;
	FtkColor* dst = NULL;
	unsigned char* src = NULL;
	FtkBitmap* bitmap = NULL;

	FILE *fp = fopen(filename, "rb");
	return_val_if_fail(fp, NULL);

	bg.a = 0xff;

	fread(header, 1, 8, fp);
	return_val_if_fail(png_sig_cmp(header, 0, 8) == 0, NULL);

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	return_val_if_fail(png_ptr, NULL);

	info_ptr = png_create_info_struct(png_ptr);
	return_val_if_fail(info_ptr, NULL);

	return_val_if_fail(setjmp(png_jmpbuf(png_ptr)) == 0, NULL);

	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, 8);

	png_read_info(png_ptr, info_ptr);

	width = png_get_image_width(png_ptr, info_ptr);
	height = png_get_image_height(png_ptr, info_ptr);
	color_type = png_get_color_type(png_ptr, info_ptr);
	bit_depth = png_get_bit_depth(png_ptr, info_ptr);

	number_of_passes = png_set_interlace_handling(png_ptr);
	png_read_update_info(png_ptr, info_ptr);

	return_val_if_fail(setjmp(png_jmpbuf(png_ptr)) == 0, NULL);
	
	rowbytes = png_get_rowbytes(png_ptr,info_ptr);
	row_pointers = (png_bytep*) FTK_ZALLOC(sizeof(png_bytep) * height);

	for (y=0; y<height; y++) 
	{
		row_pointers[y] = (png_byte*) FTK_ZALLOC(rowbytes);
	}

	png_read_image(png_ptr, row_pointers);

	fclose(fp);
	
	bitmap = ftk_bitmap_create(width, height, bg);
	dst = ftk_bitmap_lock(bitmap);

	if (color_type == PNG_COLOR_TYPE_RGBA)
	{
		unsigned int w = width;
		unsigned int h = height;
		for(y = 0; y < h; y++)
		{
			src = row_pointers[y];
			for(x = 0; x < w; x++)
			{
				if(src[3])
				{
					dst->r = src[0];
					dst->g = src[1];
					dst->b = src[2];
					dst->a = src[3];
				}
				else
				{
					dst->r = 0xff;
					dst->g = 0xff;
					dst->b = 0xff;
					dst->a = 0;
				}
				src +=4;
				dst++;
			}
		}
	}
	else if(color_type == PNG_COLOR_TYPE_RGB)
	{
		unsigned int w = width;
		unsigned int h = height;
		for(y = 0; y < h; y++)
		{
			src = row_pointers[y];
			for(x = 0; x < w; x++)
			{
				dst->r = src[0];
				dst->g = src[1];
				dst->b = src[2];
				dst->a = 0xff;
				src += 3;
				dst++;
			}
		}
	}
	else
	{
		assert(!"not supported.");
	}

	for(y = 0; y < height; y++)
	{
		FTK_FREE(row_pointers[y]);
	}
	FTK_FREE(row_pointers);

	return bitmap;
}
Esempio n. 17
0
int fh_png_load(const char *name,unsigned char **buffer,int* /*xp*/,int* /*yp*/)
{
	static const png_color_16 my_background = {0, 0, 0, 0, 0};

	png_structp png_ptr;
	png_infop info_ptr;
	png_uint_32 width, height;
	unsigned int i;
	int bit_depth, color_type, interlace_type;
	int number_passes,pass;
	png_byte * fbptr;
	FILE     * fh;

	if(!(fh=fopen(name,"rb")))	return(FH_ERROR_FILE);

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
	if(png_ptr == NULL) {
		fclose(fh);
		return(FH_ERROR_FORMAT);
	}
	info_ptr = png_create_info_struct(png_ptr);
	if(info_ptr == NULL)
	{
		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
		fclose(fh);
		return(FH_ERROR_FORMAT);
	}

	if(setjmp(png_ptr->jmpbuf))
	{
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		fclose(fh);
		return(FH_ERROR_FORMAT);
	}

	png_init_io(png_ptr,fh);

	png_read_info(png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL);

	if (color_type == PNG_COLOR_TYPE_PALETTE)
	{
		png_set_palette_to_rgb(png_ptr);
		png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
		/* other possibility for png_set_background: use png_get_bKGD */
	}

	if (color_type == PNG_COLOR_TYPE_GRAY        ||
			color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
	{
		png_set_gray_to_rgb(png_ptr);
		png_set_background(png_ptr, (png_color_16*)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
	}

	/* this test does not trigger for 8bit-paletted PNGs with newer libpng (1.2.36 at least),
	   but the data delivered is with alpha channel anyway, so always strip alpha for now
	 */
#if PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR <= 2 && PNG_LIBPNG_VER_RELEASE < 36
	if (color_type & PNG_COLOR_MASK_ALPHA)
#endif
		png_set_strip_alpha(png_ptr);

	if (bit_depth < 8)
		png_set_packing(png_ptr);

	if (bit_depth == 16)
		png_set_strip_16(png_ptr);

	/* on Intel PC ?:
	   if (bit_depth == 16)
	   png_set_swap(png_ptr);
	   */

	number_passes = png_set_interlace_handling(png_ptr);
	png_read_update_info(png_ptr,info_ptr);

	if (width * 3 != png_get_rowbytes(png_ptr, info_ptr))
	{
		printf("[png.cpp]: Error processing %s - please report (including image).\n", name);
		printf("           width: %lu rowbytes: %lu\n", width, png_get_rowbytes(png_ptr, info_ptr));
		fclose(fh);
		return(FH_ERROR_FORMAT);
	}

	for(pass = 0; pass < number_passes; pass++)
	{
		fbptr = (png_byte *)(*buffer);
		for (i = 0; i < height; i++, fbptr += width * 3)
		{
			png_read_row(png_ptr, fbptr, NULL);
		}
	}
	png_read_end(png_ptr, info_ptr);
	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
	fclose(fh);
	return(FH_ERROR_OK);
}
Esempio n. 18
0
int PngDecoder::validate()
{
    if (png_sig_cmp((png_bytep)buf->data(), 0, PNG_HEADER_SIZE)) {
        std::cout << "[PngDecoder] error: %s is not a PNG." << std::endl;
        return -1;
    }
    buf->drain(PNG_HEADER_SIZE);

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {
        std::cout << "[PngDecoder] error: png_create_read_struct returned 0." << std::endl;
        return -1;
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        std::cout << "[PngDecoder] error: png_create_info_struct returned 0." << std::endl;
        png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
        return -1;
    }

    end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        std::cout << "[PngDecoder] error: png_create_info_struct returned 0." << std::endl;
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
        return -1;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        std::cout << "[PngDecoder] error from libpng" << std::endl;
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return -1;
    }

    png_set_read_fn(png_ptr, buf, pngDecoderReadFunction);

    png_set_sig_bytes(png_ptr, PNG_HEADER_SIZE);

    png_read_info(png_ptr, info_ptr);

    png_set_expand(png_ptr);
    png_set_strip_16(png_ptr);
    png_set_gray_to_rgb(png_ptr);
    png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER);
    png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);

    imgInfo.width    = png_get_image_width(png_ptr, info_ptr);
    imgInfo.height   = png_get_image_height(png_ptr, info_ptr);

    imgInfo.color_type = png_get_color_type(png_ptr, info_ptr);
    imgInfo.channels = png_get_channels(png_ptr, info_ptr);
    imgInfo.bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    imgInfo.interlance_type = png_get_interlace_type(png_ptr, info_ptr);
    imgInfo.rowbytes = png_get_rowbytes(png_ptr, info_ptr);

#ifdef _PNGDECODER_DEBUG
    std::cout << "[PngDecoder] Extracted w=" << imgInfo.width
              << " h="  << imgInfo.height
              << " color_type=" << imgInfo.color_type
              << " bit_depth="<< imgInfo.bit_depth
              << " rowbytes="<< imgInfo.rowbytes
              << " channels="<< imgInfo.channels
              << " interlance_type="<< imgInfo.interlance_type
              << std::endl;
#endif

    if (imgInfo.bit_depth != 8) {
        std::cout << "[PngDecoder] error: Unsupported bit depth=" << imgInfo.bit_depth <<". Must be 8." << std::endl;
        return -1;
    }

    switch(imgInfo.color_type) {
    case PNG_COLOR_TYPE_RGB:
        imgInfo.format = GL_RGB;
        break;
    case PNG_COLOR_TYPE_RGB_ALPHA:
        imgInfo.format = GL_RGBA;
        break;
    case PNG_COLOR_TYPE_PALETTE:
        if (imgInfo.color_type & PNG_COLOR_MASK_ALPHA) {
            imgInfo.format = GL_RGBA;
        } else if (imgInfo.color_type & PNG_COLOR_MASK_COLOR) {
            imgInfo.format = GL_RGB;
        }
        break;
    default:
        std::cout << "[PngDecoder] error: unknown libpng color type=" << imgInfo.color_type << " rgb=" << PNG_COLOR_TYPE_RGB << " rgba=" << PNG_COLOR_TYPE_RGBA << " palette=" << PNG_COLOR_TYPE_PALETTE << std::endl;
        return -1;
    }

    return 0;
}
Esempio n. 19
0
WL_EXPORT uint32_t *
weston_load_image(const char *filename,
		  int32_t *width_arg, int32_t *height_arg,
		  uint32_t *stride_arg)
{
	png_struct *png;
	png_info *info;
	png_byte *data;
	png_byte **row_pointers = NULL;
	png_uint_32 width, height;
	int depth, color_type, interlace, stride;
	unsigned int i;
	FILE *fp;

	fp = fopen(filename, "rb");
	if (fp == NULL)
		return NULL;

	png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
				     NULL, NULL, NULL);
	if (!png) {
		fclose(fp);
		return NULL;
	}

	info = png_create_info_struct(png);
	if (!info) {
		png_destroy_read_struct(&png, &info, NULL);
		fclose(fp);
		return NULL;
	}

	png_set_read_fn(png, fp, read_func);
	png_read_info(png, info);
	png_get_IHDR(png, info,
		     &width, &height, &depth,
		     &color_type, &interlace, NULL, NULL);

	if (color_type == PNG_COLOR_TYPE_PALETTE)
		png_set_palette_to_rgb(png);

	if (color_type == PNG_COLOR_TYPE_GRAY)
		png_set_expand_gray_1_2_4_to_8(png);

	if (png_get_valid(png, info, PNG_INFO_tRNS))
		png_set_tRNS_to_alpha(png);

	if (depth == 16)
		png_set_strip_16(png);

	if (depth < 8)
		png_set_packing(png);

	if (color_type == PNG_COLOR_TYPE_GRAY ||
	    color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
		png_set_gray_to_rgb(png);

	if (interlace != PNG_INTERLACE_NONE)
		png_set_interlace_handling(png);

	png_set_filler(png, 0xff, PNG_FILLER_AFTER);
	png_set_read_user_transform_fn(png, premultiply_data);
	png_read_update_info(png, info);
	png_get_IHDR(png, info,
		     &width, &height, &depth,
		     &color_type, &interlace, NULL, NULL);

	stride = width * 4;
	data = malloc(stride * height);
	if (!data) {
		png_destroy_read_struct(&png, &info, NULL);
		fclose(fp);
		return NULL;
	}

	row_pointers = malloc(height * sizeof row_pointers[0]);
	if (row_pointers == NULL) {
		free(data);
		png_destroy_read_struct(&png, &info, NULL);
		fclose(fp);
		return NULL;
	}

	for (i = 0; i < height; i++)
		row_pointers[i] = &data[i * stride];

	png_read_image(png, row_pointers);
	png_read_end(png, info);

	free(row_pointers);
	png_destroy_read_struct(&png, &info, NULL);
	fclose(fp);

	*width_arg = width;
	*height_arg = height;
	*stride_arg = stride;

	return (uint32_t *) data;
}
Esempio n. 20
0
static
void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scaledSize, bool *doScaledRead, float screen_gamma=0.0)
{
    if (screen_gamma != 0.0 && png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
        double file_gamma;
        png_get_gAMA(png_ptr, info_ptr, &file_gamma);
        png_set_gamma(png_ptr, screen_gamma, file_gamma);
    }

    png_uint_32 width;
    png_uint_32 height;
    int bit_depth;
    int color_type;
    png_bytep trans_alpha = 0;
    png_color_16p trans_color_p = 0;
    int num_trans;
    png_colorp palette = 0;
    int num_palette;
    int interlace_method;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_method, 0, 0);
    png_set_interlace_handling(png_ptr);

    if (color_type == PNG_COLOR_TYPE_GRAY) {
        // Black & White or 8-bit grayscale
        if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) {
            png_set_invert_mono(png_ptr);
            png_read_update_info(png_ptr, info_ptr);
            if (image.size() != QSize(width, height) || image.format() != QImage::Format_Mono) {
                image = QImage(width, height, QImage::Format_Mono);
                if (image.isNull())
                    return;
            }
            image.setColorCount(2);
            image.setColor(1, qRgb(0,0,0));
            image.setColor(0, qRgb(255,255,255));
        } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
            png_set_expand(png_ptr);
            png_set_strip_16(png_ptr);
            png_set_gray_to_rgb(png_ptr);
            if (image.size() != QSize(width, height) || image.format() != QImage::Format_ARGB32) {
                image = QImage(width, height, QImage::Format_ARGB32);
                if (image.isNull())
                    return;
            }
            if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
                png_set_swap_alpha(png_ptr);

            png_read_update_info(png_ptr, info_ptr);
        } else {
            if (bit_depth == 16)
                png_set_strip_16(png_ptr);
            else if (bit_depth < 8)
                png_set_packing(png_ptr);
            int ncols = bit_depth < 8 ? 1 << bit_depth : 256;
            png_read_update_info(png_ptr, info_ptr);
            if (image.size() != QSize(width, height) || image.format() != QImage::Format_Indexed8) {
                image = QImage(width, height, QImage::Format_Indexed8);
                if (image.isNull())
                    return;
            }
            image.setColorCount(ncols);
            for (int i=0; i<ncols; i++) {
                int c = i*255/(ncols-1);
                image.setColor(i, qRgba(c,c,c,0xff));
            }
            if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) {
                const int g = trans_color_p->gray;
                if (g < ncols) {
                    image.setColor(g, 0);
                }
            }
        }
    } else if (color_type == PNG_COLOR_TYPE_PALETTE
               && png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)
               && num_palette <= 256)
    {
        // 1-bit and 8-bit color
        if (bit_depth != 1)
            png_set_packing(png_ptr);
        png_read_update_info(png_ptr, info_ptr);
        png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
        QImage::Format format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8;
        if (image.size() != QSize(width, height) || image.format() != format) {
            image = QImage(width, height, format);
            if (image.isNull())
                return;
        }
        png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
        image.setColorCount(num_palette);
        int i = 0;
        if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) {
            while (i < num_trans) {
                image.setColor(i, qRgba(
                    palette[i].red,
                    palette[i].green,
                    palette[i].blue,
                    trans_alpha[i]
                   )
               );
                i++;
            }
        }
        while (i < num_palette) {
            image.setColor(i, qRgba(
                palette[i].red,
                palette[i].green,
                palette[i].blue,
                0xff
               )
           );
            i++;
        }
    } else {
        // 32-bit
        if (bit_depth == 16)
            png_set_strip_16(png_ptr);

        png_set_expand(png_ptr);

        if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
            png_set_gray_to_rgb(png_ptr);

        QImage::Format format = QImage::Format_ARGB32;
        // Only add filler if no alpha, or we can get 5 channel data.
        if (!(color_type & PNG_COLOR_MASK_ALPHA)
            && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
            png_set_filler(png_ptr, 0xff, QSysInfo::ByteOrder == QSysInfo::BigEndian ?
                           PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
            // We want 4 bytes, but it isn't an alpha channel
            format = QImage::Format_RGB32;
        }
        QSize outSize(width,height);
        if (!scaledSize.isEmpty() && quint32(scaledSize.width()) <= width &&
            quint32(scaledSize.height()) <= height && interlace_method == PNG_INTERLACE_NONE) {
            // Do inline downscaling
            outSize = scaledSize;
            if (doScaledRead)
                *doScaledRead = true;
        }
        if (image.size() != outSize || image.format() != format) {
            image = QImage(outSize, format);
            if (image.isNull())
                return;
        }

        if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
            png_set_swap_alpha(png_ptr);

        png_read_update_info(png_ptr, info_ptr);
    }

    // Qt==ARGB==Big(ARGB)==Little(BGRA)
    if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
        png_set_bgr(png_ptr);
    }
}
Esempio n. 21
0
pictw_t *
spng_read(session_t *ps, const char *path) {
	assert(path);

	char sig[SPNG_SIGBYTES] = "";
	pictw_t *pictw = NULL;
	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	FILE *fp = fopen(path, "rb");
	bool need_premultiply = false;
	if (unlikely(!fp)) {
		printfef("(\"%s\"): Failed to open file.", path);
		goto spng_read_end;
	}
	if (unlikely(SPNG_SIGBYTES != fread(&sig, 1, SPNG_SIGBYTES, fp))) {
		printfef("(\"%s\"): Failed to read %d-byte signature.",
				path, SPNG_SIGBYTES);
		goto spng_read_end;
	}
	if (unlikely(png_sig_cmp((png_bytep) sig, 0, SPNG_SIGBYTES))) {
		printfef("(\"%s\"): PNG signature invalid.", path);
		goto spng_read_end;
	}
	png_ptr = allocchk(png_create_read_struct(PNG_LIBPNG_VER_STRING,
				NULL, NULL, NULL));
	info_ptr = allocchk(png_create_info_struct(png_ptr));
	if (setjmp(png_jmpbuf(png_ptr)))
		goto spng_read_end;
	png_init_io(png_ptr, fp);
	png_set_sig_bytes(png_ptr, SPNG_SIGBYTES);
	png_read_info(png_ptr, info_ptr);
	png_uint_32 width = 0, height = 0;

	// Set transformations
	int bit_depth = 0, color_type = 0;
	{
		int interlace_type = 0;
		png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
				&color_type, &interlace_type, NULL, NULL);

		// Scale or strip 16-bit colors
		if (bit_depth == 16) {
			printfdf("(\"%s\"): Scaling 16-bit colors.", path);
#if PNG_LIBPNG_VER >= 10504
			png_set_scale_16(png_ptr);
#else
			png_set_strip_16(png_ptr);
#endif
			bit_depth = 8;
		}

		/* if (bit_depth < 8)
			png_set_packing(png_ptr); */

		// No idea why this is needed...
		png_set_bgr(png_ptr);

		// Convert palette to RGB
		if (color_type == PNG_COLOR_TYPE_PALETTE) {
			printfdf("(\"%s\"): Converting palette PNG to RGB.", path);
			png_set_palette_to_rgb(png_ptr);
			color_type = PNG_COLOR_TYPE_RGB;
		}

		if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
			printfdf("(\"%s\"): Converting rDNS to full alpha.", path);
			png_set_tRNS_to_alpha(png_ptr);
		}

		if (color_type == PNG_COLOR_TYPE_GRAY
				|| PNG_COLOR_TYPE_GRAY_ALPHA == color_type) {
			printfdf("(\"%s\"): Converting gray (+ alpha) PNG to RGB.", path);
			png_set_gray_to_rgb(png_ptr);
			if (PNG_COLOR_TYPE_GRAY == color_type)
				color_type = PNG_COLOR_TYPE_RGB;
			else
				color_type = PNG_COLOR_TYPE_RGB_ALPHA;
		}

		/*
		if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
			printfdf("(\"%s\"): Converting 1/2/4 bit gray PNG to 8-bit.", path);
#if PNG_LIBPNG_VER >= 10209
			png_set_expand_gray_1_2_4_to_8(png_ptr);
#else
			png_set_gray_1_2_4_to_8(png_ptr);
#endif
			bit_depth = 8;
		}
		*/

		// Somehow XImage requires 24-bit visual to use 32 bits per pixel
		if (color_type == PNG_COLOR_TYPE_RGB) {
			printfdf("(\"%s\"): Appending filler alpha values.", path);
			png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
		}

		// Premultiply alpha
		if (PNG_COLOR_TYPE_RGB_ALPHA == color_type) {
#if PNG_LIBPNG_VER >= 10504
			png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD, 1.0);
#else
			need_premultiply = true;
#endif
		}

		/*
		int number_passes = 1;
#ifdef PNG_READ_INTERLACING_SUPPORTED
		number_passes = png_set_interlace_handling(png_ptr);
#endif */

		if (PNG_INTERLACE_NONE != interlace_type)
			png_set_interlace_handling(png_ptr);
	}

	png_read_update_info(png_ptr, info_ptr);

	int depth = 0;
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
				&color_type, NULL, NULL, NULL);
	switch (color_type) {
		case PNG_COLOR_TYPE_GRAY:       depth = 1 * bit_depth; break;
		case PNG_COLOR_TYPE_RGB:        depth = 3 * bit_depth; break;
		case PNG_COLOR_TYPE_RGB_ALPHA:  depth = 4 * bit_depth; break;
		default:                        assert(0); break;
	}

	// Read data and fill to Picture
	{
		int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
		png_bytep row_pointers[height];
		memset(row_pointers, 0, sizeof(row_pointers));
		row_pointers[0] = png_malloc(png_ptr, rowbytes * height);
		for (int row = 1; row < height; row++)
			row_pointers[row] = row_pointers[row - 1] + rowbytes;
		png_read_image(png_ptr, row_pointers);
		if (need_premultiply)
			for (int row = 0; row < height; row++)
				simg_data32_premultiply(row_pointers[row], width);
		if (unlikely(!(pictw = simg_data_to_pictw(ps, width, height, depth,
							row_pointers[0], rowbytes)))) {
			printfef("(\"%s\"): Failed to create Picture.", path);
			goto spng_read_end;
		}
	}

spng_read_end:
	if (png_ptr)
		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
	if (fp)
		fclose(fp);

	return pictw;
}
Esempio n. 22
0
void load_png_buffer(std::string filename, buffer_t &buf) {
	png_byte header[8];
	png_structp png_ptr;
	png_infop info_ptr;
	png_bytep *row_pointers;

	/* open file and test for it being a png */
	FILE *f = fopen(filename.c_str(), "rb");
	_assert(f, "File %s could not be opened for reading\n", filename.c_str());
	_assert(fread(header, 1, 8, f) == 8, "File ended before end of header\n");
	_assert(!png_sig_cmp(header, 0, 8), "File %s is not recognized as a PNG file\n", filename.c_str());

	/* initialize stuff */
	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

	_assert(png_ptr, "png_create_read_struct failed\n");

	info_ptr = png_create_info_struct(png_ptr);
	_assert(info_ptr, "png_create_info_struct failed\n");

	_assert(!setjmp(png_jmpbuf(png_ptr)), "Error during init_io\n");

	png_init_io(png_ptr, f);
	png_set_sig_bytes(png_ptr, 8);

	png_read_info(png_ptr, info_ptr);

	int width = png_get_image_width(png_ptr, info_ptr);
	int height = png_get_image_height(png_ptr, info_ptr);
	int channels = png_get_channels(png_ptr, info_ptr);
	int bit_depth = png_get_bit_depth(png_ptr, info_ptr);

	// Expand low-bpp images to have only 1 pixel per byte (As opposed to tight packing)
	if (bit_depth < 8) {
		png_set_packing(png_ptr);
	}

	if (channels != 1) {
		buf.extent[0] = width;
		buf.extent[1] = height;
		buf.extent[2] = channels;

		buf.stride[0] = 1;
		buf.stride[1] = width;
		buf.stride[2] = width*height;
	} else {
		buf.extent[0] = width;
		buf.extent[1] = height;

		buf.stride[0] = 1;
		buf.stride[1] = width;
	}

	if (bit_depth == 8) {
		buf.elem_size = 1;
	} else {
		buf.elem_size = 2;
	}

	png_set_interlace_handling(png_ptr);
	png_read_update_info(png_ptr, info_ptr);

	// read the file
	_assert(!setjmp(png_jmpbuf(png_ptr)), "Error during read_image\n");

	row_pointers = new png_bytep[height];
	for (int y = 0; y < height; y++) {
		row_pointers[y] = new png_byte[png_get_rowbytes(png_ptr, info_ptr)];
	}

	png_read_image(png_ptr, row_pointers);

	fclose(f);

	_assert((bit_depth == 8) || (bit_depth == 16), "Can only handle 8-bit or 16-bit pngs\n");

	// convert the data to uint8_t

	int c_stride = (channels == 1) ? 0 : width*height;
	uint8_t *img = (uint8_t*)malloc(width*height*channels*sizeof(uint8_t));
	uint8_t *ptr = img;
	_assert(ptr, "Error alocation memory for buffer.");
	if (bit_depth == 8) {
		for (int y = 0; y < height; y++) {
			uint8_t *srcPtr = (uint8_t *)(row_pointers[y]);
			for (int x = 0; x < width;x++) {
				for (int c = 0; c < channels; c++) {
					convert(*srcPtr++, ptr[c*c_stride]);
				}
				ptr++;
			}
		}
	} else if (bit_depth == 16) {
		for (int y = 0; y < height; y++) {
			uint8_t *srcPtr = (uint8_t *)(row_pointers[y]);
			for (int x = 0; x < width; x++) {
				for (int c = 0; c < channels; c++) {
					uint16_t hi = (*srcPtr++) << 8;
					uint16_t lo = hi | (*srcPtr++);
					convert(lo, ptr[c*c_stride]);
				}
				ptr++;
			}
		}
	}

	// Fill buffer_t
	buf.host = img;

	// clean up
	for (int y = 0; y < height; y++) {
		delete[] row_pointers[y];
	}
	delete[] row_pointers;

	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

	buf.host_dirty = true;
}
Esempio n. 23
0
static BOOL DLL_CALLCONV
Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
	png_structp png_ptr;
	png_infop info_ptr;
	png_colorp palette = NULL;
	png_uint_32 width, height;
	BOOL has_alpha_channel = FALSE;

	RGBQUAD *pal;					// pointer to dib palette
	int bit_depth, pixel_depth;		// pixel_depth = bit_depth * channels
	int palette_entries;
	int	interlace_type;

	fi_ioStructure fio;
    fio.s_handle = handle;
	fio.s_io = io;

	if ((dib) && (handle)) {
		try {
			// create the chunk manage structure

			png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, error_handler, warning_handler);

			if (!png_ptr)  {
				return FALSE;
			}

			// allocate/initialize the image information data.

			info_ptr = png_create_info_struct(png_ptr);

			if (!info_ptr)  {
				png_destroy_write_struct(&png_ptr,  (png_infopp)NULL);
				return FALSE;
			}

			// Set error handling.  REQUIRED if you aren't supplying your own
			// error handling functions in the png_create_write_struct() call.

			if (setjmp(png_jmpbuf(png_ptr)))  {
				// if we get here, we had a problem reading the file

				png_destroy_write_struct(&png_ptr, &info_ptr);

				return FALSE;
			}

			// init the IO
            
			png_set_write_fn(png_ptr, &fio, _WriteProc, _FlushProc);

			// set physical resolution

			png_uint_32 res_x = (png_uint_32)FreeImage_GetDotsPerMeterX(dib);
			png_uint_32 res_y = (png_uint_32)FreeImage_GetDotsPerMeterY(dib);

			if ((res_x > 0) && (res_y > 0))  {
				png_set_pHYs(png_ptr, info_ptr, res_x, res_y, 1);
			}
	
			// Set the image information here.  Width and height are up to 2^31,
			// bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
			// the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
			// PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
			// or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
			// PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
			// currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED

			width = FreeImage_GetWidth(dib);
			height = FreeImage_GetHeight(dib);
			pixel_depth = FreeImage_GetBPP(dib);

			BOOL bInterlaced = FALSE;
			if( (flags & PNG_INTERLACED) == PNG_INTERLACED) {
				interlace_type = PNG_INTERLACE_ADAM7;
				bInterlaced = TRUE;
			} else {
				interlace_type = PNG_INTERLACE_NONE;
			}

			// set the ZLIB compression level or default to PNG default compression level (ZLIB level = 6)
			int zlib_level = flags & 0x0F;
			if((zlib_level >= 1) && (zlib_level <= 9)) {
				png_set_compression_level(png_ptr, zlib_level);
			} else if((flags & PNG_Z_NO_COMPRESSION) == PNG_Z_NO_COMPRESSION) {
				png_set_compression_level(png_ptr, Z_NO_COMPRESSION);
			}

			// filtered strategy works better for high color images
			if(pixel_depth >= 16){
				png_set_compression_strategy(png_ptr, Z_FILTERED);
				png_set_filter(png_ptr, 0, PNG_FILTER_NONE|PNG_FILTER_SUB|PNG_FILTER_PAETH);
			} else {
				png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
			}

			FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
			if(image_type == FIT_BITMAP) {
				// standard image type
				bit_depth = (pixel_depth > 8) ? 8 : pixel_depth;
			} else {
				// 16-bit greyscale or 16-bit RGB(A)
				bit_depth = 16;
			}

			switch (FreeImage_GetColorType(dib)) {
				case FIC_MINISWHITE:
					// Invert monochrome files to have 0 as black and 1 as white (no break here)
					png_set_invert_mono(png_ptr);

				case FIC_MINISBLACK:
					png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, 
						PNG_COLOR_TYPE_GRAY, interlace_type, 
						PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

					break;

				case FIC_PALETTE:
				{
					png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, 
						PNG_COLOR_TYPE_PALETTE, interlace_type, 
						PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

					// set the palette

					palette_entries = 1 << bit_depth;
					palette = (png_colorp)png_malloc(png_ptr, palette_entries * sizeof (png_color));
					pal = FreeImage_GetPalette(dib);

					for (int i = 0; i < palette_entries; i++) {
						palette[i].red   = pal[i].rgbRed;
						palette[i].green = pal[i].rgbGreen;
						palette[i].blue  = pal[i].rgbBlue;
					}
					
					png_set_PLTE(png_ptr, info_ptr, palette, palette_entries);

					// You must not free palette here, because png_set_PLTE only makes a link to
					// the palette that you malloced.  Wait until you are about to destroy
					// the png structure.

					break;
				}

				case FIC_RGBALPHA :
					has_alpha_channel = TRUE;

					png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, 
						PNG_COLOR_TYPE_RGBA, interlace_type, 
						PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
					// flip BGR pixels to RGB
					if(image_type == FIT_BITMAP)
						png_set_bgr(png_ptr);
#endif
					break;
	
				case FIC_RGB:
					png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, 
						PNG_COLOR_TYPE_RGB, interlace_type, 
						PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
					// flip BGR pixels to RGB
					if(image_type == FIT_BITMAP)
						png_set_bgr(png_ptr);
#endif
					break;
					
				case FIC_CMYK:
					break;
			}

			// write possible ICC profile

			FIICCPROFILE *iccProfile = FreeImage_GetICCProfile(dib);
			if (iccProfile->size && iccProfile->data) {
				png_set_iCCP(png_ptr, info_ptr, "Embedded Profile", 0, (png_charp)iccProfile->data, iccProfile->size);
			}

			// write metadata

			WriteMetadata(png_ptr, info_ptr, dib);

			// Optional gamma chunk is strongly suggested if you have any guess
			// as to the correct gamma of the image.
			// png_set_gAMA(png_ptr, info_ptr, gamma);

			// set the transparency table

			if ((pixel_depth == 8) && (FreeImage_IsTransparent(dib)) && (FreeImage_GetTransparencyCount(dib) > 0)) {
				png_set_tRNS(png_ptr, info_ptr, FreeImage_GetTransparencyTable(dib), FreeImage_GetTransparencyCount(dib), NULL);
			}

			// set the background color

			if(FreeImage_HasBackgroundColor(dib)) {
				png_color_16 image_background;
				RGBQUAD rgbBkColor;

				FreeImage_GetBackgroundColor(dib, &rgbBkColor);
				memset(&image_background, 0, sizeof(png_color_16));
				image_background.blue  = rgbBkColor.rgbBlue;
				image_background.green = rgbBkColor.rgbGreen;
				image_background.red   = rgbBkColor.rgbRed;
				image_background.index = rgbBkColor.rgbReserved;

				png_set_bKGD(png_ptr, info_ptr, &image_background);
			}
			
			// Write the file header information.

			png_write_info(png_ptr, info_ptr);

			// write out the image data

#ifndef FREEIMAGE_BIGENDIAN
			if (bit_depth == 16) {
				// turn on 16 bit byte swapping
				png_set_swap(png_ptr);
			}
#endif

			int number_passes = 1;
			if (bInterlaced) {
				number_passes = png_set_interlace_handling(png_ptr);
			}

			if ((pixel_depth == 32) && (!has_alpha_channel)) {
				BYTE *buffer = (BYTE *)malloc(width * 3);

				// transparent conversion to 24-bit
				// the number of passes is either 1 for non-interlaced images, or 7 for interlaced images
				for (int pass = 0; pass < number_passes; pass++) {
					for (png_uint_32 k = 0; k < height; k++) {
						FreeImage_ConvertLine32To24(buffer, FreeImage_GetScanLine(dib, height - k - 1), width);			
						png_write_row(png_ptr, buffer);
					}
				}
				free(buffer);
			} else {
				// the number of passes is either 1 for non-interlaced images, or 7 for interlaced images
				for (int pass = 0; pass < number_passes; pass++) {
					for (png_uint_32 k = 0; k < height; k++) {			
						png_write_row(png_ptr, FreeImage_GetScanLine(dib, height - k - 1));					
					}
				}
			}

			// It is REQUIRED to call this to finish writing the rest of the file
			// Bug with png_flush

			png_write_end(png_ptr, info_ptr);

			// clean up after the write, and free any memory allocated
			if (palette) {
				png_free(png_ptr, palette);
			}

			png_destroy_write_struct(&png_ptr, &info_ptr);

			return TRUE;
		} catch (const char *text) {
			FreeImage_OutputMessageProc(s_format_id, text);
		}
	}

	return FALSE;
}
Esempio n. 24
0
    void initialize()
    {
        // Now it's time for some transformations.

        if( little_endian() )
        {
            if( this->_info._bit_depth == 16 )
            {
                // Swap bytes of 16 bit files to least significant byte first.
                png_set_swap( this->get()->_struct );
            }

            if( this->_info._bit_depth < 8 )
            {
                // swap bits of 1, 2, 4 bit packed pixel formats
                png_set_packswap( this->get()->_struct );
            }
        }

        if( this->_info._color_type == PNG_COLOR_TYPE_PALETTE )
        {
            png_set_palette_to_rgb( this->get()->_struct );
        }

        if( this->_info._num_trans > 0 )
        {
            png_set_tRNS_to_alpha( this->get()->_struct );
        }

        // Tell libpng to handle the gamma conversion for you.  The final call
        // is a good guess for PC generated images, but it should be configurable
        // by the user at run time by the user.  It is strongly suggested that
        // your application support gamma correction.
        if( this->_settings._apply_screen_gamma )
        {
            // png_set_gamma will change the image data!

#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
        png_set_gamma( this->get()->_struct
                     , this->_settings._screen_gamma
                     , this->_info._file_gamma
                     );
#else
        png_set_gamma( this->get()->_struct
                     , this->_settings._screen_gamma
                     , this->_info._file_gamma
                     );
#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
        }

        // Interlaced images are not supported.
        this->_number_passes = png_set_interlace_handling( this->get()->_struct );
        io_error_if( this->_number_passes != 1
                   , "scanline_read_iterator cannot read interlaced png images."
                   );


        // The above transformation might have changed the bit_depth and color type.
        png_read_update_info( this->get()->_struct
                            , this->get()->_info
                            );

        this->_info._bit_depth = png_get_bit_depth( this->get()->_struct
                                                  , this->get()->_info
                                                  );

        this->_info._num_channels = png_get_channels( this->get()->_struct
                                                    , this->get()->_info
                                                    );

        this->_info._color_type = png_get_color_type( this->get()->_struct
                                                    , this->get()->_info
                                                    );

        this->_scanline_length = png_get_rowbytes( this->get()->_struct
                                                 , this->get()->_info
                                                 );
    }
Esempio n. 25
0
s32 pngDecSetParameter(PStream stream, PInParam in_param, POutParam out_param, PExtInParam extra_in_param = vm::null, PExtOutParam extra_out_param = vm::null)
{
	if (in_param->outputPackFlag == CELL_PNGDEC_1BYTE_PER_NPIXEL)
	{
		fmt::throw_exception("Packing not supported! (%d)" HERE, in_param->outputPackFlag);
	}

	// flag to keep unknown chunks
	png_set_keep_unknown_chunks(stream->png_ptr, PNG_HANDLE_CHUNK_IF_SAFE, 0, 0);

	// Scale 16 bit depth down to 8 bit depth.
	if (stream->info.bitDepth == 16 && in_param->outputBitDepth == 8)
	{
		// PS3 uses png_set_strip_16, since png_set_scale_16 wasn't available back then.
		png_set_strip_16(stream->png_ptr);
	}

	// This shouldnt ever happen, but not sure what to do if it does, just want it logged for now
	if (stream->info.bitDepth != 16 && in_param->outputBitDepth == 16)
		cellPngDec.error("Output depth of 16 with non input depth of 16 specified!");
	if (in_param->commandPtr != vm::null)
		cellPngDec.warning("Ignoring CommandPtr.");

	if (stream->info.colorSpace != in_param->outputColorSpace)
	{
		// check if we need to set alpha
		const bool inputHasAlpha = cellPngColorSpaceHasAlpha(stream->info.colorSpace);
		const bool outputWantsAlpha = cellPngColorSpaceHasAlpha(in_param->outputColorSpace);

		if (outputWantsAlpha && !inputHasAlpha)
		{
			if (in_param->outputAlphaSelect == CELL_PNGDEC_FIX_ALPHA)
				png_set_add_alpha(stream->png_ptr, in_param->outputColorAlpha, in_param->outputColorSpace == CELL_PNGDEC_ARGB ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
			else
			{
				// Check if we can steal the alpha from a trns block
				if (png_get_valid(stream->png_ptr, stream->info_ptr, PNG_INFO_tRNS))
					png_set_tRNS_to_alpha(stream->png_ptr);
				// if not, just set default of 0xff
				else
					png_set_add_alpha(stream->png_ptr, 0xff, in_param->outputColorSpace == CELL_PNGDEC_ARGB ? PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
			}
		}
		else if (inputHasAlpha && !outputWantsAlpha)
			png_set_strip_alpha(stream->png_ptr);
		else if (in_param->outputColorSpace == CELL_PNGDEC_ARGB && stream->info.colorSpace == CELL_PNGDEC_RGBA)
			png_set_swap_alpha(stream->png_ptr);

		// Handle gray<->rgb colorspace conversions
		// rgb output
		if (in_param->outputColorSpace == CELL_PNGDEC_ARGB
			|| in_param->outputColorSpace == CELL_PNGDEC_RGBA
			|| in_param->outputColorSpace == CELL_PNGDEC_RGB)
		{

			if (stream->info.colorSpace == CELL_PNGDEC_PALETTE)
				png_set_palette_to_rgb(stream->png_ptr);
			if ((stream->info.colorSpace == CELL_PNGDEC_GRAYSCALE || stream->info.colorSpace == CELL_PNGDEC_GRAYSCALE_ALPHA)
				&& stream->info.bitDepth < 8)
				png_set_expand_gray_1_2_4_to_8(stream->png_ptr);
		}
		// grayscale output
		else
		{
			if (stream->info.colorSpace == CELL_PNGDEC_ARGB
				|| stream->info.colorSpace == CELL_PNGDEC_RGBA
				|| stream->info.colorSpace == CELL_PNGDEC_RGB)
			{

				png_set_rgb_to_gray(stream->png_ptr, PNG_ERROR_ACTION_NONE, PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT);
			}
			else {
				// not sure what to do here
				cellPngDec.error("Grayscale / Palette to Grayscale / Palette conversion currently unsupported.");
			}
		}
	}

	stream->passes = png_set_interlace_handling(stream->png_ptr);

	// Update the info structure
	png_read_update_info(stream->png_ptr, stream->info_ptr);

	stream->out_param.outputWidth = stream->info.imageWidth;
	stream->out_param.outputHeight = stream->info.imageHeight;
	stream->out_param.outputBitDepth = in_param->outputBitDepth;
	stream->out_param.outputColorSpace = in_param->outputColorSpace;
	stream->out_param.outputMode = in_param->outputMode;

	stream->out_param.outputWidthByte = png_get_rowbytes(stream->png_ptr, stream->info_ptr);
	stream->out_param.outputComponents = png_get_channels(stream->png_ptr, stream->info_ptr);

	stream->packing = in_param->outputPackFlag;

	// Set the memory usage. We currently don't actually allocate memory for libpng through the callbacks, due to libpng needing a lot more memory compared to PS3 variant.
	stream->out_param.useMemorySpace = 0;

	if (extra_in_param)
	{
		if (extra_in_param->bufferMode != CELL_PNGDEC_LINE_MODE)
		{
			cellPngDec.error("Invalid Buffermode specified.");
			return CELL_PNGDEC_ERROR_ARG;
		}

		if (stream->passes > 1)
		{
			stream->outputCounts = 1;
		}
		else
			stream->outputCounts = extra_in_param->outputCounts;

		if (extra_out_param)
		{
			if (stream->outputCounts == 0)
				extra_out_param->outputHeight = stream->out_param.outputHeight;
			else
				extra_out_param->outputHeight = std::min(stream->outputCounts, stream->out_param.outputHeight.value());
			extra_out_param->outputWidthByte = stream->out_param.outputWidthByte;
		}
	}

	*out_param = stream->out_param;

	return CELL_OK;
}
Esempio n. 26
0
void png_reader::read(unsigned x0, unsigned y0,image_data_32& image)
{
    FILE *fp=fopen(fileName_.c_str(),"rb");
    if (!fp) throw image_reader_exception("cannot open image file "+fileName_);

    png_structp png_ptr = png_create_read_struct
        (PNG_LIBPNG_VER_STRING,0,0,0);

    if (!png_ptr)
    {
        fclose(fp);
        throw image_reader_exception("failed to allocate png_ptr");
    }

    // catch errors in a custom way to avoid the need for setjmp
    png_set_error_fn(png_ptr, png_get_error_ptr(png_ptr), user_error_fn, user_warning_fn);

    png_infop info_ptr;
    try
    {
        info_ptr = png_create_info_struct(png_ptr);
        if (!info_ptr)
        {
            png_destroy_read_struct(&png_ptr,0,0);
            fclose(fp);
            throw image_reader_exception("failed to create info_ptr");
        }
    }
    catch (std::exception const& ex)
    {
        png_destroy_read_struct(&png_ptr,0,0);
        fclose(fp);
        throw;
    }

    png_set_read_fn(png_ptr, (png_voidp)fp, png_read_data);
    png_read_info(png_ptr, info_ptr);

    if (color_type_ == PNG_COLOR_TYPE_PALETTE)
        png_set_expand(png_ptr);
    if (color_type_ == PNG_COLOR_TYPE_GRAY && bit_depth_ < 8)
        png_set_expand(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
        png_set_expand(png_ptr);
    if (bit_depth_ == 16)
        png_set_strip_16(png_ptr);
    if (color_type_ == PNG_COLOR_TYPE_GRAY ||
        color_type_ == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);

    // quick hack -- only work in >=libpng 1.2.7
    png_set_add_alpha(png_ptr,0xff,PNG_FILLER_AFTER); //rgba

    double gamma;
    if (png_get_gAMA(png_ptr, info_ptr, &gamma))
        png_set_gamma(png_ptr, 2.2, gamma);

    if (x0 == 0 && y0 == 0 && image.width() >= width_ && image.height() >= height_)
    {

        if (png_get_interlace_type(png_ptr,info_ptr) == PNG_INTERLACE_ADAM7)
        {
            png_set_interlace_handling(png_ptr); // FIXME: libpng bug?
            // according to docs png_read_image
            // "..automatically handles interlacing,
            // so you don't need to call png_set_interlace_handling()"
        }
        png_read_update_info(png_ptr, info_ptr);
        // we can read whole image at once
        // alloc row pointers
        boost::scoped_array<png_byte*> rows(new png_bytep[height_]);
        for (unsigned i=0; i<height_; ++i)
            rows[i] = (png_bytep)image.getRow(i);
        png_read_image(png_ptr, rows.get());
    }
    else
    {
        png_read_update_info(png_ptr, info_ptr);
        unsigned w=std::min(unsigned(image.width()),width_);
        unsigned h=std::min(unsigned(image.height()),height_);
        unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr);
        boost::scoped_array<png_byte> row(new png_byte[rowbytes]);
        //START read image rows
        for (unsigned i=0;i<height_;++i)
        {
            png_read_row(png_ptr,row.get(),0);
            if (i>=y0 && i<h)
            {
                image.setRow(i-y0,reinterpret_cast<unsigned*>(&row[x0]),w);
            }
        }
        //END
    }

    png_read_end(png_ptr,0);
    png_destroy_read_struct(&png_ptr, &info_ptr,0);
    fclose(fp);
}
Esempio n. 27
0
pngquant_error rwpng_read_image24_libpng(struct rwpng_data * read_data, png24_image *mainprog_ptr)
{
    png_structp  png_ptr = NULL;
    png_infop    info_ptr = NULL;
    png_size_t   rowbytes;
    int          color_type, bit_depth;

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr,
      rwpng_error_handler, NULL);
    if (!png_ptr) {
        return PNG_OUT_OF_MEMORY_ERROR;   /* out of memory */
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return PNG_OUT_OF_MEMORY_ERROR;   /* out of memory */
    }

    /* setjmp() must be called in every function that calls a non-trivial
     * libpng function */

    if (setjmp(mainprog_ptr->jmpbuf)) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return LIBPNG_FATAL_ERROR;   /* fatal libpng error (via longjmp()) */
    }

    //struct rwpng_data read_data = {infile, 0,};
    png_set_read_fn(png_ptr, read_data, user_read_data);

    png_read_info(png_ptr, info_ptr);  /* read all PNG info up to image data */


    /* alternatively, could make separate calls to png_get_image_width(),
     * etc., but want bit_depth and color_type for later [don't care about
     * compression_type and filter_type => NULLs] */

    png_get_IHDR(png_ptr, info_ptr, &mainprog_ptr->width, &mainprog_ptr->height,
      &bit_depth, &color_type, NULL, NULL, NULL);


    /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits,
     * transparency chunks to full alpha channel; strip 16-bit-per-sample
     * images to 8 bits per sample; and convert grayscale to RGB[A] */

    /* GRR TO DO:  preserve all safe-to-copy ancillary PNG chunks */

    if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
#ifdef PNG_READ_FILLER_SUPPORTED
        /* GRP:  expand palette to RGB, and grayscale or RGB to GA or RGBA */
        if (color_type == PNG_COLOR_TYPE_PALETTE)
            png_set_expand(png_ptr);
        png_set_filler(png_ptr, 65535L, PNG_FILLER_AFTER);
#else
        fprintf(stderr, "pngquant readpng:  image is neither RGBA nor GA\n");
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        mainprog_ptr->retval = 26;
        return mainprog_ptr->retval;
#endif
    }
/*
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
        png_set_expand(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
        png_set_expand(png_ptr);
 */
    if (bit_depth == 16)
        png_set_strip_16(png_ptr);

    if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);


    /* get and save the gamma info (if any) for writing */

    double gamma;
    mainprog_ptr->gamma = png_get_gAMA(png_ptr, info_ptr, &gamma) ? gamma : 0.45455;

    png_set_interlace_handling(png_ptr);

    /* all transformations have been registered; now update info_ptr data,
     * get rowbytes and channels, and allocate image memory */

    png_read_update_info(png_ptr, info_ptr);

    rowbytes = png_get_rowbytes(png_ptr, info_ptr);

    if ((mainprog_ptr->rgba_data = malloc(rowbytes*mainprog_ptr->height)) == NULL) {
        fprintf(stderr, "pngquant readpng:  unable to allocate image data\n");
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return PNG_OUT_OF_MEMORY_ERROR;
    }

    png_bytepp row_pointers = rwpng_create_row_pointers(info_ptr, png_ptr, mainprog_ptr->rgba_data, mainprog_ptr->height, 0);

    /* now we can go ahead and just read the whole image */

    png_read_image(png_ptr, row_pointers);

    /* and we're done!  (png_read_end() can be omitted if no processing of
     * post-IDAT text/time/etc. is desired) */

    png_read_end(png_ptr, NULL);

    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    mainprog_ptr->file_size = read_data->bytes_read;
    mainprog_ptr->row_pointers = (unsigned char **)row_pointers;

    return SUCCESS;
}
Esempio n. 28
0
/** 
Reads one PNG file. 
@param process Process the image data (0 for initial parameter determination)
@returns -1 on failure, 1 on sucess
*/
int decode_png(const char *pngname, int process, parameters_t *param)
{
  int num_pass = 1;
  int bit_depth, color_type;
  FILE *pngfile;
  //png_byte hdptr[8];

  /* Now open this PNG file, and examine its header to retrieve the 
     YUV4MPEG info that shall be written */
  pngfile = fopen(pngname, "rb");
  if (!pngfile)
    {
      perror("PNG file open failed:");
      return -1;
    }

  //fread(hdptr, 1, 8, pngfile);

#if 0 
  bool is_png = !png_sig_cmp(hdptr, 0, 8);
  if (!is_png)
    {
      mjpeg_error("%s is _no_ PNG file !\n");
      return -1;
    }
#endif
  
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if (!png_ptr)
    mjpeg_error_exit1("%s: Could not allocate PNG read struct !", pngname);
  
  png_init_io(png_ptr, pngfile);
  //png_set_sig_bytes(png_ptr, 8);
  
  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
    {
      png_destroy_read_struct(&png_ptr,
			      (png_infopp)NULL, (png_infopp)NULL);
      mjpeg_error_exit1("%s: Could not allocate PNG info struct !", pngname);
    }
  
  end_info = png_create_info_struct(png_ptr);
  if (!end_info)
    {
      png_destroy_read_struct(&png_ptr, &info_ptr,
			      (png_infopp)NULL);
      mjpeg_error_exit1("%s: Could not allocate PNG end info struct !", pngname);
    }
  
  if (setjmp(png_jmpbuf(png_ptr)))
    {
      png_destroy_read_struct(&png_ptr, &info_ptr,
			      &end_info);
      mjpeg_error("%s: Corrupted PNG file !", pngname);
      return -1;
    }
  
  if (process)
    png_set_read_user_transform_fn(png_ptr, png_separation);
  png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_STRIP_ALPHA, NULL);
  
  if (png_get_IHDR(png_ptr, info_ptr, &param->width, &param->height, &bit_depth,
		       //   &color_type, &interlace_type, &compression_type, &filter_type))
		   &color_type, NULL, NULL, NULL))	
    num_pass = png_set_interlace_handling(png_ptr);
  else
    mjpeg_error_exit1("PNG header reading failed !!\n");
#if 0 
  mjpeg_info("Reading info struct...\n");
  png_read_info(png_ptr, info_ptr);
  mjpeg_info("Done...\n");
  
  if (png_get_IHDR(png_ptr, info_ptr, &param->width, &param->height, &bit_depth,
		       //   &color_type, &interlace_type, &compression_type, &filter_type))
		   &color_type, NULL, NULL, NULL))	
    num_pass = png_set_interlace_handling(png_ptr);
  else
    mjpeg_error_exit1("PNG header reading failed !!\n");
  
  if (process)
    {
      printf("%d passes needed\n\n", num_pass);
      
      if (bit_depth != 8 && bit_depth != 16)
	{
	  mjpeg_error_exit1("Invalid bit_depth %d, only 8 and 16 bit allowed !!\n", bit_depth);
	}
      
      png_set_strip_16(png_ptr); // always has to strip the 16bit input, MPEG can't handle it	  
      png_set_strip_alpha(png_ptr); // Alpha can't be processed until Z/Alpha is integrated
      
      printf("\nAllocating row buffer...");
      png_set_read_user_transform_fn(png_ptr, png_separation);
      png_bytep row_buf = (png_bytep)png_malloc(png_ptr,
						png_get_rowbytes(png_ptr, info_ptr));
      
      for (int n=0; n < num_pass; n++)
	for (int y=0; y < sh_param->height; y++)
	  {
	    printf("Writing row data for pass %d\n", n);
	    png_read_rows(png_ptr, (png_bytepp)&row_buf, NULL, 1);
	  }
      
      png_free(png_ptr, row_buf);	      
    }
  png_read_end(png_ptr, info_ptr);
#endif  
  if (setjmp(png_ptr->jmpbuf)) {
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
    return 2;
    }

  fclose(pngfile);

  return 1;
}
Esempio n. 29
0
PyObject*
_png_module::_read_png(const Py::Object& py_fileobj, const bool float_result)
{
    png_byte header[8];   // 8 is the maximum size that can be checked
    FILE* fp = NULL;
    bool close_file = false;

#if PY3K
    int fd = PyObject_AsFileDescriptor(py_fileobj.ptr());
    PyErr_Clear();
#endif

    if (py_fileobj.isString())
    {
        std::string fileName = Py::String(py_fileobj);
        const char *file_name = fileName.c_str();
        if ((fp = fopen(file_name, "rb")) == NULL)
        {
            throw Py::RuntimeError(
                Printf("Could not open file %s for reading", file_name).str());
        }
        close_file = true;
    }
#if PY3K
    else if (fd != -1) {
        fp = fdopen(fd, "r");
    }
#else
    else if (PyFile_CheckExact(py_fileobj.ptr()))
    {
        fp = PyFile_AsFile(py_fileobj.ptr());
    }
#endif
    else
    {
        PyObject* read_method = PyObject_GetAttrString(py_fileobj.ptr(), "read");
        if (!(read_method && PyCallable_Check(read_method)))
        {
            Py_XDECREF(read_method);
            throw Py::TypeError("Object does not appear to be a 8-bit string path or a Python file-like object");
        }
        Py_XDECREF(read_method);
    }

    if (fp)
    {
        if (fread(header, 1, 8, fp) != 8)
        {
            throw Py::RuntimeError(
                "_image_module::readpng: error reading PNG header");
        }
    }
    else
    {
        _read_png_data(py_fileobj.ptr(), header, 8);
    }
    if (png_sig_cmp(header, 0, 8))
    {
        throw Py::RuntimeError(
            "_image_module::readpng: file not recognized as a PNG file");
    }

    /* initialize stuff */
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

    if (!png_ptr)
    {
        throw Py::RuntimeError(
            "_image_module::readpng:  png_create_read_struct failed");
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr)
    {
        throw Py::RuntimeError(
            "_image_module::readpng:  png_create_info_struct failed");
    }

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        throw Py::RuntimeError(
            "_image_module::readpng:  error during init_io");
    }

    if (fp)
    {
        png_init_io(png_ptr, fp);
    }
    else
    {
        png_set_read_fn(png_ptr, (void*)py_fileobj.ptr(), &read_png_data);
    }
    png_set_sig_bytes(png_ptr, 8);
    png_read_info(png_ptr, info_ptr);

    png_uint_32 width = png_get_image_width(png_ptr, info_ptr);
    png_uint_32 height = png_get_image_height(png_ptr, info_ptr);

    int bit_depth = png_get_bit_depth(png_ptr, info_ptr);

    // Unpack 1, 2, and 4-bit images
    if (bit_depth < 8)
        png_set_packing(png_ptr);

    // If sig bits are set, shift data
    png_color_8p sig_bit;
    if ((png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE) &&
        png_get_sBIT(png_ptr, info_ptr, &sig_bit))
    {
        png_set_shift(png_ptr, sig_bit);
    }

    // Convert big endian to little
    if (bit_depth == 16)
    {
        png_set_swap(png_ptr);
    }

    // Convert palletes to full RGB
    if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE)
    {
        png_set_palette_to_rgb(png_ptr);
    }

    // If there's an alpha channel convert gray to RGB
    if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY_ALPHA)
    {
        png_set_gray_to_rgb(png_ptr);
    }

    png_set_interlace_handling(png_ptr);
    png_read_update_info(png_ptr, info_ptr);

    /* read file */
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        throw Py::RuntimeError(
            "_image_module::readpng: error during read_image");
    }

    png_bytep *row_pointers = new png_bytep[height];
    png_uint_32 row;

    for (row = 0; row < height; row++)
    {
        row_pointers[row] = new png_byte[png_get_rowbytes(png_ptr,info_ptr)];
    }

    png_read_image(png_ptr, row_pointers);

    npy_intp dimensions[3];
    dimensions[0] = height;  //numrows
    dimensions[1] = width;   //numcols
    if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_ALPHA)
    {
        dimensions[2] = 4;     //RGBA images
    }
    else if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_COLOR)
    {
        dimensions[2] = 3;     //RGB images
    }
    else
    {
        dimensions[2] = 1;     //Greyscale images
    }
    //For gray, return an x by y array, not an x by y by 1
    int num_dims  = (png_get_color_type(png_ptr, info_ptr)
                                & PNG_COLOR_MASK_COLOR) ? 3 : 2;

    PyArrayObject *A = NULL;
    if (float_result) {
        double max_value = (1 << ((bit_depth < 8) ? 8 : bit_depth)) - 1;

        A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_FLOAT);

        if (A == NULL)
        {
            throw Py::MemoryError("Could not allocate image array");
        }

        for (png_uint_32 y = 0; y < height; y++)
        {
            png_byte* row = row_pointers[y];
            for (png_uint_32 x = 0; x < width; x++)
            {
                size_t offset = y * A->strides[0] + x * A->strides[1];
                if (bit_depth == 16)
                {
                    png_uint_16* ptr = &reinterpret_cast<png_uint_16*>(row)[x * dimensions[2]];
                    for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                    {
                        *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
                    }
                }
                else
                {
                    png_byte* ptr = &(row[x * dimensions[2]]);
                    for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                    {
                        *(float*)(A->data + offset + p*A->strides[2]) = (float)(ptr[p]) / max_value;
                    }
                }
            }
        }
    } else {
        A = (PyArrayObject *) PyArray_SimpleNew(num_dims, dimensions, NPY_UBYTE);

        if (A == NULL)
        {
            throw Py::MemoryError("Could not allocate image array");
        }

        for (png_uint_32 y = 0; y < height; y++)
        {
            png_byte* row = row_pointers[y];
            for (png_uint_32 x = 0; x < width; x++)
            {
                size_t offset = y * A->strides[0] + x * A->strides[1];
                if (bit_depth == 16)
                {
                    png_uint_16* ptr = &reinterpret_cast<png_uint_16*>(row)[x * dimensions[2]];
                    for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                    {
                        *(png_byte*)(A->data + offset + p*A->strides[2]) = ptr[p] >> 8;
                    }
                }
                else
                {
                    png_byte* ptr = &(row[x * dimensions[2]]);
                    for (png_uint_32 p = 0; p < (png_uint_32)dimensions[2]; p++)
                    {
                        *(png_byte*)(A->data + offset + p*A->strides[2]) = ptr[p];
                    }
                }
            }
        }
Esempio n. 30
0
int fh_png_load(const char *name, unsigned char *buffer, int x, int y)
{
	static const png_color_16 my_background = {0, 0, 0, 0, 0};

	png_structp png_ptr;
	png_infop info_ptr;
	png_uint_32 width, height;
	unsigned int i;
	int bit_depth, color_type, interlace_type;
	int number_passes, pass;
	png_byte * fbptr;
	FILE * fh;

	if (!(fh = fopen(name, "rb")))
		return(FH_ERROR_FILE);

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (png_ptr == NULL) 
		return(FH_ERROR_FORMAT);
	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL)
	{
		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
		fclose(fh); 
		return(FH_ERROR_FORMAT);
	}

	if (setjmp(png_ptr->jmpbuf))
	{
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		fclose(fh); 
		return(FH_ERROR_FORMAT);
	}

	png_init_io(png_ptr, fh);

	png_read_info(png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);

	if (color_type == PNG_COLOR_TYPE_PALETTE)
	{
		png_set_palette_to_rgb(png_ptr);
		png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
		/* other possibility for png_set_background: use png_get_bKGD */
	}

	if (color_type == PNG_COLOR_TYPE_GRAY        ||
	    color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
	{
		png_set_gray_to_rgb(png_ptr);
		png_set_background(png_ptr, (png_color_16 *)&my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
	}

	if (color_type & PNG_COLOR_MASK_ALPHA)
		png_set_strip_alpha(png_ptr);

	if (bit_depth < 8)
		png_set_packing(png_ptr);

	if (bit_depth == 16)
		png_set_strip_16(png_ptr);

/* on Intel PC ?:
	if (bit_depth == 16)
		png_set_swap(png_ptr);
*/

	number_passes = png_set_interlace_handling(png_ptr);
	png_read_update_info(png_ptr, info_ptr);

	if (width * 3 != png_get_rowbytes(png_ptr, info_ptr))
	{
		printf("[png.cpp]: Error processing %s - please report (including image).\n", name);
		return(FH_ERROR_FORMAT);
	}

	for(pass = 0; pass < number_passes; pass++)
	{
		fbptr = (png_byte *)buffer;
		for (i = 0; i < height; i++, fbptr += width * 3)
		{
			png_read_row(png_ptr, fbptr, NULL);
		}
	}
	png_read_end(png_ptr, info_ptr);
	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
	fclose(fh);
	return(FH_ERROR_OK);
}