Пример #1
0
/*
 *  fgetPngResolution()
 *
 *      Input:  stream (opened for read)
 *              &xres, &yres (<return> resolution in ppi)
 *      Return: 0 if OK; 0 on error
 *
 *  Notes:
 *      (1) If neither resolution field is set, this is not an error;
 *          the returned resolution values are 0 (designating 'unknown').
 *      (2) Side-effect: this rewinds the stream.
 */
l_int32
fgetPngResolution(FILE     *fp,
                  l_int32  *pxres,
                  l_int32  *pyres)
{
png_uint_32  xres, yres;
png_structp  png_ptr;
png_infop    info_ptr;

    PROCNAME("fgetPngResolution");

    if (!pxres || !pyres)
        return ERROR_INT("&xres and &yres not both defined", procName, 1);
    *pxres = *pyres = 0;
    if (!fp)
        return ERROR_INT("stream not opened", procName, 1);

       /* Make the two required structs */
   if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                   (png_voidp)NULL, NULL, NULL)) == NULL)
        return ERROR_INT("png_ptr not made", procName, 1);
    if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
        png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
        return ERROR_INT("info_ptr not made", procName, 1);
    }

        /* Set up png setjmp error handling.
         * Without this, an error calls exit. */
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
        return ERROR_INT("internal png error", procName, 1);
    }

        /* Read the metadata */
    rewind(fp);
    png_init_io(png_ptr, fp);
    png_read_png(png_ptr, info_ptr, 0, NULL);

    xres = png_get_x_pixels_per_meter(png_ptr, info_ptr);
    yres = png_get_y_pixels_per_meter(png_ptr, info_ptr);
    *pxres = (l_int32)((l_float32)xres / 39.37 + 0.5);  /* to ppi */
    *pyres = (l_int32)((l_float32)yres / 39.37 + 0.5);

    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    rewind(fp);
    return 0;
}
Пример #2
0
int
png_get_bbox (FILE *png_file, uint32_t *width, uint32_t *height,
	       double *xdensity, double *ydensity)
{
  png_structp png_ptr;
  png_infop   png_info_ptr;

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

  /* 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);
  *width      = png_get_image_width (png_ptr, png_info_ptr);
  *height     = png_get_image_height(png_ptr, png_info_ptr);

  if (compat_mode)
    *xdensity = *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);

    *xdensity = xppm ? 72.0 / 0.0254 / xppm : 1.0;
    *ydensity = yppm ? 72.0 / 0.0254 / yppm : 1.0;
  }

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

  return 0;
}
Пример #3
0
int					/* O - Read status */
_cupsImageReadPNG(
    cups_image_t    *img,		/* IO - cupsImage */
    FILE            *fp,		/* I - cupsImage file */
    cups_icspace_t  primary,		/* I - Primary choice for colorspace */
    cups_icspace_t  secondary,		/* I - Secondary choice for colorspace */
    int             saturation,		/* I - Color saturation (%) */
    int             hue,		/* I - Color hue (degrees) */
    const cups_ib_t *lut)		/* I - Lookup table for gamma/brightness */
{
  int		y;			/* Looping var */
  png_structp	pp;			/* PNG read pointer */
  png_infop	info;			/* PNG info pointers */
  png_uint_32	width,			/* Width of image */
		height;			/* Height of image */
  int		bit_depth,		/* Bit depth */
		color_type,		/* Color type */
		interlace_type,		/* Interlace type */
		compression_type,	/* Compression type */
		filter_type;		/* Filter type */
  png_uint_32	xppm,			/* X pixels per meter */
		yppm;			/* Y pixels per meter */
  int		bpp;			/* Bytes per pixel */
  int		pass,			/* Current pass */
		passes;			/* Number of passes required */
  cups_ib_t	*in,			/* Input pixels */
		*inptr,			/* Pointer into pixels */
		*out;			/* Output pixels */
  png_color_16	bg;			/* Background color */


 /*
  * Setup the PNG data structures...
  */

  pp   = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  info = png_create_info_struct(pp);

 /*
  * Initialize the PNG read "engine"...
  */

  png_init_io(pp, fp);

 /*
  * Get the image dimensions and load the output image...
  */

  png_read_info(pp, info);

  png_get_IHDR(pp, info, &width, &height, &bit_depth, &color_type,
               &interlace_type, &compression_type, &filter_type);

  fprintf(stderr, "DEBUG: PNG image: %dx%dx%d, color_type=%x (%s%s%s)\n",
          (int)width, (int)height, bit_depth, color_type,
	  (color_type & PNG_COLOR_MASK_COLOR) ? "RGB" : "GRAYSCALE",
	  (color_type & PNG_COLOR_MASK_ALPHA) ? "+ALPHA" : "",
	  (color_type & PNG_COLOR_MASK_PALETTE) ? "+PALETTE" : "");

  if (color_type & PNG_COLOR_MASK_PALETTE)
    png_set_expand(pp);
  else if (bit_depth < 8)
  {
    png_set_packing(pp);
    png_set_expand(pp);
  }
  else if (bit_depth == 16)
    png_set_strip_16(pp);

  if (color_type & PNG_COLOR_MASK_COLOR)
    img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB :
                                                         primary;
  else
    img->colorspace = secondary;

  if (width == 0 || width > CUPS_IMAGE_MAX_WIDTH ||
      height == 0 || height > CUPS_IMAGE_MAX_HEIGHT)
  {
    fprintf(stderr, "DEBUG: PNG image has invalid dimensions %ux%u!\n",
            (unsigned)width, (unsigned)height);
    fclose(fp);
    return (1);
  }

  img->xsize = width;
  img->ysize = height;

  if ((xppm = png_get_x_pixels_per_meter(pp, info)) != 0 &&
      (yppm = png_get_y_pixels_per_meter(pp, info)) != 0)
  {
    img->xppi = (int)((float)xppm * 0.0254);
    img->yppi = (int)((float)yppm * 0.0254);

    if (img->xppi == 0 || img->yppi == 0)
    {
      fprintf(stderr, "DEBUG: PNG image has invalid resolution %dx%d PPI\n",
              img->xppi, img->yppi);

      img->xppi = img->yppi = 128;
    }
  }

  cupsImageSetMaxTiles(img, 0);

  passes = png_set_interlace_handling(pp);

 /*
  * Handle transparency...
  */

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

  bg.red   = 65535;
  bg.green = 65535;
  bg.blue  = 65535;

  png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);

  if (passes == 1)
  {
   /*
    * Load one row at a time...
    */

    if (color_type == PNG_COLOR_TYPE_GRAY ||
	color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
      in = malloc(img->xsize);
    else
      in = malloc(img->xsize * 3);
  }
  else
  {
   /*
    * Interlaced images must be loaded all at once...
    */

    size_t bufsize;			/* Size of buffer */


    if (color_type == PNG_COLOR_TYPE_GRAY ||
	color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
    {
      bufsize = img->xsize * img->ysize;

      if ((bufsize / img->ysize) != img->xsize)
      {
	fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n",
		(unsigned)width, (unsigned)height);
	fclose(fp);
	return (1);
      }
    }
    else
    {
      bufsize = img->xsize * img->ysize * 3;

      if ((bufsize / (img->ysize * 3)) != img->xsize)
      {
	fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n",
		(unsigned)width, (unsigned)height);
	fclose(fp);
	return (1);
      }
    }

    in = malloc(bufsize);
  }

  bpp = cupsImageGetDepth(img);
  out = malloc(img->xsize * bpp);

  if (!in || !out)
  {
    fputs("DEBUG: Unable to allocate memory for PNG image!\n", stderr);

    if (in)
      free(in);

    if (out)
      free(out);

    fclose(fp);

    return (1);
  }

 /*
  * Read the image, interlacing as needed...
  */

  for (pass = 1; pass <= passes; pass ++)
    for (inptr = in, y = 0; y < img->ysize; y ++)
    {
      png_read_row(pp, (png_bytep)inptr, NULL);

      if (pass == passes)
      {
       /*
        * Output this row...
	*/

	if (color_type & PNG_COLOR_MASK_COLOR)
	{
	  if ((saturation != 100 || hue != 0) && bpp > 1)
	    cupsImageRGBAdjust(inptr, img->xsize, saturation, hue);

	  switch (img->colorspace)
	  {
	    case CUPS_IMAGE_WHITE :
		cupsImageRGBToWhite(inptr, out, img->xsize);
		break;
	    case CUPS_IMAGE_RGB :
	    case CUPS_IMAGE_RGB_CMYK :
		cupsImageRGBToRGB(inptr, out, img->xsize);
		break;
	    case CUPS_IMAGE_BLACK :
		cupsImageRGBToBlack(inptr, out, img->xsize);
		break;
	    case CUPS_IMAGE_CMY :
		cupsImageRGBToCMY(inptr, out, img->xsize);
		break;
	    case CUPS_IMAGE_CMYK :
		cupsImageRGBToCMYK(inptr, out, img->xsize);
		break;
	  }
	}
	else
	{
	  switch (img->colorspace)
	  {
	    case CUPS_IMAGE_WHITE :
		memcpy(out, inptr, img->xsize);
		break;
	    case CUPS_IMAGE_RGB :
	    case CUPS_IMAGE_RGB_CMYK :
		cupsImageWhiteToRGB(inptr, out, img->xsize);
		break;
	    case CUPS_IMAGE_BLACK :
		cupsImageWhiteToBlack(inptr, out, img->xsize);
		break;
	    case CUPS_IMAGE_CMY :
		cupsImageWhiteToCMY(inptr, out, img->xsize);
		break;
	    case CUPS_IMAGE_CMYK :
		cupsImageWhiteToCMYK(inptr, out, img->xsize);
		break;
	  }
	}

	if (lut)
	  cupsImageLut(out, img->xsize * bpp, lut);

	_cupsImagePutRow(img, 0, y, img->xsize, out);
      }

      if (passes > 1)
      {
	if (color_type & PNG_COLOR_MASK_COLOR)
          inptr += img->xsize * 3;
	else
          inptr += img->xsize;
      }
    }

  png_read_end(pp, info);
  png_destroy_read_struct(&pp, &info, NULL);

  fclose(fp);
  free(in);
  free(out);

  return (0);
}
Пример #4
0
/*!
 *  pixReadStreamPng()
 *
 *      Input:  stream
 *      Return: pix, or null on error
 *
 *  Notes:
 *      (1) If called from pixReadStream(), the stream is positioned
 *          at the beginning of the file.
 *      (2) To do sequential reads of png format images from a stream,
 *          use pixReadStreamPng()
 */
PIX *
pixReadStreamPng(FILE  *fp)
{
l_uint8      rval, gval, bval;
l_int32      i, j, k;
l_int32      wpl, d, spp, cindex;
l_uint32     png_transforms;
l_uint32    *data, *line, *ppixel;
int          num_palette, num_text;
png_byte     bit_depth, color_type, channels;
png_uint_32  w, h, rowbytes;
png_uint_32  xres, yres;
png_bytep    rowptr;
png_bytep   *row_pointers;
png_structp  png_ptr;
png_infop    info_ptr, end_info;
png_colorp   palette;
png_textp    text_ptr;  /* ptr to text_chunk */
PIX         *pix;
PIXCMAP     *cmap;

    PROCNAME("pixReadStreamPng");

    if (!fp)
        return (PIX *)ERROR_PTR("fp not defined", procName, NULL);
    pix = NULL;

        /* Allocate the 3 data structures */
    if ((png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                   (png_voidp)NULL, NULL, NULL)) == NULL)
        return (PIX *)ERROR_PTR("png_ptr not made", procName, NULL);

    if ((info_ptr = png_create_info_struct(png_ptr)) == NULL) {
        png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
        return (PIX *)ERROR_PTR("info_ptr not made", procName, NULL);
    }

    if ((end_info = png_create_info_struct(png_ptr)) == NULL) {
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
        return (PIX *)ERROR_PTR("end_info not made", procName, NULL);
    }

        /* Set up png setjmp error handling */
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return (PIX *)ERROR_PTR("internal png error", procName, NULL);
    }

    png_init_io(png_ptr, fp);

        /* ---------------------------------------------------------- *
         *  Set the transforms flags.  Whatever happens here,
         *  NEVER invert 1 bpp using PNG_TRANSFORM_INVERT_MONO.
         * ---------------------------------------------------------- */
        /* To strip 16 --> 8 bit depth, use PNG_TRANSFORM_STRIP_16 */
    if (var_PNG_STRIP_16_TO_8 == 1)   /* our default */
        png_transforms = PNG_TRANSFORM_STRIP_16;
    else
        png_transforms = PNG_TRANSFORM_IDENTITY;
        /* To remove alpha channel, use PNG_TRANSFORM_STRIP_ALPHA */
    if (var_PNG_STRIP_ALPHA == 1)   /* our default */
        png_transforms |= PNG_TRANSFORM_STRIP_ALPHA;

        /* Read it */
    png_read_png(png_ptr, info_ptr, png_transforms, NULL);

    row_pointers = png_get_rows(png_ptr, info_ptr);
    w = png_get_image_width(png_ptr, info_ptr);
    h = png_get_image_height(png_ptr, info_ptr);
    bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    color_type = png_get_color_type(png_ptr, info_ptr);
    channels = png_get_channels(png_ptr, info_ptr);
    spp = channels;

    if (spp == 1)
        d = bit_depth;
    else if (spp == 2) {
        d = 2 * bit_depth;
        L_WARNING("there shouldn't be 2 spp!", procName);
    }
    else  /* spp == 3 (rgb), spp == 4 (rgba) */
        d = 4 * bit_depth;

        /* Remove if/when this is implemented for all bit_depths */
    if (spp == 3 && bit_depth != 8) {
        fprintf(stderr, "Help: spp = 3 and depth = %d != 8\n!!", bit_depth);
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return (PIX *)ERROR_PTR("not implemented for this depth",
            procName, NULL);
    }

    if (color_type == PNG_COLOR_TYPE_PALETTE ||
        color_type == PNG_COLOR_MASK_PALETTE) {   /* generate a colormap */
        png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
        cmap = pixcmapCreate(d);  /* spp == 1 */
        for (cindex = 0; cindex < num_palette; cindex++) {
            rval = palette[cindex].red;
            gval = palette[cindex].green;
            bval = palette[cindex].blue;
            pixcmapAddColor(cmap, rval, gval, bval);
        }
    }
    else
        cmap = NULL;

    if ((pix = pixCreate(w, h, d)) == NULL) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return (PIX *)ERROR_PTR("pix not made", procName, NULL);
    }
    wpl = pixGetWpl(pix);
    data = pixGetData(pix);
    pixSetColormap(pix, cmap);

    if (spp == 1) {   /* copy straight from buffer to pix */
        for (i = 0; i < h; i++) {
            line = data + i * wpl;
            rowptr = row_pointers[i];
            for (j = 0; j < rowbytes; j++) {
                SET_DATA_BYTE(line, j, rowptr[j]);
            }
        }
    }
    else  {   /* spp == 3 or spp == 4 */
        for (i = 0; i < h; i++) {
            ppixel = data + i * wpl;
            rowptr = row_pointers[i];
            for (j = k = 0; j < w; j++) {
                SET_DATA_BYTE(ppixel, COLOR_RED, rowptr[k++]);
                SET_DATA_BYTE(ppixel, COLOR_GREEN, rowptr[k++]);
                SET_DATA_BYTE(ppixel, COLOR_BLUE, rowptr[k++]);
                if (spp == 4)
                    SET_DATA_BYTE(ppixel, L_ALPHA_CHANNEL, rowptr[k++]);
                ppixel++;
            }
        }
    }

#if  DEBUG
    if (cmap) {
        for (i = 0; i < 16; i++) {
            fprintf(stderr, "[%d] = %d\n", i,
                   ((l_uint8 *)(cmap->array))[i]);
        }
    }
#endif  /* DEBUG */

        /* If there is no colormap, PNG defines black = 0 and
         * white = 1 by default for binary monochrome.  Therefore,
         * since we use the opposite definition, we must invert
         * the image colors in either of these cases:
         *    (i) there is no colormap (default)
         *    (ii) there is a colormap which defines black to
         *         be 0 and white to be 1.
         * We cannot use the PNG_TRANSFORM_INVERT_MONO flag
         * because that flag (since version 1.0.9) inverts 8 bpp
         * grayscale as well, which we don't want to do.
         * (It also doesn't work if there is a colormap.)
         * If there is a colormap that defines black = 1 and
         * white = 0, we don't need to do anything.
         *
         * How do we check the polarity of the colormap?
         * The colormap determines the values of black and
         * white pixels in the following way:
         *     if black = 1 (255), white = 0
         *          255, 255, 255, 0, 0, 0, 0, 0, 0
         *     if black = 0, white = 1 (255)
         *          0, 0, 0, 0, 255, 255, 255, 0
         * So we test the first byte to see if it is 0;
         * if so, invert the colors.
         *
         * If there is a colormap, after inverting the pixels it is
         * necessary to destroy the colormap.  Otherwise, if someone were
         * to call pixRemoveColormap(), this would cause the pixel
         * values to be inverted again!
         */
    if (d == 1 && (!cmap || (cmap && ((l_uint8 *)(cmap->array))[0] == 0x0))) {
/*        fprintf(stderr, "Inverting binary data on png read\n"); */
        pixInvert(pix, pix);
        pixDestroyColormap(pix);
    }

    xres = png_get_x_pixels_per_meter(png_ptr, info_ptr);
    yres = png_get_y_pixels_per_meter(png_ptr, info_ptr);
    pixSetXRes(pix, (l_int32)((l_float32)xres / 39.37 + 0.5));  /* to ppi */
    pixSetYRes(pix, (l_int32)((l_float32)yres / 39.37 + 0.5));  /* to ppi */

        /* Get the text if there is any */
    png_get_text(png_ptr, info_ptr, &text_ptr, &num_text);
    if (num_text && text_ptr)
        pixSetText(pix, text_ptr->text);

    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
    return pix;
}
Пример #5
0
png_uint_32 PNGAPI
png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
{
   return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr)
     *.0254 +.5));
}
Пример #6
0
static void _png_load_bmp_attribute(png_structp png_ptr,
                                    png_infop info_ptr,
                                    CFX_DIBAttribute* pAttribute) {
  if (pAttribute) {
#if defined(PNG_pHYs_SUPPORTED)
    pAttribute->m_nXDPI = png_get_x_pixels_per_meter(png_ptr, info_ptr);
    pAttribute->m_nYDPI = png_get_y_pixels_per_meter(png_ptr, info_ptr);
    png_uint_32 res_x, res_y;
    int unit_type;
    png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type);
    switch (unit_type) {
      case PNG_RESOLUTION_METER:
        pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_METER;
        break;
      default:
        pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_NONE;
    }
#endif
#if defined(PNG_iCCP_SUPPORTED)
    png_charp icc_name;
    png_bytep icc_profile;
    png_uint_32 icc_proflen;
    int compress_type;
    png_get_iCCP(png_ptr, info_ptr, &icc_name, &compress_type, &icc_profile,
                 &icc_proflen);
#endif
    int bTime = 0;
#if defined(PNG_tIME_SUPPORTED)
    png_timep t = nullptr;
    png_get_tIME(png_ptr, info_ptr, &t);
    if (t) {
      FXSYS_memset(pAttribute->m_strTime, 0, sizeof(pAttribute->m_strTime));
      FXSYS_snprintf((FX_CHAR*)pAttribute->m_strTime,
                     sizeof(pAttribute->m_strTime), "%4u:%2u:%2u %2u:%2u:%2u",
                     t->year, t->month, t->day, t->hour, t->minute, t->second);
      pAttribute->m_strTime[sizeof(pAttribute->m_strTime) - 1] = 0;
      bTime = 1;
    }
#endif
#if defined(PNG_TEXT_SUPPORTED)
    int i;
    FX_STRSIZE len;
    const FX_CHAR* buf;
    int num_text;
    png_textp text = nullptr;
    png_get_text(png_ptr, info_ptr, &text, &num_text);
    for (i = 0; i < num_text; i++) {
      len = FXSYS_strlen(text[i].key);
      buf = "Time";
      if (!FXSYS_memcmp(buf, text[i].key, std::min(len, FXSYS_strlen(buf)))) {
        if (!bTime) {
          FXSYS_memset(pAttribute->m_strTime, 0, sizeof(pAttribute->m_strTime));
          FXSYS_memcpy(
              pAttribute->m_strTime, text[i].text,
              std::min(sizeof(pAttribute->m_strTime) - 1, text[i].text_length));
        }
      } else {
        buf = "Author";
        if (!FXSYS_memcmp(buf, text[i].key, std::min(len, FXSYS_strlen(buf)))) {
          pAttribute->m_strAuthor =
              CFX_ByteString(reinterpret_cast<uint8_t*>(text[i].text),
                             static_cast<FX_STRSIZE>(text[i].text_length));
        }
      }
    }
#endif
  }
}
Пример #7
0
BOOL OutputPNG::OutputPNGHeader(CCLexFile *File, LPBITMAPINFOHEADER pInfo,
                                BOOL InterlaceState, INT32 TransparentColour,
                                LPLOGPALETTE pPalette, LPRGBQUAD pQuadPalette)
{
    ERROR2IF(File==NULL,FALSE,"OutputPNG::OutputPNGHeader File pointer is null");
    if (pInfo == NULL)
        pInfo = &(DestBitmapInfo->bmiHeader);
    ERROR2IF(pInfo==NULL,FALSE,"OutputPNG::OutputPNGHeader BitmapInfo pointer is null");
    //ERROR2IF(pPalette==NULL && pQuadPalette==NULL,FALSE,"OutputPNG::OutputPNGHeader Bitmap palette pointer is null");

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

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

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

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

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

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

    palette = NULL;

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

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

        BitsPerPixel = pInfo->biBitCount;

        // Start up the PNG writing code

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

        png_set_bgr(png_ptr);

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

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

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

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

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

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

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

        return FALSE;
    }

    ERROR2( FALSE, "Escaped exception clause somehow" );
}
bool PNGImageFileType::read(      Image        *OSG_PNG_ARG(pImage  ), 
                                  std::istream &OSG_PNG_ARG(is      ),
                            const std::string  &OSG_PNG_ARG(mimetype))
{
#ifdef OSG_WITH_PNG

    bool                retCode;
    Image::PixelFormat  pixelFormat = OSG::Image::OSG_INVALID_PF;
    png_structp         png_ptr;
    png_infop           info_ptr;
    png_uint_32         width, wc, height, h, i, res_x, res_y;
    png_byte            bit_depth, channels, color_type;
    png_bytep           *row_pointers, base;

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

    if(!png_ptr)
        return false;

    png_set_error_fn(png_ptr, 0, &errorOutput, &warningOutput);

    info_ptr = png_create_info_struct(png_ptr);

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

    if(setjmp(png_ptr->jmpbuf))
    {
        png_destroy_read_struct(&png_ptr, &info_ptr, 0);
        return false;
    }

    png_set_read_fn(png_ptr, &is, &isReadFunc);

    png_read_info(png_ptr, info_ptr);

    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);
    bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    res_x = png_get_x_pixels_per_meter(png_ptr, info_ptr);
    res_y = png_get_y_pixels_per_meter(png_ptr, info_ptr);
    channels = png_get_channels(png_ptr, info_ptr);
    color_type = png_get_color_type(png_ptr, info_ptr);

    // Convert paletted images to RGB
    if (color_type == PNG_COLOR_TYPE_PALETTE)
    {
        png_set_palette_to_rgb(png_ptr);
        channels = 3;
        bit_depth = 8;
    }

    // Convert < 8 bit to 8 bit
    if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
    {
        png_set_gray_1_2_4_to_8(png_ptr);
        bit_depth = 8;
    }

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

    // Add 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);
        ++channels;
    } 

    Int32 dataType;

    switch (bit_depth) 
    {
        case 8:
            dataType = Image::OSG_UINT8_IMAGEDATA;
            break;
        case 16:
            dataType = Image::OSG_UINT16_IMAGEDATA;
            break;
        default:
            FWARNING (( "Invalid bit_depth: %d, can not read png-data\n",
                        bit_depth ));
            return false;
    }

    switch(channels)
    {
        case 1:
            pixelFormat = Image::OSG_L_PF;
            break;
        case 2:
            pixelFormat = Image::OSG_LA_PF;
            break;
        case 3:
            pixelFormat = Image::OSG_RGB_PF;
            break;
        case 4:
            pixelFormat = Image::OSG_RGBA_PF;
        break;
    };
    
    if(pImage->set(pixelFormat, width, height,
                   1, 1, 1, 0.0, 0,
                   dataType))
    {
        // set resolution png supports only pixel per meter,
        // so we do a conversion to dpi with some rounding.
        res_x = png_uint_32((Real32(res_x) / 39.37007874f) < 0.0f ?
                            (Real32(res_x) / 39.37007874f) - 0.5f :
                            (Real32(res_x) / 39.37007874f) + 0.5f);
        res_y = png_uint_32((Real32(res_y) / 39.37007874f) < 0.0f ?
                            (Real32(res_y) / 39.37007874f) - 0.5f :
                            (Real32(res_y) / 39.37007874f) + 0.5f);

        pImage->setResX(Real32(res_x));
        pImage->setResY(Real32(res_y));
        pImage->setResUnit(Image::OSG_RESUNIT_INCH);

        // Calculate the row pointers
        row_pointers = new png_bytep[height];
        wc = width * channels * (bit_depth / 8);
        h = height - 1;
        base = pImage->editData();

        for(i = 0; i < height; ++i)
            row_pointers[i] = base + (h - i) * wc;

        // Read the image data
        png_read_image(png_ptr, row_pointers);

        delete[] row_pointers;

        retCode = true;
    }
    else
    {
        retCode = false;
    }

    png_destroy_read_struct(&png_ptr, &info_ptr, 0);

    return retCode;

#else

    SWARNING << getMimeType() 
             << " read is not compiled into the current binary " 
             << std::endl;

    return false;

#endif

}
Пример #9
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;
}
Пример #10
0
bool Q_INTERNAL_WIN_NO_THROW QPngHandlerPrivate::readPngImage(QImage *outImage)
{
    if (state == Error)
        return false;

    if (state == Ready && !readPngHeader()) {
        state = Error;
        return false;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        png_ptr = 0;
        amp.deallocate();
        state = Error;
        return false;
    }

    bool doScaledRead = false;
    setup_qt(*outImage, png_ptr, info_ptr, scaledSize, &doScaledRead, gamma, fileGamma);

    if (outImage->isNull()) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        png_ptr = 0;
        amp.deallocate();
        state = Error;
        return false;
    }

    if (doScaledRead) {
        read_image_scaled(outImage, png_ptr, info_ptr, amp, scaledSize);
    } else {
        png_uint_32 width = 0;
        png_uint_32 height = 0;
        png_int_32 offset_x = 0;
        png_int_32 offset_y = 0;

        int bit_depth = 0;
        int color_type = 0;
        int unit_type = PNG_OFFSET_PIXEL;
        png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
        png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &unit_type);
        uchar *data = outImage->bits();
        int bpl = outImage->bytesPerLine();
        amp.row_pointers = new png_bytep[height];

        for (uint y = 0; y < height; y++)
            amp.row_pointers[y] = data + y * bpl;

        png_read_image(png_ptr, amp.row_pointers);
        amp.deallocate();

        outImage->setDotsPerMeterX(png_get_x_pixels_per_meter(png_ptr,info_ptr));
        outImage->setDotsPerMeterY(png_get_y_pixels_per_meter(png_ptr,info_ptr));

        if (unit_type == PNG_OFFSET_PIXEL)
            outImage->setOffset(QPoint(offset_x, offset_y));

        // sanity check palette entries
        if (color_type == PNG_COLOR_TYPE_PALETTE && outImage->format() == QImage::Format_Indexed8) {
            int color_table_size = outImage->colorCount();
            for (int y=0; y<(int)height; ++y) {
                uchar *p = FAST_SCAN_LINE(data, bpl, y);
                uchar *end = p + width;
                while (p < end) {
                    if (*p >= color_table_size)
                        *p = 0;
                    ++p;
                }
            }
        }
    }

    state = ReadingEnd;
    png_read_end(png_ptr, end_info);

    readPngTexts(end_info);
    for (int i = 0; i < readTexts.size()-1; i+=2)
        outImage->setText(readTexts.at(i), readTexts.at(i+1));

    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
    png_ptr = 0;
    amp.deallocate();
    state = Ready;

    if (scaledSize.isValid() && outImage->size() != scaledSize)
        *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);

    return true;
}
Пример #11
0
static void read_image_scaled(QImage *outImage, png_structp png_ptr, png_infop info_ptr,
                              QPngHandlerPrivate::AllocatedMemoryPointers &amp, QSize scaledSize)
{

    png_uint_32 width = 0;
    png_uint_32 height = 0;
    png_int_32 offset_x = 0;
    png_int_32 offset_y = 0;

    int bit_depth = 0;
    int color_type = 0;
    int unit_type = PNG_OFFSET_PIXEL;
    png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0);
    png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &unit_type);
    uchar *data = outImage->bits();
    int bpl = outImage->bytesPerLine();

    if (scaledSize.isEmpty() || !width || !height)
        return;

    const quint32 iysz = height;
    const quint32 ixsz = width;
    const quint32 oysz = scaledSize.height();
    const quint32 oxsz = scaledSize.width();
    const quint32 ibw = 4*width;
    amp.accRow = new quint32[ibw];
    memset(amp.accRow, 0, ibw*sizeof(quint32));
    amp.inRow = new png_byte[ibw];
    memset(amp.inRow, 0, ibw*sizeof(png_byte));
    amp.outRow = new uchar[ibw];
    memset(amp.outRow, 0, ibw*sizeof(uchar));
    qint32 rval = 0;
    for (quint32 oy=0; oy<oysz; oy++) {
        // Store the rest of the previous input row, if any
        for (quint32 i=0; i < ibw; i++)
            amp.accRow[i] = rval*amp.inRow[i];
        // Accumulate the next input rows
        for (rval = iysz-rval; rval > 0; rval-=oysz) {
            png_read_row(png_ptr, amp.inRow, NULL);
            quint32 fact = qMin(oysz, quint32(rval));
            for (quint32 i=0; i < ibw; i++)
                amp.accRow[i] += fact*amp.inRow[i];
        }
        rval *= -1;

        // We have a full output row, store it
        for (quint32 i=0; i < ibw; i++)
            amp.outRow[i] = uchar(amp.accRow[i]/iysz);

        quint32 a[4] = {0, 0, 0, 0};
        qint32 cval = oxsz;
        quint32 ix = 0;
        for (quint32 ox=0; ox<oxsz; ox++) {
            for (quint32 i=0; i < 4; i++)
                a[i] = cval * amp.outRow[ix+i];
            for (cval = ixsz - cval; cval > 0; cval-=oxsz) {
                ix += 4;
                if (ix >= ibw)
                    break;            // Safety belt, should not happen
                quint32 fact = qMin(oxsz, quint32(cval));
                for (quint32 i=0; i < 4; i++)
                    a[i] += fact * amp.outRow[ix+i];
            }
            cval *= -1;
            for (quint32 i=0; i < 4; i++)
                data[(4*ox)+i] = uchar(a[i]/ixsz);
        }
        data += bpl;
    }
    amp.deallocate();

    outImage->setDotsPerMeterX((png_get_x_pixels_per_meter(png_ptr,info_ptr)*oxsz)/ixsz);
    outImage->setDotsPerMeterY((png_get_y_pixels_per_meter(png_ptr,info_ptr)*oysz)/iysz);

    if (unit_type == PNG_OFFSET_PIXEL)
        outImage->setOffset(QPoint(offset_x*oxsz/ixsz, offset_y*oysz/iysz));

}
Пример #12
0
png_uint_32
png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
{
   return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr)
     *.03937 +.5)
}