Beispiel #1
0
bool
loadPngFile(
    IMAGE_T* image,
    FILE *file)
{
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                                 NULL,
                                                 NULL,
                                                 NULL);

    if (png_ptr == NULL)
    {
        return false;
    }

    png_infop info_ptr = png_create_info_struct(png_ptr);

    if (info_ptr == NULL)
    {
        png_destroy_read_struct(&png_ptr, 0, 0);
        return false;
    }

    if (setjmp(png_jmpbuf(png_ptr)))
    {
        png_destroy_read_struct(&png_ptr, &info_ptr, 0);
        return false;
    }

    //---------------------------------------------------------------------

    png_init_io(png_ptr, file);

    png_read_info(png_ptr, info_ptr);

    //---------------------------------------------------------------------

    png_byte colour_type = png_get_color_type(png_ptr, info_ptr);
    png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);

    VC_IMAGE_TYPE_T type = VC_IMAGE_RGB888;

    if (colour_type & PNG_COLOR_MASK_ALPHA)
    {
        type = VC_IMAGE_RGBA32;
    }

    initImage(image,
              type,
              png_get_image_width(png_ptr, info_ptr),
              png_get_image_height(png_ptr, info_ptr),
              false);

    //---------------------------------------------------------------------

    double gamma = 0.0;

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

    //---------------------------------------------------------------------

    if (colour_type == PNG_COLOR_TYPE_PALETTE) 
    {
        png_set_palette_to_rgb(png_ptr);
    }

    if ((colour_type == PNG_COLOR_TYPE_GRAY) && (bit_depth < 8))
    {
        png_set_expand_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)
    {
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
        png_set_scale_16(png_ptr);
#else
        png_set_strip_16(png_ptr);
#endif
    }

    if (colour_type == PNG_COLOR_TYPE_GRAY ||
        colour_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    {
        png_set_gray_to_rgb(png_ptr);
    }

    //---------------------------------------------------------------------

    png_read_update_info(png_ptr, info_ptr);

    //---------------------------------------------------------------------

    png_bytepp row_pointers = malloc(image->height * sizeof(png_bytep));

    png_uint_32 j = 0;
    for (j = 0 ; j < image->height ; ++j)
    {
        row_pointers[j] = image->buffer + (j * image->pitch);
    }

    //---------------------------------------------------------------------

    png_read_image(png_ptr, row_pointers);

    //---------------------------------------------------------------------

    free(row_pointers);

    png_destroy_read_struct(&png_ptr, &info_ptr, 0);

    return true;
}
Beispiel #2
0
int
png_include_image (pdf_ximage *ximage, FILE *png_file)
{
  pdf_obj  *stream;
  pdf_obj  *stream_dict;
  pdf_obj  *colorspace, *mask, *intent;
  png_bytep stream_data_ptr;
  int       trans_type;
  ximage_info info;
  /* Libpng stuff */
  png_structp png_ptr;
  png_infop   png_info_ptr;
  png_byte    bpc, color_type;
  png_uint_32 width, height, rowbytes;

  pdf_ximage_init_image_info(&info);

  stream      = NULL;
  stream_dict = NULL;
  colorspace  = mask = intent = NULL;

  rewind (png_file);
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, warn);
  if (png_ptr == NULL ||
      (png_info_ptr = png_create_info_struct (png_ptr)) == NULL) {
    WARN("%s: Creating Libpng read/info struct failed.", PNG_DEBUG_STR);
    if (png_ptr)
      png_destroy_read_struct(&png_ptr, NULL, NULL);
    return -1;
  }

#if PNG_LIBPNG_VER >= 10603
  /* ignore possibly incorrect CMF bytes */
  png_set_option(png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON);
#endif

  /* Inititializing file IO. */
  png_init_io (png_ptr, png_file);

  /* Read PNG info-header and get some info. */
  png_read_info(png_ptr, png_info_ptr);
  color_type = png_get_color_type  (png_ptr, png_info_ptr);
  width      = png_get_image_width (png_ptr, png_info_ptr);
  height     = png_get_image_height(png_ptr, png_info_ptr);
  bpc        = png_get_bit_depth   (png_ptr, png_info_ptr);

  /* Ask libpng to convert down to 8-bpc. */
  if (bpc > 8) {
    if (pdf_get_version() < 5) {
      WARN("%s: 16-bpc PNG requires PDF version 1.5.", PNG_DEBUG_STR);
    png_set_strip_16(png_ptr);
    bpc = 8;
  }
  }
  /* Ask libpng to gamma-correct.
   * It is wrong to assume screen gamma value 2.2 but...
   * We do gamma correction here only when uncalibrated color space is used. 
   */
  if (!png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP) &&
      !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_sRGB) &&
      !png_get_valid(png_ptr, png_info_ptr, PNG_INFO_cHRM) &&
       png_get_valid(png_ptr, png_info_ptr, PNG_INFO_gAMA)) {
    double G = 1.0;
    png_get_gAMA (png_ptr, png_info_ptr, &G);
    png_set_gamma(png_ptr, 2.2, G);
  }

  trans_type = check_transparency(png_ptr, png_info_ptr);
  /* check_transparency() does not do updata_info() */
  png_read_update_info(png_ptr, png_info_ptr);
  rowbytes = png_get_rowbytes(png_ptr, png_info_ptr);

  /* Values listed below will not be modified in the remaining process. */
  info.width  = width;
  info.height = height;
  info.bits_per_component = bpc;

  if (compat_mode)
    info.xdensity = info.ydensity = 72.0 / 100.0;
  else
  {
    png_uint_32 xppm = png_get_x_pixels_per_meter(png_ptr, png_info_ptr);
    png_uint_32 yppm = png_get_y_pixels_per_meter(png_ptr, png_info_ptr);

    if (xppm > 0)
      info.xdensity = 72.0 / 0.0254 / xppm;
    if (yppm > 0)
      info.ydensity = 72.0 / 0.0254 / yppm;
  }

  stream      = pdf_new_stream (STREAM_COMPRESS);
  stream_dict = pdf_stream_dict(stream);

  stream_data_ptr = (png_bytep) NEW(rowbytes*height, png_byte);
  read_image_data(png_ptr, stream_data_ptr, height, rowbytes);

  /* Non-NULL intent means there is valid sRGB chunk. */
  intent = get_rendering_intent(png_ptr, png_info_ptr);
  if (intent)
    pdf_add_dict(stream_dict, pdf_new_name("Intent"), intent);

  switch (color_type) {
  case PNG_COLOR_TYPE_PALETTE:

    colorspace = create_cspace_Indexed(png_ptr, png_info_ptr);

    switch (trans_type) {
    case PDF_TRANS_TYPE_BINARY:
      /* Color-key masking */
      mask = create_ckey_mask(png_ptr, png_info_ptr);
      break;
    case PDF_TRANS_TYPE_ALPHA:
      /* Soft mask */
      mask = create_soft_mask(png_ptr, png_info_ptr, stream_data_ptr, width, height);
      break;
    default:
      /* Nothing to be done here.
       * No tRNS chunk or image already composited with background color.
       */
      break;
    }
    info.num_components = 1;

    break;
  case PNG_COLOR_TYPE_RGB:
  case PNG_COLOR_TYPE_RGB_ALPHA:

    if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP))
      colorspace = create_cspace_ICCBased(png_ptr, png_info_ptr);
    else if (intent) {
      colorspace = create_cspace_sRGB(png_ptr, png_info_ptr);
    } else {
      colorspace = create_cspace_CalRGB(png_ptr, png_info_ptr);
    }
    if (!colorspace)
      colorspace = pdf_new_name("DeviceRGB");

    switch (trans_type) {
    case PDF_TRANS_TYPE_BINARY:
      mask = create_ckey_mask(png_ptr, png_info_ptr);
      break;
    /* rowbytes changes 4 to 3 at here */
    case PDF_TRANS_TYPE_ALPHA:
      mask = strip_soft_mask(png_ptr, png_info_ptr,
                             stream_data_ptr, &rowbytes, width, height);
      break;
    default:
      mask = NULL;
    }
    info.num_components = 3;
    break;

  case PNG_COLOR_TYPE_GRAY:
  case PNG_COLOR_TYPE_GRAY_ALPHA:

    if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_iCCP))
      colorspace = create_cspace_ICCBased(png_ptr, png_info_ptr);
    else if (intent) {
      colorspace = create_cspace_sRGB(png_ptr, png_info_ptr);
    } else {
      colorspace = create_cspace_CalGray(png_ptr, png_info_ptr);
    }
    if (!colorspace)
      colorspace = pdf_new_name("DeviceGray");

    switch (trans_type) {
    case PDF_TRANS_TYPE_BINARY:
      mask = create_ckey_mask(png_ptr, png_info_ptr);
      break;
    case PDF_TRANS_TYPE_ALPHA:
      mask = strip_soft_mask(png_ptr, png_info_ptr,
                             stream_data_ptr, &rowbytes, width, height);
      break;
    default:
      mask = NULL;
    }
    info.num_components = 1;
    break;

  default:
    WARN("%s: Unknown PNG colortype %d.", PNG_DEBUG_STR, color_type);
  }
  pdf_add_dict(stream_dict, pdf_new_name("ColorSpace"), colorspace);

  pdf_add_stream(stream, stream_data_ptr, rowbytes*height);
  RELEASE(stream_data_ptr);

  if (mask) {
    if (trans_type == PDF_TRANS_TYPE_BINARY)
      pdf_add_dict(stream_dict, pdf_new_name("Mask"), mask);
    else if (trans_type == PDF_TRANS_TYPE_ALPHA) {
      if (info.bits_per_component >= 8 && info.width > 64) {
        pdf_stream_set_predictor(mask, 2, info.width,
                                 info.bits_per_component, 1);
      }
      pdf_add_dict(stream_dict, pdf_new_name("SMask"), pdf_ref_obj(mask));
      pdf_release_obj(mask);
    } else {
      WARN("%s: Unknown transparency type...???", PNG_DEBUG_STR);
      pdf_release_obj(mask);
    }
  }

  /* Finally read XMP Metadata
   * See, XMP Specification Part 3, Storage in Files
   * http://www.adobe.com/jp/devnet/xmp.html
   *
   * We require libpng version >= 1.6.14 since prior versions
   * of libpng had a bug that incorrectly treat the compression
   * flag of iTxt chunks.
   */
#if PNG_LIBPNG_VER >= 10614
  if (pdf_get_version() >= 4) {
    png_textp text_ptr;
    pdf_obj  *XMP_stream, *XMP_stream_dict;
    int       i, num_text;
    int       have_XMP = 0;

    num_text = png_get_text(png_ptr, png_info_ptr, &text_ptr, NULL);
    for (i = 0; i < num_text; i++) {
      if (!memcmp(text_ptr[i].key, "XML:com.adobe.xmp", 17)) {
        /* XMP found */
        if (text_ptr[i].compression != PNG_ITXT_COMPRESSION_NONE ||
            text_ptr[i].itxt_length == 0)
          WARN("%s: Invalid value(s) in iTXt chunk for XMP Metadata.", PNG_DEBUG_STR);
        else if (have_XMP)
          WARN("%s: Multiple XMP Metadata. Don't know how to treat it.", PNG_DEBUG_STR);
        else {
          /* We compress XMP metadata for included images here.
           * It is not recommended to compress XMP metadata for PDF documents but
           * we compress XMP metadata for included images here to avoid confusing
           * application programs that only want PDF document global XMP metadata
           * and scan for that.
           */
          XMP_stream = pdf_new_stream(STREAM_COMPRESS);
          XMP_stream_dict = pdf_stream_dict(XMP_stream);
          pdf_add_dict(XMP_stream_dict,
                       pdf_new_name("Type"), pdf_new_name("Metadata"));
          pdf_add_dict(XMP_stream_dict,
                       pdf_new_name("Subtype"), pdf_new_name("XML"));
          pdf_add_stream(XMP_stream, text_ptr[i].text, text_ptr[i].itxt_length);
          pdf_add_dict(stream_dict,
                       pdf_new_name("Metadata"), pdf_ref_obj(XMP_stream));
          pdf_release_obj(XMP_stream);
          have_XMP = 1;
        }
      }
    }
  }
#endif /* PNG_LIBPNG_VER */

  png_read_end(png_ptr, NULL);

  /* Cleanup */
  if (png_info_ptr)
    png_destroy_info_struct(png_ptr, &png_info_ptr);
  if (png_ptr)
    png_destroy_read_struct(&png_ptr, NULL, NULL);
  if (color_type != PNG_COLOR_TYPE_PALETTE &&
      info.bits_per_component >= 8 &&
      info.height > 64) {
    pdf_stream_set_predictor(stream, 15, info.width,
                             info.bits_per_component, info.num_components);
  }
  pdf_ximage_set_image(ximage, &info, stream);

  return 0;
}
Beispiel #3
0
int
SplashDecodePng(Splash * splash, png_rw_ptr read_func, void *io_ptr)
{
    int stride;
    ImageFormat srcFormat;
    png_uint_32 i, rowbytes;
    png_bytepp row_pointers = NULL;
    png_bytep image_data = NULL;
    int success = 0;
    double gamma;

    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;

    png_uint_32 width, height;
    int bit_depth, color_type;

    ImageRect srcRect, dstRect;

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {
        goto done;
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        goto done;
    }

    if (setjmp(png_ptr->jmpbuf)) {
        goto done;
    }

    png_ptr->io_ptr = io_ptr;
    png_ptr->read_data_fn = read_func;

    png_set_sig_bytes(png_ptr, SIG_BYTES);      /* we already read the 8 signature bytes */

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

    png_get_IHDR(png_ptr, info_ptr, &width, &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]
     * this may be sub-optimal but this simplifies implementation */

    png_set_expand(png_ptr);
    png_set_tRNS_to_alpha(png_ptr);
    png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
    png_set_strip_16(png_ptr);
    png_set_gray_to_rgb(png_ptr);

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

    png_read_update_info(png_ptr, info_ptr);

    rowbytes = png_get_rowbytes(png_ptr, info_ptr);

    if (!SAFE_TO_ALLOC(rowbytes, height)) {
        goto done;
    }

    if ((image_data = (unsigned char *) malloc(rowbytes * height)) == NULL) {
        goto done;
    }

    if (!SAFE_TO_ALLOC(height, sizeof(png_bytep))) {
        goto done;
    }
    if ((row_pointers = (png_bytepp) malloc(height * sizeof(png_bytep)))
            == NULL) {
        goto done;
    }

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

    png_read_image(png_ptr, row_pointers);

    SplashCleanup(splash);

    splash->width = width;
    splash->height = height;

    if (!SAFE_TO_ALLOC(splash->width, splash->imageFormat.depthBytes)) {
        goto done;
    }
    stride = splash->width * splash->imageFormat.depthBytes;

    if (!SAFE_TO_ALLOC(splash->height, stride)) {
        goto done;
    }
    splash->frameCount = 1;
    splash->frames = (SplashImage *)
        malloc(sizeof(SplashImage) * splash->frameCount);

    if (splash->frames == NULL) {
        goto done;
    }

    splash->loopCount = 1;
    splash->frames[0].bitmapBits = malloc(stride * splash->height);
    if (splash->frames[0].bitmapBits == NULL) {
        free(splash->frames);
        goto done;
    }
    splash->frames[0].delay = 0;

    /* FIXME: sort out the real format */
    initFormat(&srcFormat, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
    srcFormat.byteOrder = BYTE_ORDER_MSBFIRST;

    initRect(&srcRect, 0, 0, width, height, 1, rowbytes,
        image_data, &srcFormat);
    initRect(&dstRect, 0, 0, width, height, 1, stride,
        splash->frames[0].bitmapBits, &splash->imageFormat);
    convertRect(&srcRect, &dstRect, CVT_COPY);

    SplashInitFrameShape(splash, 0);

    png_read_end(png_ptr, NULL);
    success = 1;

  done:
    free(row_pointers);
    free(image_data);
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    return success;
}
Beispiel #4
0
RImage *RLoadPNG(RContext *context, const char *file)
{
	char *tmp;
	RImage *image = NULL;
	FILE *f;
	png_structp png;
	png_infop pinfo, einfo;
	png_color_16p bkcolor;
	int alpha;
	int x, y, i;
	double gamma, sgamma;
	png_uint_32 width, height;
	int depth, junk, color_type;
	png_bytep *png_rows;
	unsigned char *ptr;

	f = fopen(file, "rb");
	if (!f) {
		RErrorCode = RERR_OPEN;
		return NULL;
	}
	png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, (png_error_ptr) NULL, (png_error_ptr) NULL);
	if (!png) {
		RErrorCode = RERR_NOMEMORY;
		fclose(f);
		return NULL;
	}

	pinfo = png_create_info_struct(png);
	if (!pinfo) {
		RErrorCode = RERR_NOMEMORY;
		fclose(f);
		png_destroy_read_struct(&png, NULL, NULL);
		return NULL;
	}

	einfo = png_create_info_struct(png);
	if (!einfo) {
		RErrorCode = RERR_NOMEMORY;
		fclose(f);
		png_destroy_read_struct(&png, &pinfo, NULL);
		return NULL;
	}

	RErrorCode = RERR_INTERNAL;
#if PNG_LIBPNG_VER - 0 < 10400
	if (setjmp(png->jmpbuf)) {
#else
	if (setjmp(png_jmpbuf(png))) {
#endif
		fclose(f);
		png_destroy_read_struct(&png, &pinfo, &einfo);
		if (image)
			RReleaseImage(image);
		return NULL;
	}

	png_init_io(png, f);

	png_read_info(png, pinfo);

	png_get_IHDR(png, pinfo, &width, &height, &depth, &color_type, &junk, &junk, &junk);

	/* sanity check */
	if (width < 1 || height < 1) {
		fclose(f);
		png_destroy_read_struct(&png, &pinfo, &einfo);
		RErrorCode = RERR_BADIMAGEFILE;
		return NULL;
	}

	/* check for an alpha channel */
	if (png_get_valid(png, pinfo, PNG_INFO_tRNS))
		alpha = True;
	else
		alpha = (color_type & PNG_COLOR_MASK_ALPHA);

	/* allocate RImage */
	image = RCreateImage(width, height, alpha);
	if (!image) {
		fclose(f);
		png_destroy_read_struct(&png, &pinfo, &einfo);
		return NULL;
	}

	/* normalize to 8bpp with alpha channel */
	if (color_type == PNG_COLOR_TYPE_PALETTE && depth <= 8)
		png_set_expand(png);

	if (color_type == PNG_COLOR_TYPE_GRAY && depth <= 8)
		png_set_expand(png);

	if (png_get_valid(png, pinfo, PNG_INFO_tRNS))
		png_set_expand(png);

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

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

	/* set gamma correction */
	if ((context->attribs->flags & RC_GammaCorrection)
	    && context->depth != 8) {
		sgamma = (context->attribs->rgamma + context->attribs->ggamma + context->attribs->bgamma) / 3;
	} else if ((tmp = getenv("DISPLAY_GAMMA")) != NULL) {
		sgamma = atof(tmp);
		if (sgamma < 1.0E-3)
			sgamma = 1;
	} else {
		/* blah */
		sgamma = 2.2;
	}

	if (png_get_gAMA(png, pinfo, &gamma))
		png_set_gamma(png, sgamma, gamma);
	else
		png_set_gamma(png, sgamma, 0.45);

	/* do the transforms */
	png_read_update_info(png, pinfo);

	/* set background color */
	if (png_get_bKGD(png, pinfo, &bkcolor)) {
		image->background.red = bkcolor->red >> 8;
		image->background.green = bkcolor->green >> 8;
		image->background.blue = bkcolor->blue >> 8;
	}

	png_rows = calloc(height, sizeof(char *));
	if (!png_rows) {
		RErrorCode = RERR_NOMEMORY;
		fclose(f);
		RReleaseImage(image);
		png_destroy_read_struct(&png, &pinfo, &einfo);
		return NULL;
	}
	for (y = 0; y < height; y++) {
		png_rows[y] = malloc(png_get_rowbytes(png, pinfo));
		if (!png_rows[y]) {
			RErrorCode = RERR_NOMEMORY;
			fclose(f);
			RReleaseImage(image);
			png_destroy_read_struct(&png, &pinfo, &einfo);
			while (y-- > 0)
				if (png_rows[y])
					free(png_rows[y]);
			free(png_rows);
			return NULL;
		}
	}
	/* read data */
	png_read_image(png, png_rows);

	png_read_end(png, einfo);

	png_destroy_read_struct(&png, &pinfo, &einfo);

	fclose(f);

	ptr = image->data;

	/* convert to RImage */
	if (alpha) {
		for (y = 0; y < height; y++) {
			for (x = 0, i = width * 4; x < i; x++, ptr++) {
				*ptr = *(png_rows[y] + x);
			}
		}
	} else {
		for (y = 0; y < height; y++) {
			for (x = 0, i = width * 3; x < i; x++, ptr++) {
				*ptr = *(png_rows[y] + x);
			}
		}
	}
	for (y = 0; y < height; y++)
		if (png_rows[y])
			free(png_rows[y]);
	free(png_rows);
	return image;
}
BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, BOOL raw, BOOL alpha)
{
  png_struct    *png_ptr = NULL;
  png_info	*info_ptr = NULL;
  png_byte      buf[8];
  png_byte      *png_pixels = NULL;
  png_byte      **row_pointers = NULL;
  png_byte      *pix_ptr = NULL;
  png_uint_32   row_bytes;

  png_uint_32   width;
  png_uint_32   height;
  int           bit_depth;
  int           channels;
  int           color_type;
  int           alpha_present;
  int           row, col;
  int           ret;
  int           i;
  long          dep_16;

  /* read and check signature in PNG file */
  ret = fread (buf, 1, 8, png_file);
  if (ret != 8)
    return FALSE;

  ret = !png_sig_cmp (buf, 0, 8);
  if (!ret)
    return FALSE;

  /* create png and info structures */

  png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
    NULL, NULL, NULL);
  if (!png_ptr)
    return FALSE;   /* out of memory */

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

  if (setjmp (png_jmpbuf(png_ptr)))
  {
    png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
    return FALSE;
  }

  /* set up the input control for C streams */
  png_init_io (png_ptr, png_file);
  png_set_sig_bytes (png_ptr, 8);  /* we already read the 8 signature bytes */

  /* read the file information */
  png_read_info (png_ptr, info_ptr);

  /* get size and bit-depth of the PNG-image */
  png_get_IHDR (png_ptr, info_ptr,
    &width, &height, &bit_depth, &color_type,
    NULL, NULL, NULL);

  /* set-up the transformations */

  /* transform paletted images into full-color rgb */
  if (color_type == PNG_COLOR_TYPE_PALETTE)
    png_set_expand (png_ptr);
  /* expand images to bit-depth 8 (only applicable for grayscale images) */
  if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    png_set_expand (png_ptr);
  /* transform transparency maps into full alpha-channel */
  if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
    png_set_expand (png_ptr);

#ifdef NJET
  /* downgrade 16-bit images to 8 bit */
  if (bit_depth == 16)
    png_set_strip_16 (png_ptr);
  /* transform grayscale images into full-color */
  if (color_type == PNG_COLOR_TYPE_GRAY ||
    color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    png_set_gray_to_rgb (png_ptr);
  /* only if file has a file gamma, we do a correction */
  if (png_get_gAMA (png_ptr, info_ptr, &file_gamma))
    png_set_gamma (png_ptr, (double) 2.2, file_gamma);
#endif

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

  /* get the new color-type and bit-depth (after expansion/stripping) */
  png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
    NULL, NULL, NULL);

  /* check for 16-bit files */
  if (bit_depth == 16)
  {
    raw = FALSE;
#ifdef __TURBOC__
    pnm_file->flags &= ~((unsigned) _F_BIN);
#endif
  }

  /* calculate new number of channels and store alpha-presence */
  if (color_type == PNG_COLOR_TYPE_GRAY)
    channels = 1;
  else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    channels = 2;
  else if (color_type == PNG_COLOR_TYPE_RGB)
    channels = 3;
  else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
    channels = 4;
  else
    channels = 0; /* should never happen */
  alpha_present = (channels - 1) % 2;

  /* check if alpha is expected to be present in file */
  if (alpha && !alpha_present)
  {
    fprintf (stderr, "PNG2PNM\n");
    fprintf (stderr, "Error:  PNG-file doesn't contain alpha channel\n");
    exit (1);
  }

  /* row_bytes is the width x number of channels x (bit-depth / 8) */
  row_bytes = png_get_rowbytes (png_ptr, info_ptr);

  if ((png_pixels = (png_byte *) malloc (row_bytes * height * sizeof (png_byte))) == NULL) {
    png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
    return FALSE;
  }

  if ((row_pointers = (png_byte **) malloc (height * sizeof (png_bytep))) == NULL)
  {
    png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
    free (png_pixels);
    png_pixels = NULL;
    return FALSE;
  }

  /* set the individual row_pointers to point at the correct offsets */
  for (i = 0; i < (height); i++)
    row_pointers[i] = png_pixels + i * row_bytes;

  /* now we can go ahead and just read the whole image */
  png_read_image (png_ptr, row_pointers);

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

  /* clean up after the read, and free any memory allocated - REQUIRED */
  png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp) NULL);

  /* write header of PNM file */

  if ((color_type == PNG_COLOR_TYPE_GRAY) ||
      (color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
  {
    fprintf (pnm_file, "%s\n", (raw) ? "P5" : "P2");
    fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
    fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
  }
  else if ((color_type == PNG_COLOR_TYPE_RGB) ||
           (color_type == PNG_COLOR_TYPE_RGB_ALPHA))
  {
    fprintf (pnm_file, "%s\n", (raw) ? "P6" : "P3");
    fprintf (pnm_file, "%d %d\n", (int) width, (int) height);
    fprintf (pnm_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
  }

  /* write header of PGM file with alpha channel */

  if ((alpha) &&
      ((color_type == PNG_COLOR_TYPE_GRAY_ALPHA) ||
       (color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
  {
    fprintf (alpha_file, "%s\n", (raw) ? "P5" : "P2");
    fprintf (alpha_file, "%d %d\n", (int) width, (int) height);
    fprintf (alpha_file, "%ld\n", ((1L << (int) bit_depth) - 1L));
  }

  /* write data to PNM file */
  pix_ptr = png_pixels;

  for (row = 0; row < height; row++)
  {
    for (col = 0; col < width; col++)
    {
      for (i = 0; i < (channels - alpha_present); i++)
      {
        if (raw)
          fputc ((int) *pix_ptr++ , pnm_file);
        else
          if (bit_depth == 16){
	    dep_16 = (long) *pix_ptr++;
            fprintf (pnm_file, "%ld ", (dep_16 << 8) + ((long) *pix_ptr++));
          }
          else
            fprintf (pnm_file, "%ld ", (long) *pix_ptr++);
      }
      if (alpha_present)
      {
        if (!alpha)
        {
          pix_ptr++; /* alpha */
          if (bit_depth == 16)
            pix_ptr++;
        }
        else /* output alpha-channel as pgm file */
        {
          if (raw)
            fputc ((int) *pix_ptr++ , alpha_file);
          else
            if (bit_depth == 16){
	      dep_16 = (long) *pix_ptr++;
              fprintf (alpha_file, "%ld ", (dep_16 << 8) + (long) *pix_ptr++);
	    }  
            else
              fprintf (alpha_file, "%ld ", (long) *pix_ptr++);
        }
      } /* if alpha_present */

      if (!raw)
        if (col % 4 == 3)
          fprintf (pnm_file, "\n");
    } /* end for col */

    if (!raw)
      if (col % 4 != 0)
        fprintf (pnm_file, "\n");
  } /* end for row */

  if (row_pointers != (unsigned char**) NULL)
    free (row_pointers);
  if (png_pixels != (unsigned char*) NULL)
    free (png_pixels);

  return TRUE;

} /* end of source */
Beispiel #6
0
unsigned char *
ReadPNG(FILE *infile,int *width, int *height, XColor *colrs)
{

    unsigned char *pixmap;
    unsigned char *p;
    png_byte *q;

    png_struct *png_ptr;
    png_info *info_ptr;

    png_uint_32 raw_width, raw_height, rowbytes;
    int bit_depth, color_type, interlace_type, compression_type, filter_type;

    png_uint_32 have_palette;
    png_colorp palette;
    int num_palette;
    png_uint_16p hist = NULL;

    double gamma, screen_gamma;

    png_byte *png_pixels=NULL, **row_pointers=NULL;
    int i, j;

    unsigned int packets;

    png_color std_color_cube[216];

    
        /* first check to see if its a valid PNG file. If not, return. */
        /* we assume that infile is a valid filepointer */
    {
        int ret;
        png_byte buf[8];
        
        ret = fread(buf, 1, 8, infile);
        
        if(ret != 8)
            return 0;
        
        ret = png_sig_cmp(buf, 0, 8);
        
        if(ret)
            return(0);
    }

        /* OK, it is a valid PNG file, so let's rewind it, and start 
           decoding it */
    rewind(infile);

        /* allocate the structures */
    /*png_ptr = (png_struct *)malloc(sizeof(png_struct));*/
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if(!png_ptr)
        return 0;

    /* initialize the structures */
    info_ptr = png_create_info_struct(png_ptr);
    if(!info_ptr) {
        /*free(png_ptr);*/
        return 0;
    }

        /* Establish the setjmp return context for png_error to use. */
    if (setjmp(png_jmpbuf(png_ptr))) {
        
#ifndef DISABLE_TRACE
        if (srcTrace) {
            fprintf(stderr, "\n!!!libpng read error!!!\n");
        }
#endif

        /*png_read_destroy(png_ptr, info_ptr, (png_info *)0); */
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

        if(png_pixels != NULL)
            free((char *)png_pixels);
        if(row_pointers != NULL)
            free((png_byte **)row_pointers);
                
        /*free((char *)png_ptr);*/
        free((char *)info_ptr);
        
        return 0;
    }

#ifdef SAM_NO
    /* SWP -- Hopefully to fix cores on bad PNG files */
    png_set_message_fn(png_ptr,png_get_msg_ptr(png_ptr),NULL,NULL); 
#endif

    /*png_read_init(png_ptr);*/
    
        /* set up the input control */
    png_init_io(png_ptr, infile);
    
        /* read the file information */
    png_read_info(png_ptr, info_ptr);
    
        /* setup other stuff using the fields of png_info. */
    
    png_get_IHDR(png_ptr, info_ptr, &raw_width, &raw_height, &bit_depth,
                 &color_type, &interlace_type, &compression_type,
                 &filter_type);
    rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    have_palette = png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);

    *width = (int)raw_width;
    *height = (int)raw_height;

#ifndef DISABLE_TRACE
    if (srcTrace) {
        fprintf(stderr,"\n\nBEFORE\nwidth = %d\n", *width);
        fprintf(stderr,"height = %d\n", *height);
        fprintf(stderr,"bit depth = %d\n", bit_depth);
        fprintf(stderr,"color type = %d\n", color_type);
        fprintf(stderr,"compression type = %d\n", compression_type);
        fprintf(stderr,"filter type = %d\n", filter_type);
        fprintf(stderr,"interlace type = %d\n", interlace_type);
        fprintf(stderr,"num colors = %d\n", num_palette);
        fprintf(stderr,"rowbytes = %d\n", rowbytes);
    }
#endif


#if 0
        /* This handles alpha and transparency by replacing it with 
           a background value. */
        /* its #if'ed out for now cause I don't have anything to 
           test it with */
    {
        png_color_16 my_background;
	
        if (info_ptr->valid & PNG_INFO_bKGD)
            png_set_background(png_ptr, &(info_ptr->background),
                               PNG_GAMMA_FILE, 1, 1.0);
        else
            png_set_background(png_ptr, &my_background,
                               PNG_GAMMA_SCREEN, 0, 1.0);
    }
#endif

        /* strip pixels in 16-bit images down to 8 bits */
    if (bit_depth == 16)
        png_set_strip_16(png_ptr);


        /* If it is a color image then check if it has a palette. If not
           then dither the image to 256 colors, and make up a palette */
    if (color_type==PNG_COLOR_TYPE_RGB ||
        color_type==PNG_COLOR_TYPE_RGB_ALPHA) {

        if(!have_palette) {

#ifndef DISABLE_TRACE
            if (srcTrace) {
                fprintf(stderr,"dithering (RGB->palette)...\n");
            }
#endif
                /* if there is is no valid palette, then we need to make
                   one up */
            for(i=0;i<216;i++) {
                    /* 255.0/5 = 51 */
                std_color_cube[i].red=(i%6)*51;
                std_color_cube[i].green=((i/6)%6)*51;
                std_color_cube[i].blue=(i/36)*51;
            }

                /* this should probably be dithering to 
                   Rdata.colors_per_inlined_image colors */
            png_set_quantize(png_ptr, std_color_cube, 216, 216, NULL, 1);
            
        } else {
#ifndef DISABLE_TRACE
            if (srcTrace) {
                fprintf(stderr,"dithering (RGB->file supplied palette)...\n");
            }
#endif
 
            png_get_hIST(png_ptr, info_ptr, &hist);
            png_set_quantize(png_ptr, palette, num_palette,
                             get_pref_int(eCOLORS_PER_INLINED_IMAGE), hist, 1);
            
        }
    }

        /* PNG files pack pixels of bit depths 1, 2, and 4 into bytes as
           small as they can. This expands pixels to 1 pixel per byte, and
           if a transparency value is supplied, an alpha channel is
           built.*/
    if (bit_depth < 8)
        png_set_packing(png_ptr);


        /* have libpng handle the gamma conversion */

    if (get_pref_boolean(eUSE_SCREEN_GAMMA)) { /*SWP*/
        if (bit_depth != 16) {  /* temporary .. glennrp */
            screen_gamma=(double)(get_pref_float(eSCREEN_GAMMA));
            
#ifndef DISABLE_TRACE
            if (srcTrace) {
                fprintf(stderr,"screen gamma=%f\n",screen_gamma);
            }
#endif
            if (png_get_gAMA(png_ptr, info_ptr, &gamma)) {
#ifndef DISABLE_TRACE
                if (srcTrace) {
                    printf("setting gamma=%f\n", gamma);
                }
#endif
                png_set_gamma(png_ptr, screen_gamma, gamma);
            }
            else {
#ifndef DISABLE_TRACE
                if (srcTrace) {
                    fprintf(stderr,"setting gamma=%f\n",0.45);
                }
#endif
                png_set_gamma(png_ptr, screen_gamma, (double)0.45);
            }
        }
    }
    
    if (interlace_type)
        png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);
    
    png_get_IHDR(png_ptr, info_ptr, &raw_width, &raw_height, &bit_depth,
                 &color_type, &interlace_type, &compression_type,
                 &filter_type);
    rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    have_palette = png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);

#ifndef DISABLE_TRACE
    if (srcTrace) {
        fprintf(stderr,"\n\nAFTER\nwidth = %d\n", *width);
        fprintf(stderr,"height = %d\n", *height);
        fprintf(stderr,"bit depth = %d\n", bit_depth);
        fprintf(stderr,"color type = %d\n", color_type);
        fprintf(stderr,"compression type = %d\n", compression_type);
        fprintf(stderr,"filter type = %d\n", filter_type);
        fprintf(stderr,"interlace type = %d\n", interlace_type);
        fprintf(stderr,"num colors = %d\n",num_palette);
        fprintf(stderr,"rowbytes = %d\n", rowbytes);
    }
#endif

        /* allocate the pixel grid which we will need to send to 
           png_read_image(). */
    png_pixels = (png_byte *)malloc(rowbytes * (*height) * sizeof(png_byte));
    

    row_pointers = (png_byte **) malloc((*height) * sizeof(png_byte *));
    for (i=0; i < *height; i++)
        row_pointers[i]=png_pixels+(rowbytes*i);

    
        /* FINALLY - read the darn thing. */
    png_read_image(png_ptr, row_pointers);
    
    
        /* now that we have the (transformed to 8-bit RGB) image, we have
           to copy the resulting palette to our colormap. */
    if (color_type & PNG_COLOR_MASK_COLOR) {
        if (have_palette) {
            
            for (i=0; i < num_palette; i++) {
                colrs[i].red = palette[i].red << 8;
                colrs[i].green = palette[i].green << 8;
                colrs[i].blue = palette[i].blue << 8;
                colrs[i].pixel = i;
                colrs[i].flags = DoRed|DoGreen|DoBlue;
            }
            
        }
        else {
            for (i=0; i < 216; i++) {
                colrs[i].red = std_color_cube[i].red << 8;
                colrs[i].green = std_color_cube[i].green << 8;
                colrs[i].blue = std_color_cube[i].blue << 8;
                colrs[i].pixel = i;
                colrs[i].flags = DoRed|DoGreen|DoBlue;
            }	    
        }
    } else {
            /* grayscale image */
        
        for(i=0; i < 256; i++ ) {
            colrs[i].red = i << 8;
            colrs[i].green = i << 8; 	    
            colrs[i].blue = i << 8;
            colrs[i].pixel = i;
            colrs[i].flags = DoRed|DoGreen|DoBlue;    
        }
    }
    
        /* Now copy the pixel data from png_pixels to pixmap */
 
    pixmap = (png_byte *)malloc((*width) * (*height) * sizeof(png_byte));
    
    p = pixmap; q = png_pixels;

        /* if there is an alpha channel, we have to get rid of it in the
           pixmap, since I don't do anything with it yet */
    if (color_type & PNG_COLOR_MASK_ALPHA) {

#ifndef DISABLE_TRACE
        if (srcTrace) {
            fprintf(stderr,"Getting rid of alpha channel\n");
        }
#endif
        for(i=0; i<*height; i++) {
            q = row_pointers[i];
            for(j=0; j<*width; j++) {
                *p++ = *q++; /*palette index*/
                q++; /* skip the alpha pixel */
            }
        }
        
        free((char *)png_pixels);
    }
    else {
        
#ifndef DISABLE_TRACE
        if (srcTrace) {
            fprintf(stderr,"No alpha channel\n");
        }
#endif
        
        for(i=0; i<*height; i++) {
            q = row_pointers[i];
            for(j=0; j<*width; j++) {
                *p++ = *q++; /*palette index*/
            }
        }
        
        free((char *)png_pixels);
        
    }

    free((png_byte **)row_pointers);
    
        /* clean up after the read, and free any memory allocated */
    /*png_read_destroy(png_ptr, info_ptr, (png_info *)0);*/
	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    

        /* free the structures */
    /*free((char *)png_ptr);*/
    free((char *)info_ptr);
    
    return pixmap;
}
static
void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, 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;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 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;
        }
        if (image.size() != QSize(width, height) || image.format() != format) {
            image = QImage(width, height, 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);
    }
}
Beispiel #8
0
CDibSection* InformApp::GetImage(const char* path)
{
  // Check if it's a PNG file
  CStdioFile imageFile;
  if (!imageFile.Open(path,CFile::modeRead|CFile::typeBinary))
    return 0;
  png_byte fileHeader[8];
  imageFile.Read(fileHeader,8);
  bool isPNG = (png_sig_cmp(fileHeader,0,8) == 0);

  if (isPNG)
  {
    // Prepare to read the PNG file
    png_structp png_ptr = png_create_read_struct
      (PNG_LIBPNG_VER_STRING,(png_voidp)NULL,NULL,NULL);
    if (png_ptr == NULL)
      return 0;
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL)
    {
      png_destroy_read_struct(&png_ptr,(png_infopp)NULL,(png_infopp)NULL);
      return 0;
    }
    png_infop end_info = png_create_info_struct(png_ptr);
    if (end_info == NULL)
    {
      png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)NULL);
      return 0;
    }

    // Set up the point to return to in case of error
    png_bytep* rowPointers = NULL;
    if (setjmp(png_jmpbuf(png_ptr)))
    {
      if (rowPointers)
        delete[] rowPointers;
      png_destroy_read_struct(&png_ptr,&info_ptr,&end_info);
      return 0;
    }

    png_init_io(png_ptr,imageFile.m_pStream);
    png_set_sig_bytes(png_ptr,8);
    png_read_info(png_ptr,info_ptr);

    // Get details of the image
    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);
    int color_type = png_get_color_type(png_ptr,info_ptr);

    // Set up transforms to the required format
    if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8)
      png_set_palette_to_rgb(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
      png_set_expand_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);
    double gamma;
    if (png_get_gAMA(png_ptr,info_ptr,&gamma))
      png_set_gamma(png_ptr,2.2,gamma);
    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);
    png_set_bgr(png_ptr);
    png_set_filler(png_ptr,0xFF,PNG_FILLER_AFTER);

    // Create a bitmap
    HDC dc = ::GetDC(NULL);
    CDibSection* dib = new CDibSection();
    BOOL created = dib->CreateBitmap(dc,width,height);
    ::ReleaseDC(NULL,dc);
    if (!created)
    {
      png_destroy_read_struct(&png_ptr,&info_ptr,&end_info);
      return NULL;
    }

    // Read in the image
    rowPointers = new png_bytep[height];
    for (int i = 0; i < (int)height; i++)
      rowPointers[i] = ((png_bytep)dib->GetBits())+(width*i*4);
    png_read_image(png_ptr,rowPointers);
    png_read_end(png_ptr,end_info);
    delete[] rowPointers;

    png_destroy_read_struct(&png_ptr,&info_ptr,&end_info);
    return dib;
  }
  else
  {
    imageFile.SeekToBegin();

    struct jpeg_decompress_struct info;
    struct JPEGErrorInfo error;

    // Initialize the error handling
    info.err = jpeg_std_error(&(error.base));
    error.base.error_exit = errorJPEGExit;
    error.base.output_message = outputJPEGMessage;
    if (setjmp(error.errorJump))
    {
      jpeg_destroy_decompress(&info);
      return NULL;
    }

    // Set up the decompression
    jpeg_create_decompress(&info);
    jpeg_stdio_src(&info,imageFile.m_pStream);

    // Read the image attributes
    jpeg_read_header(&info,TRUE);
    jpeg_calc_output_dimensions(&info);
    int width = info.output_width;
    int height = info.output_height;

    // Force RGB output
    info.out_color_space = JCS_RGB;

    // Create a bitmap
    HDC dc = ::GetDC(NULL);
    CDibSection* dib = new CDibSection();
    BOOL created = dib->CreateBitmap(dc,width,height);
    ::ReleaseDC(NULL,dc);
    if (!created)
    {
      jpeg_destroy_decompress(&info);
      return NULL;
    }

    // Get an output buffer
    JSAMPARRAY buffer = (*info.mem->alloc_sarray)
      ((j_common_ptr)&info,JPOOL_IMAGE,width*3,1);

    // Read in the image
    jpeg_start_decompress(&info);
    while ((int)info.output_scanline < height)
    {
      jpeg_read_scanlines(&info,buffer,1);

      BYTE* pixelRow = ((BYTE*)dib->GetBits())+(width*(info.output_scanline-1)*4);
      for (int i = 0; i < width; i++)
      {
        pixelRow[(i*4)+0] = (*buffer)[(i*3)+2];
        pixelRow[(i*4)+1] = (*buffer)[(i*3)+1];
        pixelRow[(i*4)+2] = (*buffer)[(i*3)+0];
        pixelRow[(i*4)+3] = 0xFF;
      }
    }
    jpeg_finish_decompress(&info);
    jpeg_destroy_decompress(&info);
    return dib;
  }
}
Beispiel #9
0
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 PNGs. See http://bugzil.la/251381 for more details.
    const unsigned long maxPNGSize = 1000000UL;
    if (width > maxPNGSize || height > maxPNGSize) {
        longjmp(JMPBUF(png), 1);
        return;
    }

    // Set the image size now that the image header is available.
    if (!setSize(width, height)) {
        longjmp(JMPBUF(png), 1);
        return;
    }

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

    // 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);

#if USE(QCMSLIB)
    if ((colorType & PNG_COLOR_MASK_COLOR) && !m_ignoreGammaAndColorProfile) {
        // We only support color profiles for color PALETTE and RGB[A] PNG. 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
        // do not 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.
        bool sRGB = false;
        ColorProfile colorProfile;
        getColorProfile(png, info, colorProfile, sRGB);
        bool imageHasAlpha = (colorType & PNG_COLOR_MASK_ALPHA) || trnsCount;
        m_reader->createColorTransform(colorProfile, imageHasAlpha, sRGB);
        m_hasColorProfile = !!m_reader->colorTransform();
    }
#endif

    if (!m_hasColorProfile) {
        // Deal with gamma and keep it under our control.
        const double inverseGamma = 0.45455;
        const double defaultGamma = 2.2;
        double gamma;
        if (!m_ignoreGammaAndColorProfile && png_get_gAMA(png, info, &gamma)) {
            const double maxGamma = 21474.83;
            if ((gamma <= 0.0) || (gamma > maxGamma)) {
                gamma = inverseGamma;
                png_set_gAMA(png, info, gamma);
            }
            png_set_gamma(png, defaultGamma, gamma);
        } else {
            png_set_gamma(png, defaultGamma, inverseGamma);
        }
    }

    // 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 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
    }
}
Beispiel #10
0
static
void setup_qt( QImage& image, png_structp png_ptr, png_infop info_ptr )
{
    if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA) ) {
	double file_gamma;
	png_get_gAMA(png_ptr, info_ptr, &file_gamma);
#if defined(_OS_MAC_)
	// a good guess for Mac systems
	png_set_gamma( png_ptr, 1.7, file_gamma );
#else
	// a good guess for PC monitors in a bright office or a dim room
	png_set_gamma( png_ptr, 2.2, file_gamma );
#endif
    }

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

    if ( color_type == PNG_COLOR_TYPE_GRAY ) {
	// Black & White or 8-bit greyscale
	if ( bit_depth == 1 && info_ptr->channels == 1 ) {
	    png_set_invert_mono( png_ptr );
	    png_read_update_info( png_ptr, info_ptr );
	    image.create( width, height, 1, 2, QImage::BigEndian );
	    image.setColor( 1, qRgb(0,0,0) );
	    image.setColor( 0, qRgb(255,255,255) );
	} 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);
	    image.create(width, height, 8, 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_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ) {
		int g = info_ptr->trans_values.gray;
		if ( bit_depth > 8 ) {
		    // transparency support disabled for now
		} else {
		    image.setAlphaBuffer( TRUE );
		    image.setColor(g, RGB_MASK & image.color(g));
		}
	    }
	}
    } else if ( color_type == PNG_COLOR_TYPE_PALETTE
     && png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)
     && info_ptr->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);
	image.create(width, height, bit_depth, info_ptr->num_palette,
	    QImage::BigEndian);
	int i = 0;
	if ( png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ) {
	    image.setAlphaBuffer( TRUE );
	    while ( i < info_ptr->num_trans ) {
		image.setColor(i, qRgba(
		    info_ptr->palette[i].red,
		    info_ptr->palette[i].green,
		    info_ptr->palette[i].blue,
		    info_ptr->trans[i]
		    )
		);
		i++;
	    }
	}
	while ( i < info_ptr->num_palette ) {
	    image.setColor(i, qRgba(
		info_ptr->palette[i].red,
		info_ptr->palette[i].green,
		info_ptr->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);

	image.create(width, height, 32);

	// 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,
		QImage::systemByteOrder() == QImage::BigEndian ?
		    PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
	    // We want 4 bytes, but it isn't an alpha channel
	} else {
	    image.setAlphaBuffer(TRUE);
	}

	if ( QImage::systemByteOrder() == QImage::BigEndian ) {
	    png_set_swap_alpha(png_ptr);
	}

	png_read_update_info(png_ptr, info_ptr);
    }

    // Qt==ARGB==Big(ARGB)==Little(BGRA)
    if ( QImage::systemByteOrder() == QImage::LittleEndian ) {
	png_set_bgr(png_ptr);
    }
}
Beispiel #11
0
static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
    png_structp png_ptr = NULL;
    png_infop info_ptr;
    png_uint_32 width, height;
    png_colorp png_palette = NULL;
    int color_type, palette_entries = 0;
    int bit_depth, pixel_depth;		// pixel_depth = bit_depth * channels

    FIBITMAP *dib = NULL;
    RGBQUAD *palette = NULL;		// pointer to dib palette
    png_bytepp  row_pointers = NULL;
    int i;

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

    if (handle) {
        BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;

        try {
            // check to see if the file is in fact a PNG file

            BYTE png_check[PNG_BYTES_TO_CHECK];

            io->read_proc(png_check, PNG_BYTES_TO_CHECK, 1, handle);

            if (png_sig_cmp(png_check, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) {
                return NULL;	// Bad signature
            }

            // create the chunk manage structure

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

            if (!png_ptr) {
                return NULL;
            }

            // create the info structure

            info_ptr = png_create_info_struct(png_ptr);

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

            // init the IO

            png_set_read_fn(png_ptr, &fio, _ReadProc);

            if (setjmp(png_jmpbuf(png_ptr))) {
                png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
                return NULL;
            }

            // because we have already read the signature...

            png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);

            // read the IHDR chunk

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

            pixel_depth = png_get_bit_depth(png_ptr, info_ptr) * png_get_channels(png_ptr, info_ptr);

            // get image data type (assume standard image type)

            FREE_IMAGE_TYPE image_type = FIT_BITMAP;
            if (bit_depth == 16) {
                if ((pixel_depth == 16) && (color_type == PNG_COLOR_TYPE_GRAY)) {
                    image_type = FIT_UINT16;
                }
                else if ((pixel_depth == 48) && (color_type == PNG_COLOR_TYPE_RGB)) {
                    image_type = FIT_RGB16;
                }
                else if ((pixel_depth == 64) && (color_type == PNG_COLOR_TYPE_RGB_ALPHA)) {
                    image_type = FIT_RGBA16;
                } else {
                    // tell libpng to strip 16 bit/color files down to 8 bits/color
                    png_set_strip_16(png_ptr);
                    bit_depth = 8;
                }
            }

#ifndef FREEIMAGE_BIGENDIAN
            if((image_type == FIT_UINT16) || (image_type == FIT_RGB16) || (image_type == FIT_RGBA16)) {
                // turn on 16 bit byte swapping
                png_set_swap(png_ptr);
            }
#endif

            // set some additional flags

            switch(color_type) {
            case PNG_COLOR_TYPE_RGB:
            case PNG_COLOR_TYPE_RGB_ALPHA:
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
                // flip the RGB pixels to BGR (or RGBA to BGRA)

                if(image_type == FIT_BITMAP) {
                    png_set_bgr(png_ptr);
                }
#endif
                break;

            case PNG_COLOR_TYPE_PALETTE:
                // expand palette images to the full 8 bits from 2 bits/pixel

                if (pixel_depth == 2) {
                    png_set_packing(png_ptr);
                    pixel_depth = 8;
                }

                break;

            case PNG_COLOR_TYPE_GRAY:
                // expand grayscale images to the full 8 bits from 2 bits/pixel
                // but *do not* expand fully transparent palette entries to a full alpha channel

                if (pixel_depth == 2) {
                    png_set_expand_gray_1_2_4_to_8(png_ptr);
                    pixel_depth = 8;
                }

                break;

            case PNG_COLOR_TYPE_GRAY_ALPHA:
                // expand 8-bit greyscale + 8-bit alpha to 32-bit

                png_set_gray_to_rgb(png_ptr);
#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_BGR
                // flip the RGBA pixels to BGRA

                png_set_bgr(png_ptr);
#endif
                pixel_depth = 32;

                break;

            default:
                throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
            }

            // unlike the example in the libpng documentation, we have *no* idea where
            // this file may have come from--so if it doesn't have a file gamma, don't
            // do any correction ("do no harm")

            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_gAMA)) {
                double gamma = 0;
                double screen_gamma = 2.2;

                if (png_get_gAMA(png_ptr, info_ptr, &gamma) && ( flags & PNG_IGNOREGAMMA ) != PNG_IGNOREGAMMA) {
                    png_set_gamma(png_ptr, screen_gamma, gamma);
                }
            }

            // all transformations have been registered; now update info_ptr data

            png_read_update_info(png_ptr, info_ptr);

            // color type may have changed, due to our transformations

            color_type = png_get_color_type(png_ptr,info_ptr);

            // create a DIB and write the bitmap header
            // set up the DIB palette, if needed

            switch (color_type) {
            case PNG_COLOR_TYPE_RGB:
                png_set_invert_alpha(png_ptr);

                if(image_type == FIT_BITMAP) {
                    dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
                } else {
                    dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
                }
                break;

            case PNG_COLOR_TYPE_RGB_ALPHA:
                if(image_type == FIT_BITMAP) {
                    dib = FreeImage_AllocateHeader(header_only, width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
                } else {
                    dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);
                }
                break;

            case PNG_COLOR_TYPE_PALETTE:
                dib = FreeImage_AllocateHeader(header_only, width, height, pixel_depth);

                png_get_PLTE(png_ptr,info_ptr, &png_palette, &palette_entries);

                palette_entries = MIN((unsigned)palette_entries, FreeImage_GetColorsUsed(dib));
                palette = FreeImage_GetPalette(dib);

                // store the palette

                for (i = 0; i < palette_entries; i++) {
                    palette[i].rgbRed   = png_palette[i].red;
                    palette[i].rgbGreen = png_palette[i].green;
                    palette[i].rgbBlue  = png_palette[i].blue;
                }
                break;

            case PNG_COLOR_TYPE_GRAY:
                dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height, pixel_depth);

                if(pixel_depth <= 8) {
                    palette = FreeImage_GetPalette(dib);
                    palette_entries = 1 << pixel_depth;

                    for (i = 0; i < palette_entries; i++) {
                        palette[i].rgbRed   =
                            palette[i].rgbGreen =
                                palette[i].rgbBlue  = (BYTE)((i * 255) / (palette_entries - 1));
                    }
                }
                break;

            default:
                throw FI_MSG_ERROR_UNSUPPORTED_FORMAT;
            }

            // store the transparency table

            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
                // array of alpha (transparency) entries for palette
                png_bytep trans_alpha = NULL;
                // number of transparent entries
                int num_trans = 0;
                // graylevel or color sample values of the single transparent color for non-paletted images
                png_color_16p trans_color = NULL;

                png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color);

                if((color_type == PNG_COLOR_TYPE_GRAY) && trans_color) {
                    // single transparent color
                    if (trans_color->gray < palette_entries) {
                        BYTE table[256];
                        memset(table, 0xFF, palette_entries);
                        table[trans_color->gray] = 0;
                        FreeImage_SetTransparencyTable(dib, table, palette_entries);
                    }
                } else if((color_type == PNG_COLOR_TYPE_PALETTE) && trans_alpha) {
                    // transparency table
                    FreeImage_SetTransparencyTable(dib, (BYTE *)trans_alpha, num_trans);
                }
            }

            // store the background color

            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) {
                // Get the background color to draw transparent and alpha images over.
                // 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_16p image_background = NULL;
                RGBQUAD rgbBkColor;

                if (png_get_bKGD(png_ptr, info_ptr, &image_background)) {
                    rgbBkColor.rgbRed      = (BYTE)image_background->red;
                    rgbBkColor.rgbGreen    = (BYTE)image_background->green;
                    rgbBkColor.rgbBlue     = (BYTE)image_background->blue;
                    rgbBkColor.rgbReserved = 0;

                    FreeImage_SetBackgroundColor(dib, &rgbBkColor);
                }
            }

            // get physical resolution

            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
                png_uint_32 res_x, res_y;

                // we'll overload this var and use 0 to mean no phys data,
                // since if it's not in meters we can't use it anyway

                int res_unit_type = PNG_RESOLUTION_UNKNOWN;

                png_get_pHYs(png_ptr,info_ptr, &res_x, &res_y, &res_unit_type);

                if (res_unit_type == PNG_RESOLUTION_METER) {
                    FreeImage_SetDotsPerMeterX(dib, res_x);
                    FreeImage_SetDotsPerMeterY(dib, res_y);
                }
            }

            // get possible ICC profile

            if (png_get_valid(png_ptr, info_ptr, PNG_INFO_iCCP)) {
                png_charp profile_name = NULL;
                png_bytep profile_data = NULL;
                png_uint_32 profile_length = 0;
                int  compression_type;

                png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &profile_length);

                // copy ICC profile data (must be done after FreeImage_AllocateHeader)

                FreeImage_CreateICCProfile(dib, profile_data, profile_length);
            }

            // --- header only mode => clean-up and return

            if (header_only) {
                // get possible metadata (it can be located both before and after the image data)
                ReadMetadata(png_ptr, info_ptr, dib);
                if (png_ptr) {
                    // clean up after the read, and free any memory allocated - REQUIRED
                    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
                }
                return dib;
            }

            // set the individual row_pointers to point at the correct offsets

            row_pointers = (png_bytepp)malloc(height * sizeof(png_bytep));

            if (!row_pointers) {
                png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
                FreeImage_Unload(dib);
                return NULL;
            }

            // read in the bitmap bits via the pointer table
            // allow loading of PNG with minor errors (such as images with several IDAT chunks)

            for (png_uint_32 k = 0; k < height; k++) {
                row_pointers[height - 1 - k] = FreeImage_GetScanLine(dib, k);
            }

            png_set_benign_errors(png_ptr, 1);
            png_read_image(png_ptr, row_pointers);

            // check if the bitmap contains transparency, if so enable it in the header

            if (FreeImage_GetBPP(dib) == 32) {
                if (FreeImage_GetColorType(dib) == FIC_RGBALPHA) {
                    FreeImage_SetTransparent(dib, TRUE);
                } else {
                    FreeImage_SetTransparent(dib, FALSE);
                }
            }

            // cleanup

            if (row_pointers) {
                free(row_pointers);
                row_pointers = NULL;
            }

            // read the rest of the file, getting any additional chunks in info_ptr

            png_read_end(png_ptr, info_ptr);

            // get possible metadata (it can be located both before and after the image data)

            ReadMetadata(png_ptr, info_ptr, dib);

            if (png_ptr) {
                // clean up after the read, and free any memory allocated - REQUIRED
                png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
            }

            return dib;
        } catch (const char *text) {
            if (png_ptr) {
                png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
            }
            if (row_pointers) {
                free(row_pointers);
            }
            if (dib) {
                FreeImage_Unload(dib);
            }
            FreeImage_OutputMessageProc(s_format_id, text);

            return NULL;
        }
    }

    return NULL;
}
Beispiel #12
0
// load in the image data
Picture PictureLoaderPng::load( io::NFile file ) const
{
  if(!file.isOpen())
  {
    Logger::warning( "LOAD PNG: can't open file %s", file.getFileName().toString().c_str() );
    return Picture::getInvalid();
  }

  png_byte buffer[8];
  // Read the first few bytes of the PNG file
  if( file.read(buffer, 8) != 8 )
  {
    Logger::warning( "LOAD PNG: can't read file %s", file.getFileName().toString().c_str() );
    return Picture::getInvalid();
  }

  // Check if it really is a PNG file
  if( png_sig_cmp(buffer, 0, 8) )
  {
    Logger::warning( "LOAD PNG: not really a png %s", file.getFileName().toString().c_str() );
    return Picture::getInvalid();
  }

  // Allocate the png read struct
  png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
                                                NULL, (png_error_ptr)png_cpexcept_error,
                                                (png_error_ptr)png_cpexcept_warn);
  if( !png_ptr )
  {
    Logger::warning( "LOAD PNG: Internal PNG create read struct failure %s", file.getFileName().toString().c_str() );
    return Picture::getInvalid();
  }

  // Allocate the png info struct
  png_infop info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
  {
    Logger::warning( "LOAD PNG: Internal PNG create info struct failure 5s", file.getFileName().toString().c_str() );
    png_destroy_read_struct(&png_ptr, NULL, NULL);
    return Picture::getInvalid();
  }

  // for proper error handling
  if (setjmp(png_jmpbuf(png_ptr)))
  {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        /*
        if( RowPointers )
                                delete [] RowPointers;
                        */
        return Picture::getInvalid();
  }

  // changed by zola so we don't need to have public FILE pointers
  png_set_read_fn(png_ptr, &file, user_read_data_fcn);

  png_set_sig_bytes(png_ptr, 8); // Tell png that we read the signature

  png_read_info(png_ptr, info_ptr); // Read the info section of the png file

  unsigned int Width;
  unsigned int Height;
  int BitDepth;
  int ColorType;
  {
        // Use temporary variables to avoid passing casted pointers
        png_uint_32 w,h;
        // Extract info
        png_get_IHDR(png_ptr, info_ptr,
                &w, &h,
                &BitDepth, &ColorType, NULL, NULL, NULL);
        Width=w;
        Height=h;
  }

  // Convert palette color to true color
  if (ColorType==PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);

  // Convert low bit colors to 8 bit colors
  if (BitDepth < 8)
  {
        if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA)
                png_set_expand_gray_1_2_4_to_8(png_ptr);
        else
                png_set_packing(png_ptr);
  }

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

  // Convert high bit colors to 8 bit colors
  if (BitDepth == 16)
        png_set_strip_16(png_ptr);

  // Convert gray color to true color
  if (ColorType==PNG_COLOR_TYPE_GRAY || ColorType==PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);

  int intent;
  const double screen_gamma = 2.2;

  if (png_get_sRGB(png_ptr, info_ptr, &intent))
        png_set_gamma(png_ptr, screen_gamma, 0.45455);
  else
  {
        double image_gamma;
        if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
                png_set_gamma(png_ptr, screen_gamma, image_gamma);
        else
                png_set_gamma(png_ptr, screen_gamma, 0.45455);
  }

  // Update the changes in between, as we need to get the new color type
  // for proper processing of the RGBA type
  png_read_update_info(png_ptr, info_ptr);
  {
     // Use temporary variables to avoid passing casted pointers
     png_uint_32 w,h;
     // Extract info
     png_get_IHDR(png_ptr, info_ptr,
             &w, &h,
             &BitDepth, &ColorType, NULL, NULL, NULL);
     Width=w;
     Height=h;
  }

  // Convert RGBA to BGRA
  if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA)
  {
    png_set_bgr(png_ptr);
  }

  // Create the image structure to be filled by png data
  Picture* pic = GfxEngine::instance().createPicture( Size( Width, Height ) );
  GfxEngine::instance().loadPicture( *pic );

  if( pic->getSize().getArea() == 0 )
  {
    Logger::warning( "LOAD PNG: Internal PNG create image struct failure %s", file.getFileName().toString().c_str() );
    png_destroy_read_struct(&png_ptr, NULL, NULL);
    return Picture::getInvalid();
  }

  if( !Height )
  {
    Logger::warning( "LOAD PNG: Internal PNG create row pointers failure %s", file.getFileName().toString().c_str() );
    png_destroy_read_struct(&png_ptr, NULL, NULL);
    return Picture::getInvalid();
  }

  // Create array of pointers to rows in image data
  ScopedPtr<unsigned char*> RowPointers( (unsigned char**)new png_bytep[ Height ] );

  // Fill array of pointers to rows in image data
  SDL_LockSurface( pic->getSurface() );
  unsigned char* data = (unsigned char*)pic->getSurface()->pixels;
  for(unsigned int i=0; i<Height; ++i)
  {
    RowPointers.data()[i] = data;
    data += pic->getSurface()->pitch;
  }

  // for proper error handling
  if( setjmp( png_jmpbuf( png_ptr ) ) )
  {
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    GfxEngine::instance().deletePicture( pic );
    return Picture::getInvalid();
  }

  // Read data using the library function that handles all transformations including interlacing
  png_read_image( png_ptr, RowPointers.data() );

  png_read_end( png_ptr, NULL );
  png_destroy_read_struct( &png_ptr, &info_ptr, 0 ); // Clean up memory

  SDL_UnlockSurface(pic->getSurface());

  return *pic;
}
Beispiel #13
0
int ReadPngStream(FILE *file,
                  std::vector<unsigned char> * ptr,
                  int * w,
                  int * h,
                  int * depth)  {

  // first check the eight byte PNG signature
  png_byte  pbSig[8];
  size_t readcnt = fread(pbSig, 1, 8, file);
  (void) readcnt;
  if (png_sig_cmp(pbSig, 0, 8))
  {
    return 0;
  }

  // create the two png(-info) structures
  png_structp png_ptr = nullptr;
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
    (png_error_ptr)nullptr, (png_error_ptr)nullptr);
  if (!png_ptr)
  {
    return 0;
  }
  png_infop info_ptr = nullptr;
  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr)
  {
    png_destroy_read_struct(&png_ptr, nullptr, nullptr);
    return 0;
  }

  // initialize the png structure
  png_init_io(png_ptr, file);
  png_set_sig_bytes(png_ptr, 8);

  // read all PNG info up to image data

  png_read_info(png_ptr, info_ptr);

  // get width, height, bit-depth and color-type
  png_uint_32 wPNG, hPNG;
  int                 iBitDepth;
  int                 iColorType;
  png_get_IHDR(png_ptr, info_ptr, &wPNG, &hPNG, &iBitDepth,
    &iColorType, nullptr, nullptr, nullptr);

  // expand images of all color-type to 8-bit

  if (iColorType == PNG_COLOR_TYPE_PALETTE)
    png_set_expand(png_ptr);
  if (iBitDepth < 8)
    png_set_expand(png_ptr);
  if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
    png_set_expand(png_ptr);
  if (iBitDepth == 16) // convert 16-bit to 8-bit on the fly
    png_set_strip_16(png_ptr);

  double dGamma;
  // if required set gamma conversion
  if (png_get_gAMA(png_ptr, info_ptr, &dGamma))
    png_set_gamma(png_ptr, (double) 2.2, dGamma);

  // after the transformations are registered, update info_ptr data

  png_read_update_info(png_ptr, info_ptr);

  // get again width, height and the new bit-depth and color-type

  png_get_IHDR(png_ptr, info_ptr, &wPNG, &hPNG, &iBitDepth,
    &iColorType, nullptr, nullptr, nullptr);

  // Get number of byte along a tow
  png_uint_32         ulRowBytes;
  ulRowBytes = png_get_rowbytes(png_ptr, info_ptr);

  // and allocate memory for an array of row-pointers
  png_byte   **ppbRowPointers = nullptr;
  if ((ppbRowPointers = (png_bytepp) malloc(hPNG
    * sizeof(png_bytep))) == nullptr)
  {
    std::cerr << "PNG: out of memory" << std::endl;
    return 0;
  }

  *w = wPNG;
  *h = hPNG;
  *depth = png_get_channels(png_ptr, info_ptr);

  // now we can allocate memory to store the image
  ptr->resize((*h)*(*w)*(*depth));

  // set the individual row-pointers to point at the correct offsets
  for (png_uint_32 i = 0; i < hPNG; i++)
    ppbRowPointers[i] = &((*ptr)[0]) + i * ulRowBytes;

  // now we can go ahead and just read the whole image
  png_read_image(png_ptr, ppbRowPointers);

  // read the additional chunks in the PNG file (not really needed)
  png_read_end(png_ptr, nullptr);

  free (ppbRowPointers);

  png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
  return 1;
}
Beispiel #14
0
ImageData PNGImageCodec::Load(InputStreamPtr& file, const ImageParams& params,
		ImageCodecMetaInfo& metaInfo) {
	InputStream* readr = file.GetPtr();
	// check if png_ptr
	if (!CheckIfPng(readr)) {
		Warn(String("Image file format is not png: ") + params.name);
	}

	png_structp png_ptr;
	png_infop info_ptr;
	png_uint_32 width, height;
	int bit_depth, color_type;
	bool alpha;
	Color32 keycolor;
	int keycolor_index = -1;
	bool hascolorkey = false;

	ImageType imagetype;

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
	if (png_ptr == NULL) {
		Error("Could not create read struct");
		NEX_THROW_GracefulError(EXCEPT_INVALID_CALL);
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_read_struct(&png_ptr, NULL, NULL);
		Error("Could not create info struct");
		NEX_THROW_GracefulError(EXCEPT_INVALID_CALL);
	}

	png_set_error_fn(png_ptr, (void *) (readr), PngWarn, PngWarn);
	png_set_read_fn(png_ptr, (void *) (readr), PngReadFile);

	png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);
	png_read_info(png_ptr, info_ptr);
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0,
			NULL, NULL);

	// todo Unstrip
	png_set_strip_16(png_ptr);

	if (bit_depth != 8 && bit_depth != 16) {
		Error("Unsupported bit depth");
		NEX_THROW_GracefulError(EXCEPT_INVALID_CALL);
	}

	switch (color_type) {
	case PNG_COLOR_TYPE_GRAY:
	case PNG_COLOR_TYPE_GRAY_ALPHA:
		if (color_type & PNG_COLOR_MASK_ALPHA)
			imagetype = GrayAlpha;
		else {
			imagetype = Palleted;
			png_set_strip_alpha(png_ptr);
			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
				png_color_16p trans_values;
				png_get_tRNS(png_ptr, info_ptr, 0, 0, &trans_values);
				hascolorkey = true;
				keycolor.red = uint8(trans_values->gray) & 0xff;
				keycolor.green = uint8(trans_values->gray) & 0xff;
				keycolor.blue = uint8(trans_values->gray) & 0xff;
				keycolor.alpha = uint8(trans_values->gray) & 0xff;
			}

		}
		break;
	case PNG_COLOR_TYPE_PALETTE:
		imagetype = Palleted;
		alpha = true;
		if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
			// tRNS chunk. Every palette entry gets its own alpha value.
			png_bytep trans;
			int num_trans;
			png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, 0);

			// see if there is a single entry w/ alpha==0 and all other 255.
			// if yes use keycolor transparency.
			bool only_binary_trans = true;
			for (int32 i = 0; (i < num_trans) && only_binary_trans; i++) {
				if (trans[i] != 0xff) {
					only_binary_trans = only_binary_trans && (trans[i] == 0)
							&& (keycolor_index == -1);
					keycolor_index = i;
				}
			}
			if (!only_binary_trans) {
				keycolor_index = -1;
				png_set_palette_to_rgb(png_ptr);
				png_set_tRNS_to_alpha(png_ptr);
				imagetype = RGBImage;
			} else
				alpha = false;
		} else
			alpha = false;

		break;
	case PNG_COLOR_TYPE_RGBA:
		alpha = true;
	case PNG_COLOR_TYPE_RGB:
		imagetype = RGBImage;
		if (!(color_type & PNG_COLOR_MASK_ALPHA)) {
			alpha = false;
			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
				png_color_16p trans_values;
				png_get_tRNS(png_ptr, info_ptr, 0, 0, &trans_values);
				hascolorkey = true;
				keycolor.red = uint8((trans_values->red) & 0xff);
				keycolor.green = uint8((trans_values->green) & 0xff);
				keycolor.blue = uint8((trans_values->blue) & 0xff);
			}
		}
		break;
	}

	// setup gamma
	//@ TODO: add code to retrieve the gamma here
	double screen_gamma = 0; //X_SharedPtr(iSystem)->getUserGamma();
	// and comment this
	screen_gamma = 2.2;

	int intent;

	if (png_get_sRGB(png_ptr, info_ptr, &intent))
		png_set_gamma(png_ptr, screen_gamma, 0.45455);
	else {
		double image_gamma;
		if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
			png_set_gamma(png_ptr, screen_gamma, image_gamma);
		else
			png_set_gamma(png_ptr, screen_gamma, 0.45455);
	}

	/* todo Unstrip this */
	if (bit_depth > 8) {
		// tell libpng to strip 16 bit/color files down to 8 bits/color
		png_set_strip_16(png_ptr);
		bit_depth = 8;
	} else if (bit_depth < 8)
		// Expand pictures with less than 8bpp to 8bpp
		png_set_packing(png_ptr);

	// update
	png_read_update_info(png_ptr, info_ptr);
	png_uint_32 bytes_per_row = (png_uint_32)png_get_rowbytes(png_ptr, info_ptr);

	//png_read_image
	PixelFormat fmt;
	uint32 bpp = 1;
	// we dont support anything else
	// other than RGBImage right now
	// so!

	if (imagetype == RGBImage) {
		fmt = PixelFormat::RGBA8;
		bpp = 4;
	} else if (imagetype == GrayAlpha && bytes_per_row == 1)
		fmt = PixelFormat::R8;
	else { // pallete
		   // cant handle this
		Warn(String("PixelFormat not supported.") + params.name);
		NEX_THROW_GracefulError(EXCEPT_INVALID_CALL);
	}

	int numPass = png_set_interlace_handling(png_ptr);

	ImageData img;
	uint8* imgDest = (uint8*) NEX_ALLOC(bpp * height * width, MEMCAT_GENERAL);
	img.data = imgDest;
	img.format = fmt;
	metaInfo.metaInfoInited = true;
	metaInfo.mipLevelsToRead = 0;
	metaInfo.metaInfo.maxDepth = img.depth = 1;
	metaInfo.metaInfo.maxHeight = img.height = (uint16) height;
	metaInfo.metaInfo.maxWidth = img.width = (uint16) width;
	metaInfo.metaInfo.maxMipMapCount = img.numMipMaps = 1;
	img.numFaces = 1;

	uint8* imgRows = 0;
	if (numPass > 1) {
		imgRows = (uint8*) NEX_ALLOC(bytes_per_row * height, MEMCAT_GENERAL);
	} else
		imgRows = (uint8*) NEX_ALLOC(bytes_per_row, MEMCAT_GENERAL);

	uint32 srcBpp = bytes_per_row / width;

	for (uint32 i = 0; (int32) i < numPass; ++i) {
		for (uint32 y = 0; y < height; y++) {
			uint8* rowPtr = numPass > 1 ? imgRows + bytes_per_row * y : imgRows;
			png_read_row(png_ptr, rowPtr, NULL);

			// write only once
			if (i == numPass - 1) {
				for (uint32 x = 0; x < width; x++) {
					// bgra
					switch (fmt) {
					case PixelFormat::RGBA8:

						imgDest[0] = rowPtr[0];
						imgDest[1] = rowPtr[1];
						imgDest[2] = rowPtr[2];
						if (alpha)
							imgDest[3] = rowPtr[3];
						else
							imgDest[3] = 0xff;
						break;
					case PixelFormat::R8:
						imgDest[0] = rowPtr[0];
						break;
					}
					imgDest += bpp;
					rowPtr += srcBpp;
				}
			}
		}
	}

	png_read_end(png_ptr, (png_infop) 0);
	png_destroy_read_struct(&png_ptr, NULL, NULL);
	NEX_FREE(imgRows, MEMCAT_GENERAL);

	if (hascolorkey) {
		imgDest = (uint8*) img.data;

		for (uint32 y = 0; y < height; y++) {
			for (uint32 x = 0; x < width; x++) {
				switch (fmt) {
				case PixelFormat::RGBA8:
					if (imgDest[0] == keycolor.red
							&& imgDest[1] == keycolor.green
							&& imgDest[2] == keycolor.blue)
						imgDest[3] = 0;
					break;
				case PixelFormat::R8:
					if (imgDest[0] == keycolor.alpha)
						imgDest[0] = 0;
					break;
				}
				imgDest += bpp;
			}

		}
	}

	return img;
}
Beispiel #15
0
void PNGImageDecoder::headerAvailable()
{
    png_structp png = m_reader->pngPtr();
    png_infop info = m_reader->infoPtr();
    png_uint_32 width = png->width;
    png_uint_32 height = png->height;
    
    // Protect against large images.
    if (png->width > cMaxPNGSize || png->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);

    // 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 (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.     
        m_reader->setReadOffset(m_reader->currentBufferSize() - png->buffer_size);
        png->buffer_size = 0;
    }
}
Beispiel #16
0
void readPng(GImage* pImage, const unsigned char* pData, size_t nDataSize)
{
	// Check for the PNG signature
	if(nDataSize < 8 || png_sig_cmp((png_bytep)pData, 0, 8) != 0)
		throw Ex("not a png file");

	// Read all PNG data up until the image data chunk.
	GPNGReader reader(pData);
	png_set_read_fn(reader.m_pReadStruct, (png_voidp)&reader, (png_rw_ptr)readFunc);
	png_read_info(reader.m_pReadStruct, reader.m_pInfoStruct);

	// Get the image data
	int depth, color;
	png_uint_32 width, height;
	png_get_IHDR(reader.m_pReadStruct, reader.m_pInfoStruct, &width, &height, &depth, &color, NULL, NULL, NULL);
	if(depth != 8)
		throw Ex("unexpected depth");
	pImage->resize(width, height);

	// Set gamma correction
	double dGamma;
	if (png_get_gAMA(reader.m_pReadStruct, reader.m_pInfoStruct, &dGamma))
		png_set_gamma(reader.m_pReadStruct, 2.2, dGamma);
	else
		png_set_gamma(reader.m_pReadStruct, 2.2, 1.0 / 2.2); // 1.0 = viewing gamma, 2.2 = screen gamma

	// Update the 'info' struct with the gamma information
	png_read_update_info(reader.m_pReadStruct, reader.m_pInfoStruct);

	// Tell it to expand palettes to full channels
	png_set_expand(reader.m_pReadStruct);
	png_set_gray_to_rgb(reader.m_pReadStruct);

	// Allocate the row pointers
	unsigned long rowbytes = png_get_rowbytes(reader.m_pReadStruct, reader.m_pInfoStruct);
	unsigned long channels = rowbytes / width;
	png_bytep pRawData = (png_bytep)new unsigned char[rowbytes * height];
	unsigned int i;
	{
		png_bytep* pRows = (png_bytep*)new unsigned char[sizeof(png_bytep) * height];
		for(i = 0; i < height; i++)
			pRows[i] = pRawData + i * rowbytes;
		png_read_image(reader.m_pReadStruct, pRows);
		delete[] pRows;
	}

	// Copy to the GImage
	unsigned long nPixels = width * height;
	unsigned int* pRGBQuads = pImage->m_pPixels;
	unsigned char *pBytes = pRawData;
	if(channels > 3)
	{
		if(channels != 4)
			throw Ex("Unexpected number of channels");
		for(i = 0; i < nPixels; i++)
		{
			*pRGBQuads = gARGB(pBytes[3], pBytes[0], pBytes[1], pBytes[2]);
			pBytes += channels;
			pRGBQuads++;
		}
	}
	else if(channels == 3)
	{
		for(i = 0; i < nPixels; i++)
		{
			*pRGBQuads = gARGB(0xff, pBytes[0], pBytes[1], pBytes[2]);
			pBytes += channels;
			pRGBQuads++;
		}
	}
	else
	{
		delete[] pRawData;
		throw Ex("Sorry, loading ", to_str(channels), "-channel png files is not yet supported");
	}
	delete[] pRawData;

	// Check for additional tags
	png_read_end(reader.m_pReadStruct, reader.m_pEndInfoStruct);
}
Beispiel #17
0
/* really_load_png:
 *  Worker routine, used by load_png and load_memory_png.
 */
static BITMAP *really_load_png(png_structp png_ptr, png_infop info_ptr, RGB *pal)
{
    BITMAP *bmp;
    PALETTE tmppal;
    png_uint_32 width, height, rowbytes;
    int bit_depth, color_type, interlace_type;
    double image_gamma, screen_gamma;
    int intent;
    int bpp, dest_bpp;
    int number_passes, pass;

    ASSERT(png_ptr && info_ptr);

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

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

    /* 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 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_expand(png_ptr);

    /* Adds a full alpha channel if there is transparency information
     * in a tRNS chunk. */
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
	png_set_tRNS_to_alpha(png_ptr);
    }

    /* Convert 16-bits per colour component to 8-bits per colour component. */
    if (bit_depth == 16)
	png_set_strip_16(png_ptr);

    /* Convert grayscale to RGB triplets */
    if ((color_type == PNG_COLOR_TYPE_GRAY) ||
	(color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
	png_set_gray_to_rgb(png_ptr);

    /* Optionally, tell libpng to handle the gamma correction for us. */
    if (_png_screen_gamma != 0.0) {
	screen_gamma = get_gamma();

	if (png_get_sRGB(png_ptr, info_ptr, &intent))
	    png_set_gamma(png_ptr, screen_gamma, 0.45455);
	else {
	    if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
		png_set_gamma(png_ptr, screen_gamma, image_gamma);
	    else
		png_set_gamma(png_ptr, screen_gamma, 0.45455);
	}
    }

    /* Turn on interlace handling. */
    number_passes = png_set_interlace_handling(png_ptr);

    /* Call to gamma correct and add the background to the palette
     * and update info structure.
     */
    png_read_update_info(png_ptr, info_ptr);

    /* Even if the user doesn't supply space for a palette, we want
     * one for the load process.
     */
    if (!pal)
	pal = tmppal;

    /* Palettes. */
    if (color_type & PNG_COLOR_MASK_PALETTE) {
	int num_palette, i;
	png_colorp palette;

	if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) {
	    /* We don't actually dither, we just copy the palette. */
	    for (i = 0; ((i < num_palette) && (i < 256)); i++) {
		pal[i].r = palette[i].red >> 2;		/* 256 -> 64 */
		pal[i].g = palette[i].green >> 2;
		pal[i].b = palette[i].blue >> 2;
	    }

	    for (; i < 256; i++)
		pal[i].r = pal[i].g = pal[i].b = 0;
	}
    }
Beispiel #18
0
// This is the interesting function here. It sets up a PNG image as a texture.
void loadPngTex(char * fname , struct tImagePNG * pImagePNG , int *hasAlpha )
{
  // The header of the file will be saved in here
  char           buf[PNG_BYTES_TO_CHECK];
  
  // images infos
  int            bit_depth;
  int            cType;
  double         gamma;
  FILE          *fp;

  // Open the file and check correct opening
  /* Open the prospective PNG file. */
  if ((fp = fopen(fname, "rb")) == NULL) {
    printf( "Error: Could not open the texture file [%s]!" , fname ); throw 336;
  }
  
  // Read the PNG header, which is 8 bytes long.
  /* Read in some of the signature bytes */
  if (fread(buf, 1, PNG_BYTES_TO_CHECK, fp) != PNG_BYTES_TO_CHECK) {
    printf( "Error: Incorrect PNG texture file [%s]!" , fname ); throw 336;
  }

  // Check whether the file is a PNG file
  // png_sig_cmp() checks the given PNG header and returns 0 if it could
  // be the start of a PNG file. We can use 8 bytes at max for
  // this comparison.
  if(png_sig_cmp((png_byte*)buf, (png_size_t)0, PNG_BYTES_TO_CHECK) != 0) {
    fclose( fp );
    printf( "Error: Not a PNG file [%s]!" , fname ); throw 337;
  }
  
  // Create / initialize the png_struct
  // The png_struct isn't directly accessed by the user (us).
  // We will later create a png_info from this to get access to the
  // PNG's infos.
  // The three 0's in the arg list could be pointers to user defined error
  // handling functions. 0 means we don't want to specify them, but use
  // libPNG's default error handling instead.
  png_infop info_ptr;
  png_structp png_ptr
    = png_create_read_struct(PNG_LIBPNG_VER_STRING,
			     NULL , NULL , NULL );
  if(!png_ptr) {
    fclose( fp );
    printf( "Error: Couldn't create PNG read structure [%s]!" , fname ); throw 338;
  }

  // Create / initialize the png_info
  // The png_info grants the user access to the PNG infos.
  info_ptr = png_create_info_struct(png_ptr);
  if(!info_ptr) {
    // We need to destroy the read_struct
    png_destroy_read_struct(&png_ptr, NULL, NULL);
    fclose( fp );
    printf( "Error: Couldn't create PNG info structure [%s]!" , fname ); throw 339;
  }
  
  // Setup error handler
  // This sets the point libPNG jumps back to is an error occurs.
  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 */
      printf( "Error: Couldn't setup PNG error handler [%s]!" , fname ); throw 340;
   }
  
  /* Set up the input control if you are using standard C streams */
  png_init_io(png_ptr, fp);
  
  // This tells libPNG that we have already read 8 bytes from the start
  // of the file (for the header check above).
  png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK);

  // This reads the PNG file into the read and info structs
  /*
   * 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_info(png_ptr, info_ptr);

  // Get some basic infos about the image from png_info structure
  // width & height in px, bit depth
  // interlace_method, compression_method, & filter_method are ignored
  png_get_IHDR(png_ptr, info_ptr, &(pImagePNG->sizeX), &(pImagePNG->sizeY), 
	       &bit_depth, &cType, 0, 0, 0);

  // COLOR TYPE read and possible corrections - then reread
  // Color type: we handle RGB and RGB_ALPHA (with Alpha) 
  // GRAY (luminance) and GRAY_ALPHA (luminance with Alpha)
  cType = png_get_color_type(png_ptr, info_ptr);
  // strip the pixels of a PNG stream with 16 bits per channel to 8 bits per channel
  if (bit_depth == 16) {
    png_set_strip_16(png_ptr);
  }
  // set transformation in png_ptr such that paletted images are expanded to RGB, 
  // grayscale images of bit-depth less than 8 are expanded to 8-bit images
  // tRNS chunks are expanded to alpha channels
  if (cType == PNG_COLOR_TYPE_PALETTE) {
    png_set_expand(png_ptr);
  }
  if (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 required set gamma conversion
  if (png_get_gAMA(png_ptr, info_ptr, &gamma)) {
    png_set_gamma(png_ptr, (double) 2.2, gamma);
  }

  // After the image transformations have been registered update info_ptr data
  png_read_update_info(png_ptr, info_ptr);
  // Gets again width, height and the new bit-depth and color-type
  png_get_IHDR(png_ptr, info_ptr, &(pImagePNG->sizeX), &(pImagePNG->sizeY), 
	       &bit_depth, &cType, 0, 0, 0);

  // We now calculate the *bytes* per pixel from the color type and the
  // bits per pixel.
  if((cType == PNG_COLOR_TYPE_RGB) && (bit_depth == 8)) {
    pImagePNG->bytesPerPixel = 3;
    *hasAlpha = false;
  }
  else if((cType == PNG_COLOR_TYPE_RGB_ALPHA) && (bit_depth == 8)) {
    pImagePNG->bytesPerPixel = 4;
    *hasAlpha = true;
  }
  else if((cType == PNG_COLOR_TYPE_GRAY) && (bit_depth == 8)) {
    pImagePNG->bytesPerPixel = 1;
    *hasAlpha = false;
  }
  else if((cType == PNG_COLOR_TYPE_GRAY_ALPHA) && (bit_depth == 8)) {
    pImagePNG->bytesPerPixel = 2;
    *hasAlpha = true;
  }
  else {
    /* clean up after the read, and free any memory allocated - REQUIRED */
    png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
    fclose( fp );
    printf( "Error: PNG image [%s] type (%d) bit depth (%d) is unsupported!" , fname , cType , bit_depth ); throw 336;
  }
  
  // rowbytes is the width x number of channels. channels is not used currently
  unsigned int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
  // unsigned int channels = png_get_channels(png_ptr, info_ptr);

  // Allocates memory to store the image
  pImagePNG->data = new GLubyte[pImagePNG->sizeY * rowbytes];

//   printf( "PNG image %ldx%ld (%d bitsperpixel/%d bytesPerPixel) size row %d total %ld\n" , 
// 	  pImagePNG->sizeX ,
// 	  pImagePNG->sizeY , bit_depth , pImagePNG->bytesPerPixel,
// 	  rowbytes , pImagePNG->sizeY * rowbytes);

  ////  Alternate solution without explicit row pointers
  //// and image read through png_get_rows
  // Returns a pointer to the array of array of png_bytes that holds the
  // image data.
  // png_byte **imageData = png_get_rows(png_ptr, info_ptr);
  //// must read row after row
  //   for( unsigned int i = 0 ; i < pImagePNG->sizeY ; i++ ) {
  //     printf( "Ind %d\n" , i );
  //     memcpy(&pImagePNG->data[(pImagePNG->sizeY - i - 1) * rowbytes],
  // 	   row[i], rowbytes);
  //  }

  ////  Alternate solution with explicit row pointers
  //// and image read through png_read_image
  // Allocates memory for an array of row-pointers
  png_byte ** row = new GLubyte * [pImagePNG->sizeY];
  // Sets the row-pointers to point at the correct offsets	
  for (unsigned int i = 0; i < pImagePNG->sizeY; i++) {
    row[i] = pImagePNG->data + (pImagePNG->sizeY - i - 1) * rowbytes;
  }
  // Reads the whole image
  png_read_image(png_ptr, row);
  // deallocate the now unuseful row pointers
  delete [] row;

  // Free the memory we used - we don't need it anymore
  /* clean up after the read, and free any memory allocated - REQUIRED */
  png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
  fclose( fp );
}
Beispiel #19
0
void png_reader<T>::read(unsigned x0, unsigned y0,image_rgba8& image)
{
    stream_.clear();
    stream_.seekg(0, std::ios_base::beg);

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

    if (!png_ptr)
    {
        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;
    png_struct_guard sguard(&png_ptr,&info_ptr);
    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) throw image_reader_exception("failed to create info_ptr");

    png_set_read_fn(png_ptr, (png_voidp)&stream_, 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
        const std::unique_ptr<png_bytep[]> rows(new png_bytep[height_]);
        for (unsigned i=0; i<height_; ++i)
            rows[i] = (png_bytep)image.get_row(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_ - x0);
        unsigned h=std::min(unsigned(image.height()),height_ - y0);
        unsigned rowbytes=png_get_rowbytes(png_ptr, info_ptr);
        const std::unique_ptr<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 < (y0 + h))
            {
                image.set_row(i-y0,reinterpret_cast<unsigned*>(&row[x0 * 4]),w);
            }
        }
        //END
    }
    png_read_end(png_ptr,0);
}
Beispiel #20
0
// PNG image handler functions
int LoadImagePNG (char* filename, char** image, int *width, int *height, int *channels)
{
  FILE *file;
  png_structp png = NULL;
  png_infop info = NULL;
  png_bytepp row = NULL;
  png_byte sig[8];
  png_uint_32 rowsize;
  int depth;
  int type;
  double gamma;
  int i;

  // open the PNG input file
  if (!filename)
  {
    *image = NULL;
    return 1;
  }
  if (!strcmp(filename, "-"))
  {
    file = stdin;
    _setmode(_fileno(file), _O_BINARY);
  }
  else if (!(file = fopen(filename, "rb")))
  {
    *image = NULL;
    return 1;
  }
  // first check the eight byte PNG signature
  fread(sig, 1, 8, file);
  if (!png_check_sig(sig, 8))
  {  
    *image = NULL;
    return 1;
  }
  /* create png struct with the error handlers above */
  png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
			       (png_error_ptr)_ErrorHandlerPNG, (png_error_ptr)NULL);
  if (!png)
  {
    *image = NULL;
    return 1;
  }
  /* create image info struct */
  info = png_create_info_struct(png);
  if (!info)
  {
    png_destroy_read_struct(&png, NULL, NULL);
    *image = NULL;
    return 1;
  }
  /* set up png style error handling */
  if (setjmp(png->jmpbuf))
  {
    /* the error is reported inside the handler, 
       but we still need to clean up and return */
    png_destroy_read_struct(&png, &info, NULL);
    if (*image) free(*image);
    if (row) free(row);
    if (file != stdin) fclose(file);
    *image = NULL;
    return 1;
  }
  /* initialize png I/O */
#ifdef PNG_NO_STDIO
  png_set_read_fn(png, (png_voidp)file, _ReadDataPNG);
#else
  png_init_io(png, file);
#endif
  /* if we are here, we have already read 8 bytes from the file */
  png_set_sig_bytes(png, 8);
  /* png_read_info() returns all information from the file 
     before the first data chunk */
  png_read_info(png, info);
  /* query required image info */
  png_get_IHDR(png, info, width, height, &depth, &type, 
	       NULL, NULL, NULL);
  /* expand images of all color-type and bit-depth to 3x8 bit RGB images
     let the library process things like alpha, transparency, background */
  if (depth == 16) png_set_strip_16(png);
  /* expand paletted colors into rgb triplets */
  if (type == PNG_COLOR_TYPE_PALETTE)
    png_set_palette_to_rgb(png);
  /* expand grayscale images to 8 bits from 1, 2, or 4 bits */
  if (type == PNG_COLOR_TYPE_GRAY && depth < 8)
    png_set_gray_1_2_4_to_8(png);
  /* 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);
  /* convert grayscale images to rgb */
  if (type == PNG_COLOR_TYPE_GRAY ||
      type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png);
  /* set gamma conversion */
  if (png_get_gAMA(png, info, &gamma))
    png_set_gamma(png, (double)2.2, gamma);
  /* after the transformations have been registered update info */
  png_read_update_info(png, info);
  /* get width, height again and the new bit-depth and color-type */
  png_get_IHDR(png, info, width, height, &depth,
	       &type, NULL, NULL, NULL);
  *channels = png_get_channels(png, info);
  /* row_bytes is the width x number of channels */
  rowsize = png_get_rowbytes(png, info);
  /* now we can allocate memory to store the image */
  if (*image)
  {
    free(*image); *image = NULL;
  }
  *image = (png_byte*)malloc(rowsize*(*height)*sizeof(png_byte));
  if (*image == NULL) png_error(png, "out of memory");
  /* set up row pointers */
  row = (png_bytepp)malloc((*height)*sizeof(png_bytep));
  if (row == NULL) png_error(png, "out of memory");
  for (i=0; i<(*height); i++)
    row[i] = &((png_bytep)(*image))[i*rowsize];
  /* read the whole image */
  png_read_image(png, row);
  /* finish reading */
  png_read_end(png, NULL);
  /* clean up */
  png_destroy_read_struct(&png, &info, NULL);
  free(row); row = NULL;
  if (file != stdin) fclose(file);
  /* return image data */
  return 0;
}
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);

    // 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);

    if ((colorType & PNG_COLOR_MASK_COLOR) && !m_ignoreGammaAndColorProfile) {
        // We only support color profiles for color PALETTE and RGB[A] PNG. 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
        // do not 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.
        readColorProfile(png, info, m_colorProfile);
#if USE(QCMSLIB)
        bool decodedImageHasAlpha = (colorType & PNG_COLOR_MASK_ALPHA) || trnsCount;
        m_reader->createColorTransform(m_colorProfile, decodedImageHasAlpha);
        m_colorProfile.clear();
#endif
    }

    // 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
    }
}
Beispiel #22
0
int read_PNG(char *file_name)
{
    /*
     * Took this code from doc/fblib
     * and adjusted it to the likings
     * of this program.
     * ?i
     * It is really awesome that a NOOB
     * like me, Noisegate can actually
     * make useable software on an open
     * system like this Linux...
     *
     * openSOFtWARE rocKS
     */

    png_structp png_ptr;
    png_infop info_ptr;
    unsigned int sig_read = 0;
    png_uint_32 _width, _height, row;
    int bit_depth, color_type, interlace_type;
    FILE *fp;

    float screen_gamma;

    if ((fp = fopen(file_name, "rb")) == NULL)
          return -1;

    /* 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);
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 
            (png_voidp)NULL, 
            (png_error_ptr)NULL, 
            (png_error_ptr)NULL);

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

    /* 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 -1;
    }

    /* 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 */
        fprintf(stderr, "Error: Couldn't read the file.");
        return -1;
    }

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

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

   /* 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_expand_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);


   screen_gamma = 1.0;

   int intent;

   if (png_get_sRGB(png_ptr, info_ptr, &intent))
      png_set_gamma(png_ptr, screen_gamma, 0.45455);
   else
   {
      double image_gamma;
      if (png_get_gAMA(png_ptr, info_ptr, &image_gamma))
         png_set_gamma(png_ptr, screen_gamma, image_gamma);
      else
         png_set_gamma(png_ptr, screen_gamma, 0.45455);
   }

   /* Invert monochrome files to have 0 as white and 1 as black */
   png_set_invert_mono(png_ptr);

   /* 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 (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
   {
      png_color_8p sig_bit_p;

      png_get_sBIT(png_ptr, info_ptr, &sig_bit_p);
      png_set_shift(png_ptr, sig_bit_p);
   }

   /* Flip the RGB pixels to BGR (or RGBA to BGRA) */
   if (color_type & PNG_COLOR_MASK_COLOR)
      png_set_bgr(png_ptr);

   /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
   png_set_swap_alpha(png_ptr);

   /* Swap bytes of 16 bit files to least significant byte first */
   png_set_swap(png_ptr);

   /* Add filler (or alpha) byte (before/after each RGB triplet) */
   png_set_filler(png_ptr, 0x00, PNG_FILLER_AFTER);

   /* Turn on interlace handling.  REQUIRED if you are not using
    * png_read_image().  To see how to handle interlacing passes,
    * see the png_read_row() method below:
    */
   //number_passes = png_set_interlace_handling(png_ptr);

   /* 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 (ie you selected such a transform above).
    */
   png_read_update_info(png_ptr, info_ptr);

   /* Allocate the memory to hold the image using the fields of info_ptr. */

   /* The easiest way to read the image: */
   png_bytep row_pointers[_height];

   /* Clear the pointer array */
   for (row = 0; row < _height; row++)
      row_pointers[row] = NULL;

   for (row = 0; row < _height; row++)
      row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr,
         info_ptr));

   /* Now it's time to read the image.  One of these methods is REQUIRED */
   png_read_image(png_ptr, row_pointers);


   /* Now mess this rowpointer thing into the tmp_buf
    * U dont know if width>_width and height>_height
    * so we trunc the guy
    */
    
   int maxY = _height>height?height:_height;
   int maxX = _width>width?finfo.line_length:_width;
   int pix_offset=0;

   for (row=0; row<maxY;row++){
       pix_offset = Ox*BPP + ((Oy+row)*finfo.line_length);
       memcpy(tmp_buf+pix_offset, row_pointers[row], maxX*BPP);
   }

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

   /* Close the file */
   fclose(fp);


   //printf("png W x H = %i x %i\n", _width, _height);
   /* That's it */
    return 0;
}
Beispiel #23
0
static gint
gegl_buffer_import_png (GeglBuffer  *gegl_buffer,
                        GInputStream *stream,
                        gint         dest_x,
                        gint         dest_y,
                        gint        *ret_width,
                        gint        *ret_height,
                        const Babl  *format, // can be NULL
                        GError **err)
{
  gint           width;
  gint           bit_depth;
  gint           bpp;
  gint           number_of_passes=1;
  png_uint_32    w;
  png_uint_32    h;
  png_structp    load_png_ptr;
  png_infop      load_info_ptr;
  guchar        *pixels;
  /*png_bytep     *rows;*/


  unsigned   int i;
  png_bytep  *row_p = NULL;

  g_return_val_if_fail(stream, -1);

  if (!check_valid_png_header(stream, err))
    {
      return -1;
    }

  load_png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, error_fn, NULL);

  if (!load_png_ptr)
    {
      return -1;
    }

  load_info_ptr = png_create_info_struct (load_png_ptr);
  if (!load_info_ptr)
    {
      png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL);
      return -1;
    }

  if (setjmp (png_jmpbuf (load_png_ptr)))
    {
      png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL);
     if (row_p)
        g_free (row_p);
      return -1;
    }

  png_set_read_fn(load_png_ptr, stream, read_fn);

  png_set_sig_bytes (load_png_ptr, 8); // we already read header
  png_read_info (load_png_ptr, load_info_ptr);
  {
    int color_type;
    int interlace_type;

    png_get_IHDR (load_png_ptr,
                  load_info_ptr,
                  &w, &h,
                  &bit_depth,
                  &color_type,
                  &interlace_type,
                  NULL, NULL);
    width = w;
    if (ret_width)
      *ret_width = w;
    if (ret_height)
      *ret_height = h;

    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
      {
        png_set_expand (load_png_ptr);
        bit_depth = 8;
      }

    if (png_get_valid (load_png_ptr, load_info_ptr, PNG_INFO_tRNS))
      {
        png_set_tRNS_to_alpha (load_png_ptr);
        color_type |= PNG_COLOR_MASK_ALPHA;
      }

    switch (color_type)
      {
        case PNG_COLOR_TYPE_GRAY:
          bpp = 1;
          break;
        case PNG_COLOR_TYPE_GRAY_ALPHA:
          bpp = 2;
          break;
        case PNG_COLOR_TYPE_RGB:
          bpp = 3;
          break;
        case PNG_COLOR_TYPE_RGB_ALPHA:
          bpp = 4;
          break;
        case (PNG_COLOR_TYPE_PALETTE | PNG_COLOR_MASK_ALPHA):
          bpp = 4;
          break;
        case PNG_COLOR_TYPE_PALETTE:
          bpp = 3;
          break;
        default:
          g_warning ("color type mismatch");
          png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL);
          return -1;
      }

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

    if (bit_depth == 16)
      bpp = bpp << 1;

    if (!format)
      format = get_babl_format(bit_depth, color_type);

#if BYTE_ORDER == LITTLE_ENDIAN
    if (bit_depth == 16)
      png_set_swap (load_png_ptr);
#endif

    if (interlace_type == PNG_INTERLACE_ADAM7)
      number_of_passes = png_set_interlace_handling (load_png_ptr);

    if (png_get_valid (load_png_ptr, load_info_ptr, PNG_INFO_gAMA))
      {
        gdouble gamma;
        png_get_gAMA (load_png_ptr, load_info_ptr, &gamma);
        png_set_gamma (load_png_ptr, 2.2, gamma);
      }
    else
      {
        png_set_gamma (load_png_ptr, 2.2, 0.45455);
      }

    png_read_update_info (load_png_ptr, load_info_ptr);
  }

  pixels = g_malloc0 (width*bpp);

  {
    gint           pass;
    GeglRectangle  rect;

    for (pass=0; pass<number_of_passes; pass++)
      {
        for(i=0; i<h; i++)
          {
            gegl_rectangle_set (&rect, 0, i, width, 1);

            if (pass != 0)
              gegl_buffer_get (gegl_buffer, &rect, 1.0, format, pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);

            png_read_rows (load_png_ptr, &pixels, NULL, 1);
            gegl_buffer_set (gegl_buffer, &rect, 0, format, pixels,
                             GEGL_AUTO_ROWSTRIDE);
          }
      }
  }


  png_read_end (load_png_ptr, NULL);
  png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL);

  g_free (pixels);

  return 0;
}
Beispiel #24
0
bool vtImage::_ReadPNG(const char *filename)
{
	FILE *fp = NULL;

	uchar header[8];
	png_structp png;
	png_infop   info;
	png_infop   endinfo;
	png_bytep  *row_p;

	png_uint_32 width, height;
	int depth, color;

	png_uint_32 i;
	png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
	if (!png)
	{
		// We compiled against the headers of one version of libpng, but
		// linked against the libraries from another version.  If you get
		// this, fix the paths in your development environment.
		return false;
	}
	info = png_create_info_struct(png);
	endinfo = png_create_info_struct(png);

	fp = vtFileOpen(filename, "rb");
	if (fp && fread(header, 1, 8, fp) && png_check_sig(header, 8))
		png_init_io(png, fp);
	else
	{
		png_destroy_read_struct(&png, &info, &endinfo);
		return false;
	}
	png_set_sig_bytes(png, 8);

	png_read_info(png, info);
	png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL);

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

	// never strip alpha
//	{
//		png_set_strip_alpha(png);
//		color &= ~PNG_COLOR_MASK_ALPHA;
//	}

	// Always expand paletted images
	if (color == PNG_COLOR_TYPE_PALETTE)
		png_set_expand(png);

	/*--GAMMA--*/
//	checkForGammaEnv();
	double screenGamma = 2.2 / 1.0;
#if 0
	// Getting the gamma from the PNG file is disabled here, since
	// PhotoShop writes bizarre gamma values like .227 (PhotoShop 5.0)
	// or .45 (newer versions)
	double	fileGamma;
	if (png_get_gAMA(png, info, &fileGamma))
		png_set_gamma(png, screenGamma, fileGamma);
	else
#endif
		png_set_gamma(png, screenGamma, 1.0/2.2);

	png_read_update_info(png, info);

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

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

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

	int iBitCount;

	switch (color)
	{
		case PNG_COLOR_TYPE_GRAY:
		case PNG_COLOR_TYPE_RGB:
		case PNG_COLOR_TYPE_PALETTE:
			iBitCount = 24;
			break;

		case PNG_COLOR_TYPE_GRAY_ALPHA:
		case PNG_COLOR_TYPE_RGB_ALPHA:
			iBitCount = 32;
			break;

		default:
			return false;
	}

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

	// Don't free the data, we're going to pass it to OSG
//	free(m_pPngData);

	if (fp)
		fclose(fp);

	int pixelFormat;
	uint internalFormat;

	if (iBitCount == 24)
		pixelFormat = GL_RGB;
	else if (iBitCount == 32)
		pixelFormat = GL_RGBA;

	if (m_internalformat == -1)
		internalFormat = pixelFormat;	// use default
	else
		internalFormat = m_internalformat;	// use specific

	setImage(width, height, 1,
	   internalFormat,		// int internalFormat,
	   pixelFormat,			// uint pixelFormat
	   GL_UNSIGNED_BYTE,	// uint dataType
	   m_pPngData,
	   osg::Image::USE_MALLOC_FREE);

	return true;
}
Beispiel #25
0
bool Image::load (const std::string &s)
{	
	//
	// The following is based on the libpng manual. http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-3.1
	//

	//
	// Check the file header
	//

	// Open the file
	std::ifstream infile;
	infile.open(s.c_str(), std::ifstream::in | std::ifstream::binary);

	// Read the header
	const unsigned int NUM_HEADER_BYTES_TO_READ = 8;
	char header[NUM_HEADER_BYTES_TO_READ];
	
	infile.read(header, NUM_HEADER_BYTES_TO_READ);
    if (png_sig_cmp((png_bytep) header, 0, NUM_HEADER_BYTES_TO_READ)) {
        return false;
	}
	
	//
	// Read the image data
	//
	
	png_bytep *row_pointers = NULL;

	// 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_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {
        return false;
	}
	
	// Allocate/initialize the memory for image information
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
        return false;
    }

	// 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))) {
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		delete row_pointers;	// Gets allocated after here, but don't forget the jump!
        return false;
	}

	// Set custom read routine
	png_set_read_fn(png_ptr, &infile, &png_read_data);
   
	// If we have already read some of the signature
	png_set_sig_bytes(png_ptr, NUM_HEADER_BYTES_TO_READ);
   
	//
	// Read the entire image
	//
	
	// Read PNG header info
	png_read_info(png_ptr, info_ptr);

	int bit_depth, color_type, interlace_type;
	
	// Header info
	png_uint_32 width,height;
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
	
	// Strip 16 bit down to 8 bit
	png_set_strip_16(png_ptr);
		
	// Extract components to even bytes
	png_set_packing(png_ptr);

	// Expand grayscale images to 8 bit
	png_set_expand(png_ptr);
	
	// Add a filler byte when missing
	png_set_filler(png_ptr,0xFFFFFFFF,PNG_FILLER_AFTER);

	// Expand grayscale images to rgb
	png_set_gray_to_rgb(png_ptr);
	
	// Update the transformation info within libpng
	png_read_update_info(png_ptr, info_ptr);
		
	// Header info again
	png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL);
	
	// Allocate target image
	allocate(width, height);

	// Handle Gamma
	png_set_gamma(png_ptr, 0.0, 0.0);
	
	// Setup row pointers
	row_pointers = new png_bytep[_data_height];
	if (!row_pointers) {
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
        return false;
	}
	
	for (unsigned int y = 0; y < _data_height; ++y) {
		row_pointers[y] = reinterpret_cast<png_byte*>( &getPixel(0,y) );
	}	
	
	// Read the entire image
	png_read_image(png_ptr, row_pointers);
	
	//
	// Clean up
	//
	
	delete row_pointers;
	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
	
	return true;
}
    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");
        }

        png_infop 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");
        }

        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);

        png_read_update_info(png_ptr, info_ptr);

        //START read image rows
        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]);
	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);
    }
void PNGImageDecoder::headerAvailable()
{
    png_structp png = reader()->pngPtr();
    png_infop info = reader()->infoPtr();
    png_uint_32 width = png->width;
    png_uint_32 height = png->height;
    
    // Protect against large images.
    if (png->width > cMaxPNGSize || png->height > cMaxPNGSize) {
        m_failed = true;
        longjmp(png->jmpbuf, 1);
        return;
    }
    
    // We can fill in the size now that the header is available.
    if (!m_sizeAvailable) {
        m_sizeAvailable = true;
        m_size = IntSize(width, height);
    }

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

    // 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 (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);

    reader()->setHasAlpha(channels == 4);

    if (reader()->decodingSizeOnly()) {
        // If we only needed the size, halt the reader.     
        reader()->setReadOffset(m_data->size() - png->buffer_size);
        png->buffer_size = 0;
    }
}
void PLPNGDecoder::Open(PLDataSource *pDataSrc) {
  png_uint_32 width, height;

  m_png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, user_error_fn, user_warning_fn);
  PLASSERT(m_png_ptr);

  m_info_ptr = png_create_info_struct(m_png_ptr);
  PLASSERT(m_info_ptr);

  png_set_read_fn(m_png_ptr, (void*)pDataSrc, my_read_data);

  /* 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(m_png_ptr, m_info_ptr);

#ifdef DUMP_PNG_DATA
  debugLog("%s", toString(*m_png_ptr).cstr());
#endif

  png_get_IHDR(m_png_ptr, m_info_ptr, &width, &height, &m_bit_depth
              ,&m_color_type, NULL, NULL, NULL);


  if(  (m_color_type != PNG_COLOR_TYPE_RGB_ALPHA) 
   &&  (m_color_type != PNG_COLOR_TYPE_GRAY_ALPHA) 
   && ((m_color_type != PNG_COLOR_TYPE_RGB) || (m_bit_depth < 16))
    ) {

#ifdef PNG_READ_16_TO_8_SUPPORTED
    if(m_bit_depth == 16) {
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
      png_set_scale_16(png_ptr);
#else
      png_set_strip_16(png_ptr);
#endif
    }
#endif

    if(m_color_type == PNG_COLOR_TYPE_PALETTE) {
      png_set_expand(m_png_ptr);
    }
    if(m_bit_depth < 8) {
      png_set_expand(m_png_ptr);
    }
    if(png_get_valid(m_png_ptr, m_info_ptr, PNG_INFO_tRNS)) {
      png_set_expand(m_png_ptr);
    }
    if((m_color_type == PNG_COLOR_TYPE_GRAY) || (m_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) {
      png_set_gray_to_rgb(m_png_ptr);
    }

    /* set the background color to draw transparent and alpha images over */
    png_color_16 *pBackground;
    png_color     bkgColor = {127, 127, 127};
    if(png_get_bKGD(m_png_ptr, m_info_ptr, &pBackground)) {
      png_set_background(m_png_ptr, pBackground, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
      bkgColor.red   = (png_byte)pBackground->red;
      bkgColor.green = (png_byte)pBackground->green;
      bkgColor.blue  = (png_byte)pBackground->blue;

#ifdef DUMP_PNG_DATA
      debugLog("  Background         : (%d,%d,%d)\n", bkgColor.red, bkgColor.green, bkgColor.blue);
#endif
  }

    /* if required set gamma conversion */
    double dGamma;
    if(png_get_gAMA(m_png_ptr, m_info_ptr, &dGamma)) {
      png_set_gamma(m_png_ptr, (double)2.2, dGamma);
    }

    /* after the transformations are registered, update info_ptr data */
    png_read_update_info(m_png_ptr, m_info_ptr);

    png_get_IHDR(m_png_ptr, m_info_ptr, &width, &height, &m_bit_depth
                ,&m_color_type, NULL, NULL, NULL);

  }

  PLPixelFormat pf;
  switch(m_color_type) {
    case PNG_COLOR_TYPE_RGB:  
      pf = PLPixelFormat::R8G8B8;
      break;
    case PNG_COLOR_TYPE_RGB_ALPHA:      
      pf = PLPixelFormat::A8R8G8B8;
      break;
    case PNG_COLOR_TYPE_GRAY:
      pf = PLPixelFormat::L8;
      break;
    case PNG_COLOR_TYPE_GRAY_ALPHA:      
      png_set_gray_to_rgb(m_png_ptr);
      png_set_expand(m_png_ptr);      
      pf = PLPixelFormat::A8R8G8B8;
      break;
    case PNG_COLOR_TYPE_PALETTE:
      if(m_bit_depth != 16) {
        pf = PLPixelFormat::I8;
      } else { // 16-bit palette image
        png_set_expand(m_png_ptr);        
        pf = PLPixelFormat::R8G8B8;
      }
      break;
  }

  if((pf.GetBitsPerPixel() == 32) || (pf.GetBitsPerPixel() == 24)) { 
    png_set_bgr(m_png_ptr);
  }

  SetBmpInfo(PLPoint(width, height), PLPoint(0,0), pf);

  png_uint_32 XRes, YRes;
  int UnitType;
  png_get_pHYs(m_png_ptr, m_info_ptr, &XRes, &YRes, &UnitType);
  if(UnitType == PNG_RESOLUTION_METER) {
    m_Resolution = PLPoint(int (XRes/39.37f+0.5), int (YRes/39.37f+0.5));
  }
}
Beispiel #29
0
static int pngreadstr(FILE *fp,
                      int *w, int *h, int *nc,
                      png_structp png_ptr,
                      png_infop info_ptr,
                      unsigned char **ppixels,
                      unsigned char ***prows)
{
    png_uint_32 width, height;
    int bit_depth, color_type, interlace_type;
    int bytes_per_row, row;
    int gray_palette;
    unsigned char *pixels, **rows;

    /* 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_ptr->jmpbuf)) */
    if (setjmp(png_jmpbuf(png_ptr)))
    {
        /* If we get here, we had a problem reading the file */
        return 0;
    }

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

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

    *nc = png_get_channels(png_ptr, info_ptr);
    /*printf("color_type %d, nc = %d ", color_type, *nc);*/

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

    /* 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 */
    if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
        /* Even gray paletted images will get expanded here */
        png_set_expand(png_ptr);
        *nc = 3;
    }

    /* 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_expand(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_expand(png_ptr);
        ++(*nc);
    }

    gray_palette = 0;
    if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
        int n, num_palette;
        png_colorp palette;
        if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette))
        {
            gray_palette = 1;
            for (n = 0; n < num_palette; ++n)
                if (palette[n].red != palette[n].green || palette[n].blue != palette[n].green)
                {
                    gray_palette = 0;
                    break;
                }
        }
    }

    /* set gamma */
    {
        double file_gamma, default_exponent = get_gamma_exp();
        default_exponent = 1.7;
        if (png_get_gAMA(png_ptr, info_ptr, &file_gamma))
        {
            /* fprintf(stderr,"default_exponent, FileGamma: %f,%f\n" ,default_exponent,file_gamma); */

            png_set_gamma(png_ptr, default_exponent, file_gamma);
            /* png_set_gamma(png_ptr, default_exponent, 1.7); */
        }
        else
        {
            png_set_gamma(png_ptr, default_exponent, 0.45455);
            /* png_set_gamma(png_ptr, default_exponent, 1.7); */
            /* fprintf(stderr,"DefaultGamma: 1.7\n"); */
        }
    }

    /* Get updated info */
    png_read_update_info(png_ptr, info_ptr);
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
                 &interlace_type, NULL, NULL);

    /* Allocate the memory to hold the image using the fields of info_ptr. */
    bytes_per_row = *nc * width;

    *ppixels = (unsigned char *)malloc(bytes_per_row * height);
    *prows = (unsigned char **)malloc(height * sizeof(char *));
    if (*ppixels == 0 || *prows == 0)
    {
        /* Free all of the memory associated with the png_ptr and info_ptr */
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
        return 0;
    }

    pixels = *ppixels;
    rows = *prows;
    for (row = 0; row < height; ++row)
        rows[row] = &pixels[row * bytes_per_row];

    /* Now it's time to read the image.  One of these methods is REQUIRED */
    /* Read the entire image in one go */
    png_read_image(png_ptr, rows);

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

    /* clean up after the read, and free any memory allocated - REQUIRED */
    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);

    /* Reduce gray palette images down to intensity or intensity/alpha */
    if (gray_palette)
    {
        int n, np = width * height;
        if (*nc == 3)
        {
            for (n = 1; n < np; ++n)
                pixels[n] = pixels[3 * n];
            *nc = 1;
        }
        else if (*nc == 4)
        {
            for (n = 0; n < np; ++n)
            {
                pixels[2 * n] = pixels[4 * n];
                pixels[2 * n + 1] = pixels[4 * n + 3];
            }
            *nc = 2;
        }
    }

    *w = width;
    *h = height;
    return 1;
}
Beispiel #30
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);
}