Example #1
0
void PNGAPI
png_read_png(png_structp png_ptr, png_infop info_ptr,
                           int transforms,
                           voidp params)
{
   int row;

#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
   /* invert the alpha channel from opacity to transparency */
   if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
       png_set_invert_alpha(png_ptr);
#endif

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

   /* -------------- image transformations start here ------------------- */

#if defined(PNG_READ_16_TO_8_SUPPORTED)
   /* tell libpng to strip 16 bit/color files down to 8 bits/color */
   if (transforms & PNG_TRANSFORM_STRIP_16)
       png_set_strip_16(png_ptr);
#endif

#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
   /* Strip alpha bytes from the input data without combining with the
    * background (not recommended).
    */
   if (transforms & PNG_TRANSFORM_STRIP_ALPHA)
       png_set_strip_alpha(png_ptr);
#endif

#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED)
   /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
    * byte into separate bytes (useful for paletted and grayscale images).
    */
   if (transforms & PNG_TRANSFORM_PACKING)
       png_set_packing(png_ptr);
#endif

#if defined(PNG_READ_PACKSWAP_SUPPORTED)
   /* Change the order of packed pixels to least significant bit first
    * (not useful if you are using png_set_packing). */
   if (transforms & PNG_TRANSFORM_PACKSWAP)
       png_set_packswap(png_ptr);
#endif

#if defined(PNG_READ_EXPAND_SUPPORTED)
   /* Expand paletted colors into true RGB triplets
    * Expand grayscale images to 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 (transforms & PNG_TRANSFORM_EXPAND)
       if ((png_ptr->bit_depth < 8) ||
           (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||
           (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
         png_set_expand(png_ptr);
#endif

   /* We don't handle background color or gamma transformation or dithering. */

#if defined(PNG_READ_INVERT_SUPPORTED)
   /* invert monochrome files to have 0 as white and 1 as black */
   if (transforms & PNG_TRANSFORM_INVERT_MONO)
       png_set_invert_mono(png_ptr);
#endif

#if defined(PNG_READ_SHIFT_SUPPORTED)
   /* If you want to shift the pixel values from the range [0,255] or
    * [0,65535] to the original [0,7] or [0,31], or whatever range the
    * colors were originally in:
    */
   if ((transforms & PNG_TRANSFORM_SHIFT)
       && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
   {
      png_color_8p sig_bit;

      png_get_sBIT(png_ptr, info_ptr, &sig_bit);
      png_set_shift(png_ptr, sig_bit);
   }
#endif

#if defined(PNG_READ_BGR_SUPPORTED)
   /* flip the RGB pixels to BGR (or RGBA to BGRA) */
   if (transforms & PNG_TRANSFORM_BGR)
       png_set_bgr(png_ptr);
#endif

#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
   /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
   if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
       png_set_swap_alpha(png_ptr);
#endif

#if defined(PNG_READ_SWAP_SUPPORTED)
   /* swap bytes of 16 bit files to least significant byte first */
   if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
       png_set_swap(png_ptr);
#endif

   /* We don't handle adding filler bytes */

   /* Optional call to gamma correct and add the background to the palette
    * and update info structure.  REQUIRED if you are expecting libpng to
    * update the palette for you (i.e., you selected such a transform above).
    */
   png_read_update_info(png_ptr, info_ptr);

   /* -------------- image transformations end here ------------------- */

#ifdef PNG_FREE_ME_SUPPORTED
   png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
#endif
   if(info_ptr->row_pointers == NULL)
   {
      info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr,
         info_ptr->height * sizeof(png_bytep));
#ifdef PNG_FREE_ME_SUPPORTED
      info_ptr->free_me |= PNG_FREE_ROWS;
#endif
      for (row = 0; row < (int)info_ptr->height; row++)
      {
         info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr,
            png_get_rowbytes(png_ptr, info_ptr));
      }
   }

   png_read_image(png_ptr, info_ptr->row_pointers);
   info_ptr->valid |= PNG_INFO_IDAT;

   /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
   png_read_end(png_ptr, info_ptr);

   if(transforms == 0 || params == NULL)
      /* quiet compiler warnings */ return;

}
Example #2
0
/* Read a PNG file.  You may want to return an error code if the read
 * fails (depending upon the failure).  There are two "prototypes" given
 * here - one where we are given the filename, and we need to open the
 * file, and the other where we are given an open file (possibly with
 * some or all of the magic bytes read - see comments above).
 */
#ifdef open_file /* prototype 1 */
void read_png(char *file_name)  /* We need to open the file */
{
   png_structp png_ptr;
   png_infop info_ptr;
   unsigned int sig_read = 0;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
   FILE *fp;

   if ((fp = fopen(file_name, "rb")) == NULL)
      return (ERROR);
#else no_open_file /* prototype 2 */
void read_png(FILE *fp, unsigned int sig_read)  /* file is already open */
{
   png_structp png_ptr;
   png_infop info_ptr;
   png_uint_32 width, height;
   int bit_depth, color_type, interlace_type;
#endif no_open_file /* only use one prototype! */

   /* Create and initialize the png_struct with the desired error handler
    * functions.  If you want to use the default stderr and longjump method,
    * you can supply NULL for the last three parameters.  We also supply the
    * the compiler header file version, so that we know if the application
    * was compiled with a compatible version of the library.  REQUIRED
    */
   png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
      png_voidp user_error_ptr, user_error_fn, user_warning_fn);

   if (png_ptr == NULL)
   {
      fclose(fp);
      return (ERROR);
   }

   /* Allocate/initialize the memory for image information.  REQUIRED. */
   info_ptr = png_create_info_struct(png_ptr);
   if (info_ptr == NULL)
   {
      fclose(fp);
      png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
      return (ERROR);
   }

   /* Set error handling if you are using the setjmp/longjmp method (this is
    * the normal 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_ptr)))
   {
      /* Free all of the memory associated with the png_ptr and info_ptr */
      png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
      fclose(fp);
      /* If we get here, we had a problem reading the file */
      return (ERROR);
   }

   /* One of the following I/O initialization methods is REQUIRED */
#ifdef streams /* PNG file I/O method 1 */
   /* Set up the input control if you are using standard C streams */
   png_init_io(png_ptr, fp);

#else no_streams /* PNG file I/O method 2 */
   /* If you are using replacement read functions, instead of calling
    * png_init_io() here you would call:
    */
   png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn);
   /* where user_io_ptr is a structure you want available to the callbacks */
#endif no_streams /* Use only one I/O method! */

   /* If we have already read some of the signature */
   png_set_sig_bytes(png_ptr, sig_read);

#ifdef hilevel
   /*
    * If you have enough memory to read in the entire image at once,
    * and you need to specify only transforms that can be controlled
    * with one of the PNG_TRANSFORM_* bits (this presently excludes
    * dithering, filling, setting background, and doing gamma
    * adjustment), then you can read the entire image (including
    * pixels) into the info structure with this call:
    */
   png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL);
#else
   /* OK, you're doing it the hard way, with the lower-level functions */

   /* 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_ptr, info_ptr);

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

/* Set up the data transformations you want.  Note that these are all
 * optional.  Only call them if you want/need them.  Many of the
 * transformations only work on specific types of images, and many
 * are mutually exclusive.
 */

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

   /* Strip alpha bytes from the input data without combining with the
    * background (not recommended).
    */
   png_set_strip_alpha(png_ptr);

   /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
    * byte into separate bytes (useful for paletted and grayscale images).
    */
   png_set_packing(png_ptr);

   /* Change the order of packed pixels to least significant bit first
    * (not useful if you are using png_set_packing). */
   png_set_packswap(png_ptr);

   /* Expand paletted colors into true RGB triplets */
   if (color_type == PNG_COLOR_TYPE_PALETTE)
      png_set_palette_to_rgb(png_ptr);

   /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
   if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
      png_set_gray_1_2_4_to_8(png_ptr);

   /* 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_ptr, info_ptr, PNG_INFO_tRNS))
      png_set_tRNS_to_alpha(png_ptr);

   /* Set the background color to draw transparent and alpha images over.
    * It is possible to set the red, green, and blue components directly
    * for paletted images instead of supplying a palette index.  Note that
    * even if the PNG file supplies a background, you are not required to
    * use it - you should use the (solid) application background if it has one.
    */

   png_color_16 my_background, *image_background;

   if (png_get_bKGD(png_ptr, info_ptr, &image_background))
      png_set_background(png_ptr, image_background,
                         PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
   else
      png_set_background(png_ptr, &my_background,
                         PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);

   /* Some suggestions as to how to get a screen gamma value */

   /* Note that screen gamma is the display_exponent, which includes
    * the CRT_exponent and any correction for viewing conditions */
   if (/* We have a user-defined screen gamma value */)
   {
      screen_gamma = user-defined screen_gamma;
   }
   /* This is one way that applications share the same screen gamma value */
   else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL)
Example #3
0
int read_header(const char *filename, dt_imageio_png_t *png)
{
  png->f = fopen(filename, "rb");

  if(!png->f) return 1;

#define NUM_BYTES_CHECK (8)

  png_byte dat[NUM_BYTES_CHECK];

  size_t cnt = fread(dat, 1, NUM_BYTES_CHECK, png->f);

  if(cnt != NUM_BYTES_CHECK || png_sig_cmp(dat, (png_size_t)0, NUM_BYTES_CHECK))
  {
    fclose(png->f);
    return 1;
  }

  png->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if(!png->png_ptr)
  {
    fclose(png->f);
    return 1;
  }

  png->info_ptr = png_create_info_struct(png->png_ptr);
  if(!png->info_ptr)
  {
    fclose(png->f);
    png_destroy_read_struct(&png->png_ptr, NULL, NULL);
    return 1;
  }

  if(setjmp(png_jmpbuf(png->png_ptr)))
  {
    fclose(png->f);
    png_destroy_read_struct(&png->png_ptr, &png->info_ptr, NULL);
    return 1;
  }

  png_init_io(png->png_ptr, png->f);

  // we checked some bytes
  png_set_sig_bytes(png->png_ptr, NUM_BYTES_CHECK);

  // image info
  png_read_info(png->png_ptr, png->info_ptr);

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

  // image input transformations

  // palette => rgb
  if(png->color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png->png_ptr);

  // 1, 2, 4 bit => 8 bit
  if(png->color_type == PNG_COLOR_TYPE_GRAY && png->bit_depth < 8)
  {
    png_set_expand_gray_1_2_4_to_8(png->png_ptr);
    png->bit_depth = 8;
  }

  // strip alpha channel
  if(png->color_type & PNG_COLOR_MASK_ALPHA) png_set_strip_alpha(png->png_ptr);

  // grayscale => rgb
  if(png->color_type == PNG_COLOR_TYPE_GRAY || png->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    png_set_gray_to_rgb(png->png_ptr);

  // reflect changes
  png_read_update_info(png->png_ptr, png->info_ptr);

  // png->bytespp = 3*bit_depth/8;
  png->width = png_get_image_width(png->png_ptr, png->info_ptr);
  png->height = png_get_image_height(png->png_ptr, png->info_ptr);

#undef NUM_BYTES_CHECK

  return 0;
}
Example #4
0
bool PngImage::Load(FILE *pStream)
{
  if (pStream && !IsValid())
  {
    bool success = false;
    ubyte aPngHeader[PNG_IMAGE_HEADER_SIZE];
    png_structp pPngStruct = NULL;
    png_infop   pPngInfo   = NULL;
    //float gamma = 0.0;
    uint rowSize;
    ubyte     *pImageData = NULL;
    png_bytep *pImageRows = NULL;
    uint offset = 0;
    png_uint_32 width  = 0;
    png_uint_32 height = 0;
    int bpp = 0;
    int colorType = 0;

    //check png signature
    if (sizeof(aPngHeader) != fread(aPngHeader, 1, sizeof(aPngHeader), pStream))
    {
      //read failed
      goto Exit_Load;
    }
    if (!png_check_sig(aPngHeader, sizeof(aPngHeader)))
    {
      //file is not a png image
      goto Exit_Load;
    }

    //create png read struct
    pPngStruct = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!pPngStruct)
    {
      //png struct allocation failed
      goto Exit_Load;
    }

    //create png info struct
    pPngInfo = png_create_info_struct(pPngStruct);
    if (!pPngInfo)
    {
      //png info allocation failed
      goto Exit_Load;
    }

    //required for png library use
    if (setjmp(pPngStruct->jmpbuf))
    {
      //handle png read error
      goto Exit_Load;
    }

    //initialize png io
    png_init_io(pPngStruct, pStream);

    //set offset into the file since png header has been already read 
    png_set_sig_bytes(pPngStruct, sizeof(aPngHeader));

    //read png image info header
    png_read_info(pPngStruct, pPngInfo);
    png_get_IHDR(pPngStruct, pPngInfo, &width, &height, &bpp, &colorType,
      NULL, NULL, NULL);

    DbgMessage("Image %ux%ux%ubpp", width, height, bpp);

    //filter out unsupported images
    if (bpp < PNG_IMAGE_MIN_BPP || bpp > PNG_IMAGE_MAX_BPP)
    {
      goto Exit_Load;
    }

    //convert palette images to rgb
    if (PNG_COLOR_TYPE_PALETTE == colorType)
    {
      png_set_expand(pPngStruct);
    }

    //convert low-bpp images to 8 bpp
    if (bpp < IMAGE_BPP_8)
    {
      png_set_expand(pPngStruct);
    }

    //strip alpha channel
    if ((colorType & PNG_COLOR_MASK_ALPHA) ||
      png_get_valid(pPngStruct, pPngInfo, PNG_INFO_tRNS))
    {
      png_set_strip_alpha(pPngStruct);
    }

    //strip 16 bpp images down to 8 bpp
    if (IMAGE_BPP_16 == bpp)
    {
      png_set_strip_16(pPngStruct);
    }

    //convert grayscale images to rgb
    if (PNG_COLOR_TYPE_GRAY == colorType || PNG_COLOR_TYPE_GRAY_ALPHA == colorType)
    {
      //png_set_expand(pPngStruct);
      png_set_gray_to_rgb(pPngStruct);
    }

    //perform gamma correction if gamma is preset
    /*if (png_get_gAMA(pPngStruct, pPngInfo, &gamma))
    {
      //png_set_gamma(pPngStruct, ???, gamma);
    }*/

    //update image info
    png_read_update_info(pPngStruct, pPngInfo);

    //allocate space for image row offsets
    rowSize = png_get_rowbytes(pPngStruct, pPngInfo);
    pImageData = new ubyte [height * rowSize];
    if (!pImageData)
    {
      //allocation failed
      goto Exit_Load;
    }

    //allocate space for image row pointers
    pImageRows = new png_bytep [height];
    if (!pImageRows)
    {
      //allocation failed
      goto Exit_Load;
    }

    //set individual row pointers to correct offsets
    for (uint index = 0; index < height; ++index)
    {
      pImageRows[index] = pImageData + offset;
      offset += rowSize;
    }

    //read image data
    png_read_image(pPngStruct, pImageRows);
    png_read_end(pPngStruct, NULL);

    //set image properties
    m_pImageData = pImageData;
    m_width  = static_cast<uint>(width);
    m_height = static_cast<uint>(height);
    m_bpp    = static_cast<uint>(bpp);

    //image successfully loaded
    success = true;

Exit_Load:
    delete pImageRows;
    if (pPngStruct && pPngInfo)
    {
      //free png struct and png info
      png_destroy_read_struct(&pPngStruct, &pPngInfo, NULL);
    }
    else if (pPngStruct)
    {
      //free png struct only
      png_destroy_read_struct(&pPngStruct, NULL, NULL);
    }
    if (!success)
    {
      delete pImageData;
    }
    return success;
  }
  return false;
}
Example #5
0
static Image * __doOpenImage(char * filename, CSOUND *csound)
{
#ifdef USE_LIBPNG
#define HS (8)
    FILE *fp;
    void *fd;
    unsigned char header[HS];
    png_structp png_ptr;
    png_infop info_ptr;
    /* png_infop end_ptr; */
    int is_png;
    png_uint_32 width, height, rowbytes;
    int bit_depth;
    int color_type;
    unsigned char *image_data;
    png_bytepp row_pointers;
    unsigned int i;

    Image *img;

    fd = csound->FileOpen2(csound, &fp, CSFILE_STD, filename, "rb",
                           "SFDIR;SSDIR", CSFTYPE_IMAGE_PNG, 0);
    if (UNLIKELY(fd == NULL)) {
      csound->InitError(csound,
                        Str("imageload: cannot open image %s.\n"), filename);
      return NULL;
    }

    if (UNLIKELY(HS!=fread(header, 1, HS, fp)))
      csound->InitError(csound,
                        Str("imageload: file %s is not in PNG format.\n"),
                        filename);
    is_png = !png_sig_cmp(header, 0, HS);

    if (UNLIKELY(!is_png)) {
      csound->InitError(csound,
                        Str("imageload: file %s is not in PNG format.\n"),
                        filename);
      csound->FileClose(csound, fd);
      return NULL;
    }

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (UNLIKELY(!png_ptr)) {
      csound->InitError(csound, Str("imageload: out of memory.\n"));
      csound->FileClose(csound, fd);
      return NULL;
    }
    info_ptr = png_create_info_struct(png_ptr);
    if (UNLIKELY(!info_ptr)) {
      png_destroy_read_struct(&png_ptr, (png_infopp) NULL, (png_infopp) NULL);
      csound->InitError(csound, Str("imageload: out of memory.\n"));
      csound->FileClose(csound, fd);
      return NULL;
    }

    /* end_ptr = png_create_info_struct(png_ptr); */
    /* if (UNLIKELY(!end_ptr)) { */
    /*   png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL); */
    /*   csound->InitError(csound, Str("imageload: out of memory.\n")); */
    /*   csound->FileClose(csound, fd); */
    /*   return NULL; */
    /* } */

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

    png_read_info(png_ptr, info_ptr);
    {

      png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
                   &color_type, NULL, NULL, NULL);
    }
    if (color_type & PNG_COLOR_MASK_ALPHA)
      png_set_strip_alpha(png_ptr);
    if (bit_depth == 16)
      png_set_strip_16(png_ptr);
    if (bit_depth < 8)
      png_set_packing(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY ||
        color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
      png_set_gray_to_rgb(png_ptr);
    if (color_type == PNG_COLOR_TYPE_PALETTE)
      png_set_palette_to_rgb(png_ptr);

    png_read_update_info(png_ptr, info_ptr);
    rowbytes = png_get_rowbytes(png_ptr, info_ptr);

    if (UNLIKELY((image_data = (unsigned char *) malloc(rowbytes * height))==NULL)) {
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
      csound->InitError(csound, Str("imageload: out of memory.\n"));
      return NULL;
    }

    row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep));
    if (UNLIKELY(row_pointers == NULL)) {
      png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
      free(image_data);
      image_data = NULL;
      csound->InitError(csound, Str("imageload: out of memory.\n"));
      return NULL;
    }

    for (i = 0; i < height; i++)
      row_pointers[i] = image_data + i*rowbytes;

    png_read_image(png_ptr, row_pointers);
    free(row_pointers);
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    csound->FileClose(csound, fd);

    img = malloc(sizeof(Image));
    if (UNLIKELY(!img)) {
      free(image_data);
      csound->InitError(csound, Str("imageload: out of memory.\n"));
      return NULL;
    }

    img->w = width;
    img->h = height;
    img->imageData = image_data;

    return img;

#else

    Display *disp;
    ImlibData *id;
    ImlibImage *im;
    Image *img;
    size_t datasize;

    disp=XOpenDisplay(NULL);
    id=Imlib_init(disp);
    im=Imlib_load_image(id, filename);

    img = malloc(sizeof(Image));
    img->w = im->rgb_width;
    img->h = im->rgb_height;
    datasize = img->w*img->h*3 * sizeof(unsigned char);
    img->imageData = malloc(datasize);
    memcpy(img->imageData, im->rgb_data, datasize);

    return img;
#endif

    /* SDL */
/*  Image *img;
    size_t datasize;
    SDL_Surface *srfc;
    int x,y;
    int bpp;
    int indcount = 0;
    Uint32 *pixel;
    Uint8 r, g, b;

    srfc = IMG_Load(filename);
    if (srfc) {
        SDL_LockSurface(srfc);
        img = malloc(sizeof(Image));
        img->w = srfc->w;
        img->h = srfc->h;
        bpp = srfc->format->BitsPerPixel;

        datasize = img->w*img->h*3 * sizeof(unsigned char);
        img->imageData = malloc(datasize);

        for(y = 0; y < img->h; y++) {
            for(x = 0; x < img->w; x++) {
                if (bpp<=8) //need to test on other platforms
                    pixel = srfc->pixels + y * srfc->pitch + x * bpp;
                else
                    pixel = srfc->pixels + y * srfc->pitch + x * bpp / 8;
                SDL_GetRGB(*pixel,srfc->format, &r, &g, &b);
                img->imageData[indcount]= r;
                img->imageData[indcount+1]= g;
                img->imageData[indcount+2]= b;
                indcount += 3;
            }
        }
        SDL_UnlockSurface(srfc);
        SDL_FreeSurface ( srfc );
        return img;
  }

  return NULL;
*/

}
Example #6
0
void
read_png(unsigned char **block, png_uint_32 *width, png_uint_32 *height, FILE *file)
{
    png_structp png_ptr;
    png_infop   info_ptr;
    png_bytep *row_pointers;
    unsigned row, x, y;
    int rowbytes;
    char *dst;

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,NULL,NULL,NULL);
    if (png_ptr == NULL) {
	printf("\nERROR: read_png: Could not create read struct.\n");
	exit(1);
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
	printf("\nERROR: read_png: Could not create info struct.\n");
	png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
	exit(1);
    }


    if (setjmp(png_ptr->jmpbuf)) {

	printf("\nERROR: read_png: fatal error.\n");
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_info **)0);
        /* free pointers before returning, if necessary */
        free(png_ptr);
        free(info_ptr);

	exit(1);
    }

    /* Set up the input control if you are using standard C streams */
    png_init_io(png_ptr, file);


    /* 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_ptr, info_ptr);

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

    // printf("read_png: width=%d, height=%d, bit_depth=%d\n", width, height, bit_depth);
    // printf("read_png: color_type=%d, interlace_type=%d\n", color_type, interlace_type);
    
    // strip alpha information
    if (color_type & PNG_COLOR_MASK_ALPHA) {
        png_set_strip_alpha(png_ptr);
    }

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

    /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
     * byte into separate bytes (useful for paletted and grayscale images).
     */
    png_set_packing(png_ptr);

    /* Expand paletted colors into true RGB triplets */
    png_set_expand(png_ptr);

    png_start_read_image(png_ptr);

    /* The easiest way to read the image: */

    rowbytes = png_get_rowbytes(png_ptr, info_ptr) * 3;
    row_pointers = (png_bytep *)malloc((*height) * sizeof(*row_pointers));

    row_pointers[0] = (png_bytep)malloc(rowbytes * (*height) * 2);

    for(row = 1; row < (*height); row++) {
	row_pointers[row] = row_pointers[row - 1] + rowbytes*2;
    }
    /* Read the entire image in one go */
    png_read_image(png_ptr, row_pointers);

    // we use fixed height here because block is of limited, fixed size
    // not fixed any more

    *block = realloc(*block, *height * *width * 3);

    // *block = malloc(*height * *width * 6);

    dst = *block;
    for(y = 0; y < *height; y++) {
	for(x = 0; x < *width * 3; x++) {
	  *dst++ = row_pointers[y][x];

	  // *dst++ = 0;
	}
    }
  
    free(row_pointers[0]);
    free(row_pointers);

    /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
    png_read_end(png_ptr, info_ptr);

    /* At this point you have read the entire image */

    /* clean up after the read, and free any memory allocated - REQUIRED */
    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
}
Example #7
0
int int_png_load(const char *name, unsigned char **buffer, int* xp, int* yp, int* bpp, bool alpha)
{
	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, number_passes, pass, int_bpp;
	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_jmpbuf(png_ptr)))
	{
		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 (alpha)
	{
		*bpp = png_get_channels(png_ptr, info_ptr);
		if ((*bpp != 4) || !(color_type & PNG_COLOR_MASK_ALPHA))
		{
			png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
			fclose(fh);
			return fh_png_load(name, buffer, xp, yp);
		}
		// 24bit PNGs with alpha-channel
		int_bpp = 4;
//		png_set_swap_alpha(png_ptr);
		if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
			png_set_tRNS_to_alpha(png_ptr);
	}else // All other PNGs
	{
		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);
		int_bpp = 3;
	}
	if (bit_depth == 16)
		png_set_strip_16(png_ptr);
	number_passes = png_set_interlace_handling(png_ptr);
	png_read_update_info(png_ptr,info_ptr);
	unsigned long rowbytes = png_get_rowbytes(png_ptr, info_ptr);
	if (width * int_bpp != rowbytes)
	{
		printf("[png.cpp]: Error processing %s - please report (including image).\n", name);
		printf("           width: %lu rowbytes: %lu\n", (unsigned long)width, (unsigned long)rowbytes);
		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 * int_bpp)
			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);
}
Example #8
0
    void write_header( const View& view )
    {
        typedef detail::png_write_support< typename channel_type< typename get_pixel_type< View >::type >::type
                                         , typename color_space_type< View >::type
                                         > png_rw_info_t;

        // 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
        png_set_IHDR( get_struct()
                    , get_info()
                    , static_cast< png_image_width::type  >( view.width()  )
                    , static_cast< png_image_height::type >( view.height() )
                    , static_cast< png_bitdepth::type     >( png_rw_info_t::_bit_depth )
                    , static_cast< png_color_type::type   >( png_rw_info_t::_color_type )
                    , _info._interlace_method
                    , _info._compression_type
                    , _info._filter_method
                    );

#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED
        if( _info._valid_cie_colors )
        {
            png_set_cHRM( get_struct()
                        , get_info()
                        , _info._white_x
                        , _info._white_y
                        , _info._red_x
                        , _info._red_y
                        , _info._green_x
                        , _info._green_y
                        , _info._blue_x
                        , _info._blue_y
                        );
        }

        if( _info._valid_file_gamma )
        {
            png_set_gAMA( get_struct()
                        , get_info()
                        , _info._file_gamma
                        );
        }
#else
        if( _info._valid_cie_colors )
        {
            png_set_cHRM_fixed( get_struct()
                              , get_info()
                              , _info._white_x
                              , _info._white_y
                              , _info._red_x
                              , _info._red_y
                              , _info._green_x
                              , _info._green_y
                              , _info._blue_x
                              , _info._blue_y
                              );
        }

        if( _info._valid_file_gamma )
        {
            png_set_gAMA_fixed( get_struct()
                              , get_info()
                              , _info._file_gamma
                              );
        }
#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED

        if( _info._valid_icc_profile )
        {
#if PNG_LIBPNG_VER_MINOR >= 5
            png_set_iCCP( get_struct()
                        , get_info()
                        , const_cast< png_charp >( _info._icc_name.c_str() )
                        , _info._iccp_compression_type
                        , reinterpret_cast< png_const_bytep >( _info._profile.c_str() )
                        , _info._profile_length
                        );
#else
            png_set_iCCP( get_struct()
                        , get_info()
                        , const_cast< png_charp >( _info._icc_name.c_str() )
                        , _info._iccp_compression_type
                        , const_cast< png_charp >( _info._profile.c_str() )
                        , _info._profile_length
                        );
#endif
        }

        if( _info._valid_intent )
        {
            png_set_sRGB( get_struct()
                        , get_info()
                        , _info._intent
                        );
        }

        if( _info._valid_palette )
        {
            png_set_PLTE( get_struct()
                        , get_info()
                        , const_cast< png_colorp >( &_info._palette.front() )
                        , _info._num_palette
                        );
        }

        if( _info._valid_background )
        {
            png_set_bKGD( get_struct()
                        , get_info()
                        , const_cast< png_color_16p >( &_info._background )
                        );
        }

        if( _info._valid_histogram )
        {
            png_set_hIST( get_struct()
                        , get_info()
                        , const_cast< png_uint_16p >( &_info._histogram.front() )
                        );
        }

        if( _info._valid_offset )
        {
            png_set_oFFs( get_struct()
                        , get_info()
                        , _info._offset_x
                        , _info._offset_y
                        , _info._off_unit_type
                        );
        }

        if( _info._valid_pixel_calibration )
        {
            std::vector< const char* > params( _info._num_params );
            for( std::size_t i = 0; i < params.size(); ++i )
            {
                params[i] = _info._params[ i ].c_str();
            }

            png_set_pCAL( get_struct()
                        , get_info()
                        , const_cast< png_charp >( _info._purpose.c_str() )
                        , _info._X0
                        , _info._X1
                        , _info._cal_type
                        , _info._num_params
                        , const_cast< png_charp  >( _info._units.c_str() )
                        , const_cast< png_charpp >( &params.front()     )
                        );
        }

        if( _info._valid_resolution )
        {
            png_set_pHYs( get_struct()
                        , get_info()
                        , _info._res_x
                        , _info._res_y
                        , _info._phy_unit_type
                        );
        }

        if( _info._valid_significant_bits )
        {
            png_set_sBIT( get_struct()
                        , get_info()
                        , const_cast< png_color_8p >( &_info._sig_bits )
                        );
        }

#ifdef BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED 
        if( _info._valid_scale_factors )
        {
            png_set_sCAL( get_struct()
                        , get_info()
                        , this->_info._scale_unit
                        , this->_info._scale_width
                        , this->_info._scale_height
                        );
        }
#else
#ifdef BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
        if( _info._valid_scale_factors )
        {
            png_set_sCAL_fixed( get_struct()
                              , get_info()
                              , this->_info._scale_unit
                              , this->_info._scale_width
                              , this->_info._scale_height
                              );
        }
#else
        if( _info._valid_scale_factors )
        {
            png_set_sCAL_s( get_struct()
                          , get_info()
                          , this->_info._scale_unit
                          , const_cast< png_charp >( this->_info._scale_width.c_str()  )
                          , const_cast< png_charp >( this->_info._scale_height.c_str() )
                          );
        }

#endif // BOOST_GIL_IO_PNG_FIXED_POINT_SUPPORTED
#endif // BOOST_GIL_IO_PNG_FLOATING_POINT_SUPPORTED


        if( _info._valid_text )
        {
            std::vector< png_text > texts( _info._num_text );
            for( std::size_t i = 0; i < texts.size(); ++i )
            {
                png_text pt;
                pt.compression = _info._text[i]._compression;
                pt.key         = const_cast< png_charp >( this->_info._text[i]._key.c_str()  );
                pt.text        = const_cast< png_charp >( this->_info._text[i]._text.c_str() );
                pt.text_length = _info._text[i]._text.length();

                texts[i] = pt;
            }

            png_set_text( get_struct()
                        , get_info()
                        , &texts.front()
                        , _info._num_text
                        );
        }

        if( _info._valid_modification_time )
        {
            png_set_tIME( get_struct()
                        , get_info()
                        , const_cast< png_timep >( &_info._mod_time )
                        );
        }

        if( _info._valid_transparency_factors )
        {
            int sample_max = ( 1 << _info._bit_depth );

            /* libpng doesn't reject a tRNS chunk with out-of-range samples */
            if( !(  (  _info._color_type == PNG_COLOR_TYPE_GRAY 
                    && (int) _info._trans_values[0].gray > sample_max
                    )
                 || (  _info._color_type == PNG_COLOR_TYPE_RGB
                    &&(  (int) _info._trans_values[0].red   > sample_max 
                      || (int) _info._trans_values[0].green > sample_max
                      || (int) _info._trans_values[0].blue  > sample_max
                      )
                    )
                 )
              )
            {
                //@todo Fix that once reading transparency values works
/*
                png_set_tRNS( get_struct()
                            , get_info()
                            , trans
                            , num_trans
                            , trans_values
                            );
*/
            }
        }

        // Compression Levels - valid values are [0,9]
        png_set_compression_level( get_struct()
                                 , _info._compression_level
                                 );

        png_set_compression_mem_level( get_struct()
                                     , _info._compression_mem_level
                                     );

        png_set_compression_strategy( get_struct()
                                    , _info._compression_strategy
                                    );

        png_set_compression_window_bits( get_struct()
                                       , _info._compression_window_bits
                                       );

        png_set_compression_method( get_struct()
                                  , _info._compression_method
                                  );

        png_set_compression_buffer_size( get_struct()
                                       , _info._compression_buffer_size
                                       );

#ifdef BOOST_GIL_IO_PNG_DITHERING_SUPPORTED
        // Dithering 
        if( _info._set_dithering )
        {
            png_set_dither( get_struct()
                          , &_info._dithering_palette.front()
                          , _info._dithering_num_palette
                          , _info._dithering_maximum_colors
                          , &_info._dithering_histogram.front()
                          , _info._full_dither
                          );
        }
#endif // BOOST_GIL_IO_PNG_DITHERING_SUPPORTED

        // Filter
        if( _info._set_filter )
        {
            png_set_filter( get_struct()
                          , 0
                          , _info._filter
                          );
        }

        // Invert Mono
        if( _info._invert_mono )
        {
            png_set_invert_mono( get_struct() );
        }

        // True Bits
        if( _info._set_true_bits )
        {
            png_set_sBIT( get_struct()
                        , get_info()
                        , &_info._true_bits.front()
                        );
        }

        // sRGB Intent
        if( _info._set_srgb_intent )
        {
            png_set_sRGB( get_struct()
                        , get_info()
                        , _info._srgb_intent
                        );
        }

        // Strip Alpha
        if( _info._strip_alpha )
        {
            png_set_strip_alpha( get_struct() );
        }

        // Swap Alpha
        if( _info._swap_alpha )
        {
            png_set_swap_alpha( get_struct() );
        }


        png_write_info( get_struct()
                      , get_info()
                      );
    }
Example #9
0
int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha,
            Metadata* const metadata) {
  volatile png_structp png;
  volatile png_infop info = NULL;
  volatile png_infop end_info = NULL;
  int color_type, bit_depth, interlaced;
  int has_alpha;
  int num_passes;
  int p;
  int ok = 0;
  png_uint_32 width, height, y;
  int stride;
  uint8_t* volatile rgb = NULL;

  png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
  if (png == NULL) {
    goto End;
  }

  png_set_error_fn(png, 0, error_function, NULL);
  if (setjmp(png_jmpbuf(png))) {
 Error:
    MetadataFree(metadata);
    goto End;
  }

  info = png_create_info_struct(png);
  if (info == NULL) goto Error;
  end_info = png_create_info_struct(png);
  if (end_info == NULL) goto Error;

  png_init_io(png, in_file);
  png_read_info(png, info);
  if (!png_get_IHDR(png, info,
                    &width, &height, &bit_depth, &color_type, &interlaced,
                    NULL, NULL)) goto Error;

  png_set_strip_16(png);
  png_set_packing(png);
  if (color_type == PNG_COLOR_TYPE_PALETTE) {
    png_set_palette_to_rgb(png);
  }
  if (color_type == PNG_COLOR_TYPE_GRAY ||
      color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
    if (bit_depth < 8) {
      png_set_expand_gray_1_2_4_to_8(png);
    }
    png_set_gray_to_rgb(png);
  }
  if (png_get_valid(png, info, PNG_INFO_tRNS)) {
    png_set_tRNS_to_alpha(png);
    has_alpha = 1;
  } else {
    has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
  }

  if (!keep_alpha) {
    png_set_strip_alpha(png);
    has_alpha = 0;
  }

  num_passes = png_set_interlace_handling(png);
  png_read_update_info(png, info);
  stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb);
  rgb = (uint8_t*)malloc(stride * height);
  if (rgb == NULL) goto Error;
  for (p = 0; p < num_passes; ++p) {
    for (y = 0; y < height; ++y) {
      png_bytep row = (png_bytep)(rgb + y * stride);
      png_read_rows(png, &row, NULL, 1);
    }
  }
  png_read_end(png, end_info);

  if (metadata != NULL &&
      !ExtractMetadataFromPNG(png, info, end_info, metadata)) {
    fprintf(stderr, "Error extracting PNG metadata!\n");
    goto Error;
  }

  pic->width = width;
  pic->height = height;
  pic->use_argb = 1;
  ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride)
                 : WebPPictureImportRGB(pic, rgb, stride);

  if (!ok) {
    goto Error;
  }

 End:
  if (png != NULL) {
    png_destroy_read_struct((png_structpp)&png,
                            (png_infopp)&info, (png_infopp)&end_info);
  }
  free(rgb);
  return ok;
}
Example #10
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 (PNG_LIBPNG_VER < 10500)
	if (setjmp(png_ptr->jmpbuf))
#else
	if (setjmp(png_jmpbuf(png_ptr)))
#endif
	{
		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);
}
Example #11
0
uint8_t* ImageDecoder::decodePNGImpl(png_structp pngPtr, uint32_t* width, uint32_t* height)
{
	png_bytep* rowPtrs = NULL;
	uint8_t* outData = NULL;
	png_infop infoPtr = png_create_info_struct(pngPtr);
	if (!infoPtr)
	{
		LOG(LOG_ERROR,"Couldn't initialize png info struct");
		png_destroy_read_struct(&pngPtr, (png_infopp)0, (png_infopp)0);
		return NULL;
	}

	if (setjmp(png_jmpbuf(pngPtr)))
	{
		png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0);
		if (rowPtrs != NULL) delete [] rowPtrs;
		if (outData != NULL) delete [] outData;

		LOG(LOG_ERROR,"error during reading of the png file");

		return NULL;
	}

	png_read_info(pngPtr, infoPtr);

	*width =  png_get_image_width(pngPtr, infoPtr);
	*height = png_get_image_height(pngPtr, infoPtr);

	//bits per CHANNEL! note: not per pixel!
	png_uint_32 bitdepth = png_get_bit_depth(pngPtr, infoPtr);
	//Number of channels
	png_uint_32 channels = png_get_channels(pngPtr, infoPtr);
	//Color type. (RGB, RGBA, Luminance, luminance alpha... palette... etc)
	png_uint_32 color_type = png_get_color_type(pngPtr, infoPtr);

	// Transform everything into 24 bit RGB
	switch (color_type)
	{
		case PNG_COLOR_TYPE_PALETTE:
			png_set_palette_to_rgb(pngPtr);
			// png_set_palette_to_rgb wil convert into 32
			// bit, but we don't want the alpha
			png_set_strip_alpha(pngPtr);
			break;
		case PNG_COLOR_TYPE_GRAY:
			if (bitdepth < 8)
				png_set_gray_to_rgb(pngPtr);
			break;
	}

	if (bitdepth == 16)
	{
		png_set_strip_16(pngPtr);
	}

	if (channels > 3)
	{
		LOG(LOG_NOT_IMPLEMENTED, "Alpha channel not supported in PNG");
		png_set_strip_alpha(pngPtr);
	}

	// Update the infoPtr to reflect the transformations set
	// above. Read new values by calling png_get_* again.
	png_read_update_info(pngPtr, infoPtr);

	//bitdepth = png_get_bit_depth(pngPtr, infoPtr);
	//color_type = png_get_color_type(pngPtr, infoPtr);

	channels = png_get_channels(pngPtr, infoPtr);
	if (channels != 3)
	{
		// Should never get here because of the
		// transformations
		LOG(LOG_NOT_IMPLEMENTED, "Unexpected number of channels in PNG!");

		png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0);

		return NULL;
	}

	const unsigned int stride = png_get_rowbytes(pngPtr, infoPtr);

	outData = new uint8_t[(*height) * stride];
	rowPtrs = new png_bytep[(*height)];
	for (size_t i = 0; i < (*height); i++)
	{
		rowPtrs[i] = (png_bytep)outData + i* stride;
	}

	png_read_image(pngPtr, rowPtrs);
	png_read_end(pngPtr, NULL);
	png_destroy_read_struct(&pngPtr, &infoPtr,(png_infopp)0);
	delete[] (png_bytep)rowPtrs;

	return outData;
}
void ZLEwlImageManager::convertImageDirectPng(const std::string &stringData, ZLImageData &data) const {
	struct s_my_png my_png;
	my_png.p = (char*)stringData.data();
	my_png.size = stringData.length();

	png_structp png_ptr = NULL;
	png_infop info_ptr = NULL;
	unsigned int *row = NULL;

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
			(png_voidp)&my_png, mypng_error_func, mypng_warning_func);
	if ( !png_ptr )
		return;

	if (setjmp( png_ptr->jmpbuf )) {
		data.init(0, 0);
		if (png_ptr)
		{
			png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
		}
		if ( row )
			delete row;
		return;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (!info_ptr)
		mypng_error_func(png_ptr, "cannot create png info struct");
	png_set_read_fn(png_ptr,
			(voidp)&my_png, mypng_read_func);
	png_read_info( png_ptr, info_ptr );


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

	data.init(width, height);

	row = new unsigned int[ width ];

	// SET TRANSFORMS
	if (color_type & PNG_COLOR_MASK_PALETTE)
		png_set_palette_to_rgb(png_ptr);

	if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
		png_set_gray_1_2_4_to_8(png_ptr);

	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
		png_set_tRNS_to_alpha(png_ptr);

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


	if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
		png_set_invert_alpha(png_ptr);
	} else {
		png_color_16 bg = {0, 0xffff, 0xffff, 0xffff, 0xffff};
		png_set_background(png_ptr, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 0.0);

		png_set_strip_alpha(png_ptr);
	}

	if (bit_depth < 8)
		png_set_packing(png_ptr);

	//if (color_type == PNG_COLOR_TYPE_RGB)
	//png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);

	//if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
	//    png_set_swap_alpha(png_ptr);

	if (! (color_type == PNG_COLOR_TYPE_GRAY ||
			color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
		png_set_rgb_to_gray(png_ptr, 1, -1, -1);

	int number_passes = png_set_interlace_handling(png_ptr);
	//if (color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
	//    color_type == PNG_COLOR_TYPE_GRAY_ALPHA)

	//if (color_type == PNG_COLOR_TYPE_RGB ||
	//    color_type == PNG_COLOR_TYPE_RGB_ALPHA)
	png_set_bgr(png_ptr);


	ZLIntegerOption myDitherAlgo(ZLCategoryKey::LOOK_AND_FEEL, "Options", "DitherAlgo", 0);
	register int dalgo = myDitherAlgo.value();
	char *c;	
	for(int pass = 0; pass < number_passes; pass++) {
		for(unsigned int y = 0; y < height; y++) {

			png_read_rows(png_ptr, (unsigned char **)&row, png_bytepp_NULL, 1);

			c = ((ZLEwlImageData&)data).getImageData() + width * y;


			if ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) {
				unsigned char *s = (unsigned char*)row;
				if(dalgo == 1)
					for(unsigned int i = 0; i < width; i++)
						*c++ = Dither2BitColor(*(++s)++, i, y);
				else
					for(unsigned int i = 0; i < width; i++)
						*c++ = *(++s)++;
			} else if(dalgo == 1) {
				unsigned char *s = (unsigned char*)row;
				for(unsigned int i = 0; i < width; i++)
					*c++ = Dither2BitColor(*s++, i, y);
			} else 
				memcpy(c, (char*)row, width);
		}
	}

	png_read_end(png_ptr, info_ptr);

	png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
}
Example #13
0
/*---------------------------------------------------------------------------
   Loads a PNG file.

   Image  : Image will be returned there.
   Path   : Path to image file, relative to the current working directory.
   Gamma  : Display gamma to apply on textures, 2.2 is typical.
  ---------------------------------------------------------------------------*/
void PNG::Load(Texture &Image, const std::string &Path, float Gamma)
   {
   Destroy();

   //Important - set class to reading mode
   Mode = PNG::ModeRead;

   #if defined (WINDOWS)
      if (fopen_s(&File, Path.c_str(), "rb") != 0)
         {throw dexception("Failed to open file: %s.", Path.c_str());}
   #else
      File = fopen(Path.c_str(), "rb");
      if (File == nullptr) {throw dexception("Failed to open file: %s.", Path.c_str());}
   #endif

   uint8 Header[PNG::HeaderSize];
   if (fread((png_bytep)Header, 1, PNG::HeaderSize, File) == 0)
      {throw dexception("fread( ) failed.");}

   if (!png_check_sig(Header, PNG::HeaderSize))
      {throw dexception("Not a valid PNG file.");}

   PngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
   if (PngPtr == nullptr) {throw dexception("png_create_read_struct( ) failed.");}

   InfoPtr = png_create_info_struct(PngPtr);
   if (InfoPtr == nullptr) {throw dexception("png_create_info_struct( ) failed.");}

   if (setjmp(png_jmpbuf(PngPtr)))
      {throw dexception("setjmp( ) failed.");}

   //Read into structures
   png_init_io(PngPtr, File);
   png_set_sig_bytes(PngPtr, PNG::HeaderSize);
   png_read_info(PngPtr, InfoPtr);

   //Determine image attributes
   vector2<png_uint_32> Res;
   int BitDepth, ColourType;
   png_get_IHDR(PngPtr, InfoPtr, &Res.U, &Res.V, &BitDepth, &ColourType, nullptr, nullptr, nullptr);

   Texture::TexType Type = Texture::TypeRGB;
   switch (ColourType)
      {
      case PNG_COLOR_TYPE_GRAY :
         if (BitDepth < 8)
            {
            Type = Texture::TypeLum;
            png_set_expand_gray_1_2_4_to_8(PngPtr);
            }
         else if (BitDepth == 16)
            {
            Type = Texture::TypeDepth;
            }
         break;

      case PNG_COLOR_TYPE_GRAY_ALPHA :
         Type = Texture::TypeRGBA;
         png_set_gray_to_rgb(PngPtr);
         break;

      case PNG_COLOR_TYPE_PALETTE :
         Type = Texture::TypeRGB;
         png_set_palette_to_rgb(PngPtr);
         break;

      case PNG_COLOR_TYPE_RGB :
         Type = Texture::TypeRGB;
         png_set_strip_alpha(PngPtr); //If libpng reports RGB, make sure we completely strip alpha
         break;

      case PNG_COLOR_TYPE_RGB_ALPHA :
         Type = Texture::TypeRGBA;
         break;

      default : throw dexception("Unknown colour type.");
      }

   //Convert palette alpha into a separate alpha channel
   if (png_get_valid(PngPtr, InfoPtr, PNG_INFO_tRNS))
      {
      png_set_tRNS_to_alpha(PngPtr);
      if (ColourType == PNG_COLOR_TYPE_PALETTE) {Type = Texture::TypeRGBA;}
      }

   //Force 8 bit per channel
   if (BitDepth >= 16)
      {
      if (Type != Texture::TypeDepth) {png_set_strip_16(PngPtr);}
      }
   else if (BitDepth < 8)
      {
      png_set_packing(PngPtr);
      }

   //Specify display and file gamma (assume 0.45455 for missing file gamma)
   double FileGamma;
   if (!png_get_gAMA(PngPtr, InfoPtr, &FileGamma)) {FileGamma = 0.45455;}
   png_set_gamma(PngPtr, Gamma, FileGamma);

   //Swap byte order for int16 values on big endian machines
   if ((BitDepth >= 16) && !Math::MachineLittleEndian())
      {png_set_swap(PngPtr);}

   //Apply the above transformation settings
   png_read_update_info(PngPtr, InfoPtr);

   //Allocate image
   Image.Create(cast_vector2(uint, Res), Type);

   if (Image.GetBytesPerLine() < (usize)png_get_rowbytes(PngPtr, InfoPtr))
      {throw dexception("Incorrect scan line size for allocated image.");}

   //Populate row pointer array
   Rows.Create((usize)Res.V);
   for (uiter I = 0; I < (usize)Res.V; I++)
      {
      Rows[I] = Image.Address(0, I);
      }

   //Decode
   png_read_image(PngPtr, Rows.Pointer());
   png_read_end(PngPtr, InfoPtr);

   //Clean up
   Destroy();
   }
Example #14
0
int APIENTRY pngLoadF(FILE *fp, int mipmap, int trans, pngInfo *pinfo) {
	GLint pack, unpack;
	unsigned char header[8];
	png_structp png;
	png_infop   info;
	png_infop   endinfo;
	png_bytep   data, data2;
   png_bytep  *row_p;
   double	fileGamma;

	png_uint_32 width, height, rw, rh;
	int depth, color;

	png_uint_32 i;

	fread(header, 1, 8, fp);
	if (!png_check_sig(header, 8)) return 0;

	png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	info = png_create_info_struct(png);
	endinfo = png_create_info_struct(png);

	// DH: added following lines
	if (setjmp(png->jmpbuf))
	{
		png_destroy_read_struct(&png, &info, &endinfo);
		return 0;
	}
	// ~DH

	png_init_io(png, fp);
	png_set_sig_bytes(png, 8);
	png_read_info(png, info);
	png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);

	if (pinfo != NULL) {
		pinfo->Width  = width;
		pinfo->Height = height;
		pinfo->Depth  = depth;
	}

	if (MaxTextureSize == 0)
		glGetIntegerv(GL_MAX_TEXTURE_SIZE, &MaxTextureSize);

	#ifdef SUPPORTS_PALETTE_EXT
	#ifdef _WIN32
		if (PalettedTextures == -1)
			PalettedTextures = ExtSupported("GL_EXT_paletted_texture") && (strstr((const char *) glGetString(GL_VERSION), "1.1.0 3Dfx Beta") == NULL);

		if (PalettedTextures) {
			if (glColorTableEXT == NULL) {
				glColorTableEXT = (PFNGLCOLORTABLEEXTPROC) wglGetProcAddress("glColorTableEXT");
				if (glColorTableEXT == NULL)
					PalettedTextures = 0;
			}
		}
	#endif
	#endif

	if (PalettedTextures == -1)
		PalettedTextures = 0;

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

	if (color&PNG_COLOR_MASK_ALPHA && trans != PNG_ALPHA) {
		png_set_strip_alpha(png);
		color &= ~PNG_COLOR_MASK_ALPHA;
	}

	if (!(PalettedTextures && mipmap >= 0 && trans == PNG_SOLID))
		if (color == PNG_COLOR_TYPE_PALETTE)
			png_set_expand(png);

	/*--GAMMA--*/
	checkForGammaEnv();
	if (png_get_gAMA(png, info, &fileGamma))
		png_set_gamma(png, screenGamma, fileGamma);
	else
		png_set_gamma(png, screenGamma, 1.0/2.2);

	png_read_update_info(png, info);

	data = (png_bytep) malloc(png_get_rowbytes(png, info)*height);
	row_p = (png_bytep *) malloc(sizeof(png_bytep)*height);

	for (i = 0; i < height; i++) {
		if (StandardOrientation)
			row_p[height - 1 - i] = &data[png_get_rowbytes(png, info)*i];
		else
			row_p[i] = &data[png_get_rowbytes(png, info)*i];
	}

	png_read_image(png, row_p);
	free(row_p);

	rw = SafeSize(width), rh = SafeSize(height);

	if (rw != width || rh != height) {
		const int channels = png_get_rowbytes(png, info)/width;

		data2 = (png_bytep) malloc(rw*rh*channels);

 		/* Doesn't work on certain sizes */
/* 		if (gluScaleImage(glformat, width, height, GL_UNSIGNED_BYTE, data, rw, rh, GL_UNSIGNED_BYTE, data2) != 0)
 			return 0;
*/
		Resize(channels, data, width, height, data2, rw, rh);

		width = rw, height = rh;
		free(data);
		data = data2;
	}

	{ /* OpenGL stuff */
		glGetIntegerv(GL_PACK_ALIGNMENT, &pack);
		glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack);
		glPixelStorei(GL_PACK_ALIGNMENT, 1);
		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

		#ifdef SUPPORTS_PALETTE_EXT
		if (PalettedTextures && mipmap >= 0 && trans == PNG_SOLID && color == PNG_COLOR_TYPE_PALETTE) {
			png_colorp pal;
			int cols;
			GLint intf;

			if (pinfo != NULL) pinfo->Alpha = 0;
			png_get_PLTE(png, info, &pal, &cols);

			switch (cols) {
				case 1<<1:  intf = GL_COLOR_INDEX1_EXT;  break;
				case 1<<2:  intf = GL_COLOR_INDEX2_EXT;  break;
				case 1<<4:  intf = GL_COLOR_INDEX4_EXT;  break;
				case 1<<8:  intf = GL_COLOR_INDEX8_EXT;  break;
				case 1<<12: intf = GL_COLOR_INDEX12_EXT; break;
				case 1<<16: intf = GL_COLOR_INDEX16_EXT; break;
				default:
					/*printf("Warning: Colour depth %i not recognised\n", cols);*/
					return 0;
			}
			glColorTableEXT(GL_TEXTURE_2D, GL_RGB8, cols, GL_RGB, GL_UNSIGNED_BYTE, pal);
			glTexImage2D(GL_TEXTURE_2D, mipmap, intf, width, height, 0, GL_COLOR_INDEX, GL_UNSIGNED_BYTE, data);
		}
		else
		#endif
		if (trans == PNG_SOLID || trans == PNG_ALPHA || trans == PNG_LUMINANCEALPHA || color == PNG_COLOR_TYPE_RGB_ALPHA || color == PNG_COLOR_TYPE_GRAY_ALPHA) {
			GLenum glformat;
			GLint glcomponent;

			switch (color) {
				case PNG_COLOR_TYPE_GRAY:
				case PNG_COLOR_TYPE_RGB:
				case PNG_COLOR_TYPE_PALETTE:
					glformat = GL_RGB;
					glcomponent = 3;
					if (pinfo != NULL) pinfo->Alpha = 0;
					break;

				case PNG_COLOR_TYPE_GRAY_ALPHA:
				case PNG_COLOR_TYPE_RGB_ALPHA:
					glformat = GL_RGBA;
					glcomponent = 4;
					if (pinfo != NULL) pinfo->Alpha = 8;
					break;

				default:
					/*puts("glformat not set");*/
					return 0;
			}

			if (trans == PNG_LUMINANCEALPHA)
				glformat = GL_LUMINANCE_ALPHA;

			if (mipmap == PNG_BUILDMIPMAPS)
				Build2DMipmaps(glcomponent, width, height, glformat, data, 1);
			else if (mipmap == PNG_SIMPLEMIPMAPS)
				Build2DMipmaps(glcomponent, width, height, glformat, data, 0);
			else
				glTexImage2D(GL_TEXTURE_2D, mipmap, glcomponent, width, height, 0, glformat, GL_UNSIGNED_BYTE, data);
		}
		else {
			png_bytep p, endp, q;
			int r, g, b, a;

			p = data, endp = p+width*height*3;
			q = data2 = (png_bytep) malloc(sizeof(png_byte)*width*height*4);

			if (pinfo != NULL) pinfo->Alpha = 8;

			#define FORSTART \
				do { \
					r = *p++; /*red  */ \
					g = *p++; /*green*/ \
					b = *p++; /*blue */ \
					*q++ = r; \
					*q++ = g; \
					*q++ = b;

			#define FOREND \
					q++; \
				} while (p != endp);

			#define ALPHA *q

			switch (trans) {
				case PNG_CALLBACK:
					FORSTART
						ALPHA = AlphaCallback((unsigned char) r, (unsigned char) g, (unsigned char) b);
					FOREND
					break;

				case PNG_STENCIL:
					FORSTART
						if (r == StencilRed && g == StencilGreen && b == StencilBlue)
							ALPHA = 0;
						else
							ALPHA = 255;
					FOREND
					break;

				case PNG_BLEND1:
					FORSTART
						a = r+g+b;
						if (a > 255) ALPHA = 255; else ALPHA = a;
					FOREND
					break;

				case PNG_BLEND2:
					FORSTART
						a = r+g+b;
						if (a > 255*2) ALPHA = 255; else ALPHA = a/2;
					FOREND
					break;

				case PNG_BLEND3:
					FORSTART
						ALPHA = (r+g+b)/3;
					FOREND
					break;

				case PNG_BLEND4:
					FORSTART
						a = r*r+g*g+b*b;
						if (a > 255) ALPHA = 255; else ALPHA = a;
					FOREND
					break;

				case PNG_BLEND5:
					FORSTART
						a = r*r+g*g+b*b;
						if (a > 255*2) ALPHA = 255; else ALPHA = a/2;
					FOREND
					break;

				case PNG_BLEND6:
					FORSTART
						a = r*r+g*g+b*b;
						if (a > 255*3) ALPHA = 255; else ALPHA = a/3;
					FOREND
					break;

//HACK: disabling this for now
/*
				case PNG_BLEND7:
					FORSTART
						a = r*r+g*g+b*b;
						if (a > 255*255) ALPHA = 255; else ALPHA = (int) (sqrt(float(a)));
					FOREND
*/
					break;
			}

			#undef FORSTART
			#undef FOREND
			#undef ALPHA

			if (mipmap == PNG_BUILDMIPMAPS)
				Build2DMipmaps(4, width, height, GL_RGBA, data2, 1);
			else if (mipmap == PNG_SIMPLEMIPMAPS)
				Build2DMipmaps(4, width, height, GL_RGBA, data2, 0);
			else
				glTexImage2D(GL_TEXTURE_2D, mipmap, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data2);

			free(data2);
		}

		glPixelStorei(GL_PACK_ALIGNMENT, pack);
		glPixelStorei(GL_UNPACK_ALIGNMENT, unpack);
	} /* OpenGL end */

   png_read_end(png, endinfo);
	png_destroy_read_struct(&png, &info, &endinfo);

	free(data);

	return 1;
}
Example #15
0
static DFBResult
load_image (const char            *filename,
            DFBSurfaceDescription *desc)
{
     DFBSurfacePixelFormat dest_format;
     DFBSurfacePixelFormat src_format;
     FILE          *fp;
     png_structp    png_ptr  = NULL;
     png_infop      info_ptr = NULL;
     png_uint_32    width, height;
     unsigned char *data     = NULL;
     int            type;
     char           header[8];
     int            bytes, pitch;

     dest_format = (desc->flags & DSDESC_PIXELFORMAT) ? desc->pixelformat : DSPF_UNKNOWN;

     desc->flags                = DSDESC_NONE;
     desc->preallocated[0].data = NULL;

     if (!(fp = fopen (filename, "rb"))) {
          fprintf (stderr, "Failed to open file '%s': %s.\n",
                   filename, strerror (errno));
          goto cleanup;
     }

     bytes = fread (header, 1, sizeof(header), fp);
     if (png_sig_cmp ((unsigned char*) header, 0, bytes)) {
          fprintf (stderr, "File '%s' doesn't seem to be a PNG image file.\n",
                   filename);
          goto cleanup;
     }

     png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
                                       NULL, NULL, NULL);
     if (!png_ptr)
          goto cleanup;

     if (setjmp (png_jmpbuf(png_ptr))) {
          if (desc->preallocated[0].data) {
               free (desc->preallocated[0].data);
               desc->preallocated[0].data = NULL;
          }

          /* data might have been clobbered,
             set it to NULL and leak instead of crashing */
          data = NULL;

          goto cleanup;
     }

     info_ptr = png_create_info_struct (png_ptr);
     if (!info_ptr)
          goto cleanup;

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

     png_read_info (png_ptr, info_ptr);

     png_get_IHDR (png_ptr, info_ptr,
                   &width, &height, &bytes, &type, NULL, NULL, NULL);

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

#ifdef WORDS_BIGENDIAN
     png_set_swap_alpha (png_ptr);
#else
     png_set_bgr (png_ptr);
#endif

     src_format = (type & PNG_COLOR_MASK_ALPHA) ? DSPF_ARGB : DSPF_RGB32;
     switch (type) {
          case PNG_COLOR_TYPE_GRAY:
               if (dest_format == DSPF_A8) {
                    src_format = DSPF_A8;
                    break;
               }
               /* fallthru */
          case PNG_COLOR_TYPE_GRAY_ALPHA:
               png_set_gray_to_rgb (png_ptr);
//               if (rgbformat)
//                    dest_format = rgbformat;
               break;

          case PNG_COLOR_TYPE_PALETTE:
               png_set_palette_to_rgb (png_ptr);
               /* fallthru */
          case PNG_COLOR_TYPE_RGB:
//               if (rgbformat)
//                    dest_format = rgbformat;
          case PNG_COLOR_TYPE_RGB_ALPHA:
               if (dest_format == DSPF_RGB24) {
                    png_set_strip_alpha (png_ptr);
                    src_format = DSPF_RGB24;
               }
               break;
       }

     switch (src_format) {
          case DSPF_RGB32:
                png_set_filler (png_ptr, 0xFF,
#ifdef WORDS_BIGENDIAN
                                PNG_FILLER_BEFORE
#else
                                PNG_FILLER_AFTER
#endif
                                );
                break;
          case DSPF_ARGB:
          case DSPF_A8:
               if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
                    png_set_tRNS_to_alpha (png_ptr);
               break;
          default:
               break;
     }

     pitch = (DFB_BYTES_PER_LINE( src_format, width ) + 7) & ~7;

     data  = (unsigned char*) malloc (height * pitch);
     if (!data) {
          fprintf (stderr, "Failed to allocate %lu bytes.\n", (unsigned long)(height * pitch));
          goto cleanup;
     }

     {
          unsigned int i;
          png_bytep bptrs[height];

          for (i = 0; i < height; i++)
               bptrs[i] = data + i * pitch;

          png_read_image (png_ptr, bptrs);
     }

     if (!dest_format)
          dest_format = src_format;

     if (DFB_BYTES_PER_PIXEL(src_format) != DFB_BYTES_PER_PIXEL(dest_format)) {
          unsigned char *s, *d, *dest;
          int            d_pitch, h;

          D_ASSERT( DFB_BYTES_PER_PIXEL(src_format) == 4 );

          d_pitch = (DFB_BYTES_PER_LINE(dest_format, width) + 7) & ~7;

          dest = (unsigned char*) malloc (height * d_pitch);
          if (!dest) {
               fprintf (stderr, "Failed to allocate %lu bytes.\n", (unsigned long)(height * d_pitch));
               goto cleanup;
          }

          h = height;
          switch (dest_format) {
               case DSPF_RGB16:
                    for (s = data, d = dest; h; h--, s += pitch, d += d_pitch)
                         dfb_argb_to_rgb16 ((u32 *) s, (u16 *) d, width);
                    break;
               case DSPF_ARGB8565:
                    for (s = data, d = dest; h; h--, s += pitch, d += d_pitch)
                         dfb_argb_to_argb8565 ((u32 *) s, (u8 *) d, width);
                    break;
               case DSPF_ARGB1555:
                    for (s = data, d = dest; h; h--, s += pitch, d += d_pitch)
                         dfb_argb_to_argb1555 ((u32 *) s, (u16 *) d, width);
                    break;
               case DSPF_RGBA5551:
                    for (s = data, d = dest; h; h--, s += pitch, d += d_pitch)
                         dfb_argb_to_rgba5551 ((u32 *) s, (u16 *) d, width);
                    break;
               case DSPF_ARGB2554:
                    for (s = data, d = dest; h; h--, s += pitch, d += d_pitch)
                         dfb_argb_to_argb2554 ((u32 *) s, (u16 *) d, width);
                    break;
               case DSPF_ARGB4444:
                    for (s = data, d = dest; h; h--, s += pitch, d += d_pitch)
                         dfb_argb_to_argb4444 ((u32 *) s, (u16 *) d, width);
                    break;
               case DSPF_RGB332:
                    for (s = data, d = dest; h; h--, s += pitch, d += d_pitch)
                         dfb_argb_to_rgb332 ((u32 *) s, (u8 *) d, width);
                    break;
               case DSPF_A8:
                    for (s = data, d = dest; h; h--, s += pitch, d += d_pitch)
                         dfb_argb_to_a8 ((u32 *) s, (u8 *) d, width);
                    break;
               default:
                    fprintf (stderr,
                             "Sorry, unsupported format conversion.\n");
                    goto cleanup;
          }

          free (data);
          data = dest;
          pitch = d_pitch;
     }

     desc->flags = (DFBSurfaceDescriptionFlags)(DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT |
                                                DSDESC_PREALLOCATED);
     desc->width       = width;
     desc->height      = height;
     desc->pixelformat = dest_format;
     desc->preallocated[0].pitch = pitch;
     desc->preallocated[0].data  = data;

     data = NULL;

 cleanup:
     if (fp)
          fclose (fp);

     if (png_ptr)
          png_destroy_read_struct (&png_ptr, &info_ptr, NULL);

     if (data)
          free (data);

     return ((desc->flags) ? DFB_OK : DFB_FAILURE);
}