Beispiel #1
0
/*!
    \internal
*/
void Q_INTERNAL_WIN_NO_THROW QPngHandlerPrivate::readPngTexts(png_info *info)
{
#ifndef QT_NO_IMAGE_TEXT
    png_textp text_ptr;
    int num_text=0;
    png_get_text(png_ptr, info, &text_ptr, &num_text);

    while (num_text--) {
        QString key, value;
        key = QString::fromLatin1(text_ptr->key);
#if defined(PNG_iTXt_SUPPORTED)
        if (text_ptr->itxt_length) {
            value = QString::fromUtf8(text_ptr->text, int(text_ptr->itxt_length));
        } else
#endif
        {
            value = QString::fromLatin1(text_ptr->text, int(text_ptr->text_length));
        }
        if (!description.isEmpty())
            description += QLatin1String("\n\n");
        description += key + QLatin1String(": ") + value.simplified();
        readTexts.append(key);
        readTexts.append(value);
        text_ptr++;
    }
#endif
}
bool emPngImageFileModel::TryContinueLoading() throw(emString)
{
	png_textp t;
	int e,i,n;

	if (!L->ImagePrepared) {
		Image.Setup(
			L->width,
			L->height,
			L->bytes_per_pixel
		);
		Signal(ChangeSignal);
		L->ImagePrepared=true;
		return false;
	}

	if (setjmp(L->jmpbuffer)) throw emString(L->errorText);

	if (L->y<(int)L->height && L->pass<L->number_of_passes) {
		png_read_row(
			L->png_ptr,
			Image.GetWritableMap()+L->y*Image.GetWidth()*Image.GetChannelCount(),
			NULL
		);
		L->y++;
		if (L->y>=(int)L->height) {
			L->y=0;
			L->pass++;
		}
		Signal(ChangeSignal);
		return false;
	}

	png_read_end(L->png_ptr,L->end_info_ptr);

	for (e=0; e<2; e++) {
		n=png_get_text(
			L->png_ptr,
			e ? L->end_info_ptr : L->info_ptr,
			&t,
			NULL
		);
		for (i=0; i<n; i++) {
			if (
				t[i].text && *t[i].text && t[i].key && (
					strcasecmp(t[i].key,"Comment")==0 ||
					strcasecmp(t[i].key,"Description")==0
				)
			) {
				if (!Comment.IsEmpty()) Comment+='\n';
				Comment+=t[i].text;
			}
		}
	}
	Signal(ChangeSignal);

	return true;
}
    /** \brief Get depth.
     *
     * Note that this function is expensive as depth is stored in comments.
     *
     * @return Depth as unsigned or 0.
     */
    unsigned getDepth() const
    {
      png_textp text_array;
      int text_count;

      if(png_get_text(m_png, m_info, &text_array, &text_count) > 0)
      {
        for(int ii = 0; (ii < text_count); ++ii)
        {
          png_textp text = text_array + ii;

          if(PNG_TEXT_DEPTH_KEYWORD.compare(text->key) == 0)
          {
            return boost::lexical_cast<unsigned>(text->text);
          }
        }
      }

      return 0; // No depth available equals 0.
    }
Beispiel #4
0
void
get_text(struct PNGImage *png)
{
	png_text *text;
	int i, numtxts, numremoved;

	png_get_text(png->png, png->info, &text, &numtxts);
	for (i = 0; i < numtxts; i++) {
		if (strcmp(text[i].key, "h") == 0 && !*text[i].text) {
			png->horizontal = true;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "x") == 0) {
			png->trim = strtoul(text[i].text, NULL, 0);
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "t") == 0) {
			png->mapfile = text[i].text;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "T") == 0 && !*text[i].text) {
			png->mapout = true;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "p") == 0) {
			png->palfile = text[i].text;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		} else if (strcmp(text[i].key, "P") == 0 && !*text[i].text) {
			png->palout = true;
			png_free_data(png->png, png->info, PNG_FREE_TEXT, i);
		}
	}

	/* TODO: Remove this and simply change the warning function not to warn instead. */
	for (i = 0, numremoved = 0; i < numtxts; i++) {
		if (text[i].key == NULL) {
			numremoved++;
		}
		text[i].key = text[i + numremoved].key;
		text[i].text = text[i + numremoved].text;
		text[i].compression = text[i + numremoved].compression;
	}
	png_set_text(png->png, png->info, text, numtxts - numremoved);
}
Beispiel #5
0
static BOOL 
ReadMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
	// XMP keyword
	const char *g_png_xmp_keyword = "XML:com.adobe.xmp";

	FITAG *tag = NULL;
	png_textp text_ptr = NULL;
	int num_text = 0;

	// iTXt/tEXt/zTXt chuncks
	if(png_get_text(png_ptr, info_ptr, &text_ptr, &num_text) > 0) {
		for(int i = 0; i < num_text; i++) {
			// create a tag
			tag = FreeImage_CreateTag();
			if(!tag) return FALSE;

			DWORD tag_length = (DWORD) MAX(text_ptr[i].text_length, text_ptr[i].itxt_length);

			FreeImage_SetTagLength(tag, tag_length);
			FreeImage_SetTagCount(tag, tag_length);
			FreeImage_SetTagType(tag, FIDT_ASCII);
			FreeImage_SetTagValue(tag, text_ptr[i].text);

			if(strcmp(text_ptr[i].key, g_png_xmp_keyword) == 0) {
				// store the tag as XMP
				FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
				FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);
			} else {
				// store the tag as a comment
				FreeImage_SetTagKey(tag, text_ptr[i].key);
				FreeImage_SetMetadata(FIMD_COMMENTS, dib, FreeImage_GetTagKey(tag), tag);
			}
			
			// destroy the tag
			FreeImage_DeleteTag(tag);
		}
	}

	return TRUE;
}
Beispiel #6
0
/*
	PNGのテキストチャンクからオフセットを読み込み、offsetにセットする関数
	※画像データの読み書きの前に呼び出さないといけない
	@cspecs テキストチャンクにアクセスするために必要
	@offset セットするwoff_t
*/
static void getOffsetFromChunk(woff_t *offset, struct png_control_specs *cspecs)
{
	png_text *text;
	int num_comments, num_text;

	/* コメントの取得 */
	num_comments = png_get_text(cspecs->png_ptr, cspecs->info_ptr, &text, &num_text);

	printf("num_comments : %d\n", num_comments);

	if(num_comments == 0){
		return;
	}

#ifdef DEBUG
	printf("[key words]\n%s\n", text->key);
	printf("[text body]\n%s\n", text->text);
#endif

	offset->total_bit = atoi(text->text);

	calcPixelOffset(offset, cspecs->shared_specs);	/* plane_no, x, y, colorを計算する */
}
Beispiel #7
0
void PNG::dump()
{
    // Text chunks
    png_textp textp = 0;
    int ntext = 0;
    png_get_text(mData, mInfo, &textp, &ntext);
    var text;
    for (int i=0; i<ntext; i++)
        text[textp[i].key] = textp[i].text;
    std::cout << "Text: " << text << std::endl;

    // EXIF
    // The library reports "png_get_eXIf does not work; use png_get_eXIf_1"
    png_bytep exif_data = 0;
    png_uint_32 num_exif = 0;
    png_uint_32 pngRet = png_get_eXIf_1(mData, mInfo, &num_exif, &exif_data);
    if (pngRet)
    {
        assert(exif_data);
        EXIF exif(exif_data, num_exif);
        exif.dump();
        std::cout << "EXIF date: " << exif.date() << std::endl;
    }
}
Beispiel #8
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
  }
}
Beispiel #9
0
gboolean
xdg_cache_cache_read_thumbnail_info (const gchar  *filename,
                                     gchar       **uri,
                                     guint64      *mtime,
                                     GCancellable *cancellable,
                                     GError      **error)
{
  png_structp png_ptr;
  png_infop   info_ptr;
  png_textp   text_ptr;
  gboolean    has_uri = FALSE;
  gboolean    has_mtime = FALSE;
  FILE       *png;
  gint        num_text;
  gint        i;

  g_return_val_if_fail (filename != NULL, FALSE);
  g_return_val_if_fail (uri != NULL, FALSE);
  g_return_val_if_fail (mtime != NULL, FALSE);
  g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);

  *uri = NULL;
  *mtime = 0;

  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    return FALSE;

  if ((png = g_fopen (filename, "r")) != NULL)
    {
      /* initialize the PNG reader */
      png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

      if (png_ptr)
        {
          /* initialize the info structure */
          info_ptr = png_create_info_struct (png_ptr);

          if (info_ptr)
            {
#ifdef PNG_SETJMP_SUPPORTED
              if (setjmp (png_jmpbuf (png_ptr)))
                {
                  /* finalize the PNG reader */
                  png_destroy_read_struct (&png_ptr, &info_ptr, NULL);

                  /* close the PNG file handle */
                  fclose (png);

                  return FALSE;
                }
#endif

              /* initialize reading from the file and read the file info */
              png_init_io (png_ptr, png);
              png_read_info (png_ptr, info_ptr);

              /* check if there is embedded text information */
              if (png_get_text (png_ptr, info_ptr, &text_ptr, &num_text) > 0)
                {
                  /* iterate over all text keys */
                  for (i = 0; !(has_uri && has_mtime) && i < num_text; ++i)
                    {
                      if (!text_ptr[i].key)
                        continue;

                      if (strcmp ("Thumb::URI", text_ptr[i].key) == 0)
                        {
                          /* remember the Thumb::URI value */
                          *uri = g_strdup (text_ptr[i].text);
                          has_uri = TRUE;
                        }
                      else if (strcmp ("Thumb::MTime", text_ptr[i].key) == 0)
                        {
                          /* remember the Thumb::MTime value */
                          if (text_ptr[i].text != NULL)
                            {
                              *mtime = atol (text_ptr[i].text);
                              has_mtime = TRUE;
                            }
                        }
                    }
                }
            }

          /* finalize the PNG reader */
          png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
        }

      /* close the PNG file handle */
      fclose (png);
    }

  return TRUE;
}
Beispiel #10
0
/**
 * @brief Opens an npng struct from an SDL_RWops. It does not close the RWops.
 *
 *    @param rw SDL_RWops to create npng from.
 *    @return npng created from rw.
 */
npng_t *npng_open( SDL_RWops *rw )
{
   png_byte header[8]; /* Maximum size to check. */
   npng_t *npng;

   /* Allocate memory. */
   npng = malloc( sizeof(npng_t) );
   if (npng == NULL) {
      WARN("Out of memory.");
      return NULL;
   }
   memset( npng, 0, sizeof(npng_t) );

   /* Set up struct. */
   npng->rw       = rw;
   npng->png_ptr  = png_create_read_struct( PNG_LIBPNG_VER_STRING, NULL, NULL, NULL );
   if (npng->png_ptr == NULL) {
      WARN("png_create_read_struct failed");
      goto ERR_FAIL;
   }
   npng->info_ptr = png_create_info_struct( npng->png_ptr );
   if (npng->info_ptr == NULL) {
      WARN("png_create_info_struct failed");
      goto ERR_FAIL;
   }

   /* Check header. */
   SDL_RWread( rw, header, 8, 1 );
   if (png_sig_cmp(header, 0, 8)) {
      WARN("RWops not recognized as a PNG file.");
      goto ERR_FAIL;
   }

   /* Set up for reading. */
   png_set_read_fn( npng->png_ptr, (png_voidp) rw, npng_read );

   /* Set up long jump for IO. */
   if (setjmp( png_jmpbuf( npng->png_ptr )) ) {
      WARN("Error during setjmp");
      goto ERR_FAIL;
   }

   /* We've already checked sig. */
   png_set_sig_bytes( npng->png_ptr, 8 );

   /* Get start. */
   npng->start = SDL_RWtell( npng->rw );

   /* Get info. */
   npng_info( npng );

   /* Load text. */
   png_get_text( npng->png_ptr, npng->info_ptr, &npng->text_ptr, &npng->num_text );

   return npng;

ERR_FAIL:
#if 0 /* Memory leaks are better than segfaults. */
   if (npng != NULL) {
      if (npng->png_ptr != NULL)
         png_destroy_read_struct( &npng->png_ptr, (npng->info_ptr != NULL) ? &npng->info_ptr : NULL, NULL );
      free(npng);
   }
#endif
   return NULL;
}
Beispiel #11
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;
}
Beispiel #12
0
s32 pngDecodeData(ppu_thread& ppu, PHandle handle, PStream stream, vm::ptr<u8> data, PDataControlParam data_control_param, PDataOutInfo data_out_info, PCbControlDisp cb_control_disp = vm::null, PDispParam disp_param = vm::null)
{
	// Indicate, that the PNG decoding is stopped/failed. This is incase, we return an error code in the middle of decoding
	data_out_info->status = CELL_PNGDEC_DEC_STATUS_STOP;

	const u32 bytes_per_line = data_control_param->outputBytesPerLine;

	// Log this for now
	if (bytes_per_line < stream->out_param.outputWidthByte)
	{
		fmt::throw_exception("Bytes per line less than expected output! Got: %d, expected: %d" HERE, bytes_per_line, stream->out_param.outputWidthByte);
	}

	// partial decoding
	if (cb_control_disp && stream->outputCounts > 0)
	{
		// get data from cb
		auto streamInfo = vm::ptr<CellPngDecStrmInfo>::make(handle->malloc_(ppu, sizeof(CellPngDecStrmInfo), handle->malloc_arg).addr());
		auto streamParam = vm::ptr<CellPngDecStrmParam>::make(handle->malloc_(ppu, sizeof(CellPngDecStrmParam), handle->malloc_arg).addr());
		stream->cbDispInfo = vm::ptr<CellPngDecDispInfo>::make(handle->malloc_(ppu, sizeof(CellPngDecDispInfo), handle->malloc_arg).addr());
		stream->cbDispParam = vm::ptr<CellPngDecDispParam>::make(handle->malloc_(ppu, sizeof(CellPngDecDispParam), handle->malloc_arg).addr());

		auto freeMem = [&]()
		{
			handle->free_(ppu, streamInfo, handle->free_arg);
			handle->free_(ppu, streamParam, handle->free_arg);
			handle->free_(ppu, stream->cbDispInfo, handle->free_arg);
			handle->free_(ppu, stream->cbDispParam, handle->free_arg);
		};

		// set things that won't change between callbacks
		stream->cbDispInfo->outputFrameWidthByte = bytes_per_line;
		stream->cbDispInfo->outputFrameHeight = stream->out_param.outputHeight;
		stream->cbDispInfo->outputWidthByte = stream->out_param.outputWidthByte;
		stream->cbDispInfo->outputBitDepth = stream->out_param.outputBitDepth;
		stream->cbDispInfo->outputComponents = stream->out_param.outputComponents;
		stream->cbDispInfo->outputHeight = stream->outputCounts;
		stream->cbDispInfo->outputStartXByte = 0;
		stream->cbDispInfo->outputStartY = 0;
		stream->cbDispInfo->scanPassCount = 0;
		stream->cbDispInfo->nextOutputStartY = 0;

		stream->ppuContext = &ppu;
		stream->nextRow = stream->cbDispInfo->outputHeight;
		stream->cbCtrlDisp.cbCtrlDispArg = cb_control_disp->cbCtrlDispArg;
		stream->cbCtrlDisp.cbCtrlDispFunc = cb_control_disp->cbCtrlDispFunc;

		stream->cbDispParam->nextOutputImage = disp_param->nextOutputImage;

		streamInfo->decodedStrmSize = stream->buffer->cursor;
		// push the rest of the buffer we have
		if (stream->buffer->length > stream->buffer->cursor)
		{
			u8* data = static_cast<u8*>(stream->buffer->data.get_ptr()) + stream->buffer->cursor;
			try
			{
				png_process_data(stream->png_ptr, stream->info_ptr, data, stream->buffer->length - stream->buffer->cursor);
			}
			catch (LibPngCustomException&)
			{
				freeMem();
				return CELL_PNGDEC_ERROR_FATAL;
			}
			streamInfo->decodedStrmSize = stream->buffer->length;
		}

		// todo: commandPtr
		// then just loop until the end, the callbacks should take care of the rest
		while (stream->endOfFile != true)
		{
			stream->cbCtrlStream.cbCtrlStrmFunc(ppu, streamInfo, streamParam, stream->cbCtrlStream.cbCtrlStrmArg);
			streamInfo->decodedStrmSize += streamParam->strmSize;
			try
			{
				png_process_data(stream->png_ptr, stream->info_ptr, static_cast<u8*>(streamParam->strmPtr.get_ptr()), streamParam->strmSize);
			}
			catch (LibPngCustomException&)
			{
				freeMem();
				return CELL_PNGDEC_ERROR_FATAL;
			}
		}

		freeMem();
	}
	else
	{
		// Check if the image needs to be flipped
		const bool flip = stream->out_param.outputMode == CELL_PNGDEC_BOTTOM_TO_TOP;

		// Decode the image
		// todo: commandptr
		try
		{
			for (int j = 0; j < stream->passes; j++)
			{
				for (int i = 0; i < stream->out_param.outputHeight; ++i)
				{
					const u32 line = flip ? stream->out_param.outputHeight - i - 1 : i;
					png_read_row(stream->png_ptr, &data[line*bytes_per_line], nullptr);
				}
			}
			png_read_end(stream->png_ptr, stream->info_ptr);
		}
		catch (LibPngCustomException&)
		{
			return CELL_PNGDEC_ERROR_FATAL;
		}
	}

	// Get the number of iTXt, tEXt and zTXt chunks
	const s32 text_chunks = png_get_text(stream->png_ptr, stream->info_ptr, nullptr, nullptr);

	// Set the chunk information and the previously obtained number of text chunks
	data_out_info->numText = (u32)text_chunks;
	data_out_info->chunkInformation = pngDecGetChunkInformation(stream.get_ptr(), true);
	png_unknown_chunkp unknowns;
	const int num_unknowns = png_get_unknown_chunks(stream->png_ptr, stream->info_ptr, &unknowns);
	data_out_info->numUnknownChunk = num_unknowns;

	// Indicate that the decoding succeeded
	data_out_info->status = CELL_PNGDEC_DEC_STATUS_FINISH;

	return CELL_OK;
}
Beispiel #13
0
int
main(int argc, char **argv)
{
    static char *usage="Usage:\n\t%s png__file\n";

    int i;
    FILE *fp_in = NULL;
    png_structp png_p;
    png_infop info_p;
    char header[8];
    int bit_depth;
    int color_type;
    png_color_16p input_backgrd;
    double gammaval;
    int file_width, file_height;
    png_int_32 xoff, yoff;
    png_uint_32 xres, yres;
    int unit_type;
    int rgb_intent;
    double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
    png_timep mod_time;
    png_textp text;
    int num_text;
    unsigned char *image;
    unsigned char **rows;

    if (argc != 2) {
	bu_log(usage, argv[0]);
	bu_exit(EXIT_FAILURE, "Incorrect number of arguments!!\n");
    } else {
	if ((fp_in = fopen(argv[1], "rb")) == NULL) {
	    perror(argv[1]);
	    bu_log("png_onfo: cannot open \"%s\" for reading\n",
		   argv[1]);
	    bu_exit(EXIT_FAILURE, "Cannot open input file\n");
	}
    }

    if (fread(header, 8, 1, fp_in) != 1)
	bu_exit(EXIT_FAILURE, "ERROR: Failed while reading file header!!!\n");

    if (png_sig_cmp((png_bytep)header, 0, 8))
	bu_exit(EXIT_FAILURE, "This is not a PNG file!!!\n");

    png_p = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_p)
	bu_exit(EXIT_FAILURE, "png_create_read_struct() failed!!\n");

    info_p = png_create_info_struct(png_p);
    if (!info_p)
	bu_exit(EXIT_FAILURE, "png_create_info_struct() failed!!\n");

    png_init_io(png_p, fp_in);

    png_set_sig_bytes(png_p, 8);

    png_read_info(png_p, info_p);

    color_type = png_get_color_type(png_p, info_p);

    bit_depth = png_get_bit_depth(png_p, info_p);

    switch (color_type) {
	case PNG_COLOR_TYPE_GRAY:
	    bu_log("color type: b/w (bit depth=%d)\n", bit_depth);
	    break;
	case PNG_COLOR_TYPE_GRAY_ALPHA:
	    bu_log("color type: b/w with alpha channel (bit depth=%d)\n", bit_depth);
	    break;
	case PNG_COLOR_TYPE_PALETTE:
	    bu_log("color type: color palette (bit depth=%d)\n", bit_depth);
	    break;
	case PNG_COLOR_TYPE_RGB:
	    bu_log("color type: RGB (bit depth=%d)\n", bit_depth);
	    break;
	case PNG_COLOR_TYPE_RGB_ALPHA:
	    bu_log("color type: RGB with alpha channel (bit depth=%d)\n", bit_depth);
	    break;
	default:
	    bu_log("Unrecognized color type (bit depth=%d)\n", bit_depth);
	    break;
    }

    file_width = png_get_image_width(png_p, info_p);
    file_height = png_get_image_height(png_p, info_p);

    bu_log("Image size: %d X %d\n", file_width, file_height);

    /* allocate memory for image */
    image = (unsigned char *)bu_calloc(1, file_width*file_height*3, "image");

    /* create rows array */
    rows = (unsigned char **)bu_calloc(file_height, sizeof(unsigned char *), "rows");
    for (i=0; i<file_height; i++)
	rows[file_height-1-i] = image+(i*file_width*3);

    png_read_image(png_p, rows);

    if (png_get_oFFs(png_p, info_p, &xoff, &yoff, &unit_type)) {
	if (unit_type == PNG_OFFSET_PIXEL)
	    bu_log("X Offset: %d pixels\nY Offset: %d pixels\n", (int)xoff, (int)yoff);
	else if (unit_type == PNG_OFFSET_MICROMETER)
	    bu_log("X Offset: %d um\nY Offset: %d um\n", (int)xoff, (int)yoff);
    }

    if (png_get_pHYs(png_p, info_p, &xres, &yres, &unit_type)) {
	if (unit_type == PNG_RESOLUTION_UNKNOWN)
	    bu_log("Aspect ratio: %g (width/height)\n", (double)xres/(double)yres);
	else if (unit_type == PNG_RESOLUTION_METER)
	    bu_log("pixel density:\n\t%d pixels/m horizontal\n\t%d pixels/m vertical\n",
		   (int)xres, (int)yres);
    }

    if (png_get_interlace_type(png_p, info_p) == PNG_INTERLACE_NONE)
	bu_log("not interlaced\n");
    else
	bu_log("interlaced\n");

    if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
	color_type == PNG_COLOR_TYPE_RGB_ALPHA)
	if (png_get_bKGD(png_p, info_p, &input_backgrd))
	    bu_log("background color: %d %d %d\n", input_backgrd->red, input_backgrd->green, input_backgrd->blue);

    if (png_get_sRGB(png_p, info_p, &rgb_intent)) {
	bu_log("rendering intent: ");
	switch (rgb_intent) {
	    case PNG_sRGB_INTENT_SATURATION:
		bu_log("saturation\n");
		break;
	    case PNG_sRGB_INTENT_PERCEPTUAL:
		bu_log("perceptual\n");
		break;
	    case PNG_sRGB_INTENT_ABSOLUTE:
		bu_log("absolute\n");
		break;
	    case PNG_sRGB_INTENT_RELATIVE:
		bu_log("relative\n");
		break;
	}
    }

    if (png_get_gAMA(png_p, info_p, &gammaval))
	bu_log("gamma: %g\n", gammaval);

#if defined(PNG_READ_cHRM_SUPPORTED)
    if (png_get_cHRM(png_p, info_p, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) {
	bu_log("Chromaticity:\n");
	bu_log("\twhite point\t(%g %g)\n\tred\t(%g %g)\n\tgreen\t(%g %g)\n\tblue\t(%g %g)\n",
	       white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
    }
#endif

    if (png_get_text(png_p, info_p, &text, &num_text))
	for (i=0; i<num_text; i++)
	    bu_log("%s: %s\n", text[i].key, text[i].text);

    if (png_get_tIME(png_p, info_p, &mod_time))
	bu_log("Last modified: %d/%d/%d %d:%d:%d\n", mod_time->month, mod_time->day,
	       mod_time->year, mod_time->hour, mod_time->minute, mod_time->second);
    return 0;
}
Beispiel #14
0
static void load_meta_data(png_structp png, png_infop png_info,
                           gp_storage *storage)
{
	double gamma;
	png_uint_32 res_x, res_y, w, h;
	int unit, depth, color_type, interlace_type, compr_method;
	const char *type;

	png_get_IHDR(png, png_info, &w, &h, &depth,
	             &color_type, &interlace_type, &compr_method, NULL);

	gp_storage_add_string(storage, NULL, "Interlace Type",
	                        interlace_type_name(interlace_type));


	gp_storage_add_int(storage, NULL, "Width", w);
	gp_storage_add_int(storage, NULL, "Height", h);
	gp_storage_add_int(storage, NULL, "Bit Depth", depth);

	if (color_type & PNG_COLOR_MASK_PALETTE) {
		type = "Palette";
	} else {
		if (color_type & PNG_COLOR_MASK_COLOR)
			type = "RGB";
		else
			type = "Grayscale";
	}

	gp_storage_add_string(storage, NULL, "Color Type", type);

	//TODO: To string
	gp_storage_add_int(storage, NULL, "Compression Method", compr_method);

	/* TODO: BOOL ? */
	gp_storage_add_string(storage, NULL, "Alpha Channel",
			        color_type & PNG_COLOR_MASK_ALPHA ? "Yes" : "No");

	if (png_get_gAMA(png, png_info, &gamma))
		gp_storage_add_int(storage, NULL, "gamma", gamma * 100000);

	if (png_get_pHYs(png, png_info, &res_x, &res_y, &unit)) {
		gp_storage_add_int(storage, NULL, "X Resolution", res_x);
		gp_storage_add_int(storage, NULL, "Y Resolution", res_y);

		const char *str_unit;

		if (unit == PNG_RESOLUTION_METER)
			str_unit = "Meter";
		else
			str_unit = "Unknown";

		gp_storage_add_string(storage, NULL, "Resolution Unit", str_unit);
	}

	png_timep mod_time;

	if (png_get_tIME(png, png_info, &mod_time)) {
		char buf[128];

		snprintf(buf, sizeof(buf), "%4i:%02i:%02i %02i:%02i:%02i",
		         mod_time->year, mod_time->month, mod_time->day,
			 mod_time->hour, mod_time->minute, mod_time->second);

		gp_storage_add_string(storage, NULL, "Date Time", buf);
	}

	png_textp text_ptr;
	int text_cnt;

	if (png_get_text(png, png_info, &text_ptr, &text_cnt)) {
		int i;
		char buf[128];

		for (i = 0; i < text_cnt; i++) {

			if (text_ptr[i].compression != PNG_TEXT_COMPRESSION_NONE)
				continue;

			snprintf(buf, sizeof(buf), "Text %03i", i);
			gp_storage_add_string(storage, NULL, buf, text_ptr[i].text);
		}
	}
}
Beispiel #15
0
SEXP read_png(SEXP sFn, SEXP sNative, SEXP sInfo) {
    SEXP res = R_NilValue, info_list = R_NilValue, info_tail = R_NilValue;
    const char *fn;
    char header[8];
    int native = asInteger(sNative), info = (asInteger(sInfo) == 1);
    FILE *f;
    read_job_t rj;
    png_structp png_ptr;
    png_infop info_ptr;
    
    if (TYPEOF(sFn) == RAWSXP) {
	rj.data = (char*) RAW(sFn);
	rj.len = LENGTH(sFn);
	rj.ptr = 0;
	rj.f = f = 0;
    } else {
	if (TYPEOF(sFn) != STRSXP || LENGTH(sFn) < 1) Rf_error("invalid filename");
	fn = CHAR(STRING_ELT(sFn, 0));
	f = fopen(fn, "rb");
	if (!f) Rf_error("unable to open %s", fn);
	if (fread(header, 1, 8, f) < 1 || png_sig_cmp((png_bytep) header, 0, 8)) {
	    fclose(f);
	    Rf_error("file is not in PNG format");
	}
	rj.f = f;
    }

    /* use our own error hanlding code and pass the fp so it can be closed on error */
    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)&rj, user_error_fn, user_warning_fn);
    if (!png_ptr) {
	if (f) fclose(f);
	Rf_error("unable to initialize libpng");
    }
    
    info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
	if (f) fclose(f);
	png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
	Rf_error("unable to initialize libpng");
    }
    
    if (f) {
	png_init_io(png_ptr, f);
	png_set_sig_bytes(png_ptr, 8);
    } else
	png_set_read_fn(png_ptr, (png_voidp) &rj, user_read_data);

#define add_info(K, V) { info_tail = SETCDR(info_tail, CONS(V, R_NilValue)); SET_TAG(info_tail, install(K)); }

    /* png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_EXPAND, NULL); */
    png_read_info(png_ptr, info_ptr);
    {
	png_uint_32 width, height;
	png_bytepp row_pointers;
	char *img_memory;
	SEXP dim;
	int bit_depth, color_type, interlace_type, compression_type, filter_method, rowbytes;
	int need_swap = 0;
	png_get_IHDR(png_ptr, info_ptr, &width, &height,
		     &bit_depth, &color_type, &interlace_type,
		     &compression_type, &filter_method);
	rowbytes = png_get_rowbytes(png_ptr, info_ptr);
#if VERBOSE_INFO
	Rprintf("png: %d x %d [%d], %d bytes, 0x%x, %d, %d\n", (int) width, (int) height, bit_depth, rowbytes,
		color_type, interlace_type, compression_type, filter_method);
#endif

	if (info) {
	    SEXP dv;
	    double d;
	    png_uint_32 rx, ry;
	    int ut, num_text = 0;
	    png_textp text_ptr;

	    info_tail = info_list = PROTECT(CONS((dv = allocVector(INTSXP, 2)), R_NilValue));
	    INTEGER(dv)[0] = (int) width;
	    INTEGER(dv)[1] = (int) height;
	    SET_TAG(info_list, install("dim"));
	    add_info("bit.depth", ScalarInteger(bit_depth));
	    switch(color_type) {
	    case PNG_COLOR_TYPE_GRAY: add_info("color.type", mkString("gray")); break;
	    case PNG_COLOR_TYPE_GRAY_ALPHA: add_info("color.type", mkString("gray + alpha")); break;
	    case PNG_COLOR_TYPE_PALETTE: add_info("color.type", mkString("palette")); break;
	    case PNG_COLOR_TYPE_RGB: add_info("color.type", mkString("RGB")); break;
	    case PNG_COLOR_TYPE_RGB_ALPHA: add_info("color.type", mkString("RGBA")); break;
	    default: add_info("color.type", ScalarInteger(color_type));
	    }
	    if (png_get_gAMA(png_ptr, info_ptr, &d)) add_info("gamma", ScalarReal(d));
#ifdef PNG_pHYs_SUPPORTED
	    if (png_get_pHYs(png_ptr, info_ptr, &rx, &ry, &ut)) {
		if (ut == PNG_RESOLUTION_METER) {
		    dv = allocVector(REALSXP, 2);
		    REAL(dv)[0] = ((double)rx) / 39.37008;
		    REAL(dv)[1] = ((double)ry) / 39.37008;
		    add_info("dpi", dv);
		} else if (ut == PNG_RESOLUTION_UNKNOWN)
		    add_info("asp", ScalarReal(rx / ry));
	    }
	    if (png_get_text(png_ptr, info_ptr, &text_ptr, &num_text)) {
		SEXP txt_key, txt_val = PROTECT(allocVector(STRSXP, num_text));
		if (num_text) {
		    int i;
		    setAttrib(txt_val, R_NamesSymbol, txt_key = allocVector(STRSXP, num_text));
		    for (i = 0; i < num_text; i++) {
			SET_STRING_ELT(txt_val, i, text_ptr[i].text ? mkChar(text_ptr[i].text) : NA_STRING);
			SET_STRING_ELT(txt_key, i, text_ptr[i].key ? mkChar(text_ptr[i].key) : NA_STRING);
		    }
		}
		add_info("text", txt_val);
		UNPROTECT(1);
	    }
#endif
	}

	/* on little-endian machines it's all well, but on big-endian ones we'll have to swap */
#if ! defined (__BIG_ENDIAN__) && ! defined (__LITTLE_ENDIAN__)   /* old compiler so have to use run-time check */
	{
	    char bo[4] = { 1, 0, 0, 0 };
	    int bi;
	    memcpy(&bi, bo, 4);
	    if (bi != 1)
		need_swap = 1;
	}
#endif
#ifdef __BIG_ENDIAN__
	need_swap = 1;
#endif

	/*==== set any transforms that we desire: ====*/
	/* palette->RGB - no discussion there */
	if (color_type == PNG_COLOR_TYPE_PALETTE)
	    png_set_palette_to_rgb(png_ptr);
	/* expand gray scale to 8 bits */
	if (color_type == PNG_COLOR_TYPE_GRAY &&
	    bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr);
	/* this should not be necessary but it's in the docs to guarantee 8-bit */
	if (bit_depth < 8)
	    png_set_packing(png_ptr);
	/* convert tRNS chunk into alpha */
	if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
	    png_set_tRNS_to_alpha(png_ptr);
	/* native format doesn't allow for 16-bit so it needs to be truncated */
	if (bit_depth == 16 && native) {
	    Rf_warning("Image uses 16-bit channels but R native format only supports 8-bit, truncating LSB."); 
	    png_set_strip_16(png_ptr);
	}
	/* for native output we need to a) convert gray to RGB, b) add alpha */
	if (native) {
	    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
		png_set_gray_to_rgb(png_ptr);
	    if (!(color_type & PNG_COLOR_MASK_ALPHA)) /* if there is no alpha, add it */
		png_set_add_alpha(png_ptr, 0xFF, PNG_FILLER_AFTER);
	}
#if 0 /* we use native (network) endianness since we read each byte anyway */
	/* on little-endian machines we need to swap 16-bit values - this is the inverse of need_swap as used for R! */
	if (!need_swap && bit_depth == 16)
	    png_set_swap(png_ptr);
#endif

	/* PNG wants up to call png_set_interlace_handling so it can get ready to de-interlace images */
	png_set_interlace_handling(png_ptr);

	/* all transformations are in place, so it's time to update the info structure so we can allocate stuff */
	png_read_update_info(png_ptr, info_ptr);

	/* re-read some important bits from the updated structure */
	rowbytes = png_get_rowbytes(png_ptr, info_ptr);
	bit_depth = png_get_bit_depth(png_ptr, info_ptr);
	color_type = png_get_color_type(png_ptr, info_ptr);

#if VERBOSE_INFO
	Rprintf("   -filter-> %d-bits, %d bytes, 0x%x\n", bit_depth, rowbytes, color_type);
#endif

	/* allocate data fro row pointers and the image using R's allocation */
	row_pointers = (png_bytepp) R_alloc(height, sizeof(png_bytep));
	img_memory = R_alloc(height, rowbytes);
	{ /* populate the row pointers */
	    char *i_ptr = img_memory;
	    int i;
	    for (i = 0; i < height; i++, i_ptr += rowbytes)
	      row_pointers[i] = (png_bytep) i_ptr;
	}
	
	/* do the reading work */
	png_read_image(png_ptr, row_pointers);
	
	if (f) {
	    rj.f = 0;
	    fclose(f);
	}

	/* native output - vector of integers */
	if (native) {
	    int pln = rowbytes / width;
	    if (pln < 1 || pln > 4) {
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		Rf_error("native output for %d planes is not possible.", pln);
	    }

	    res = PROTECT(allocVector(INTSXP, width * height));
	    if (pln == 4) { /* 4 planes - efficient - just copy it all */
		int y, *idata = INTEGER(res);
		for (y = 0; y < height; idata += width, y++)
		    memcpy(idata, row_pointers[y], width * sizeof(int));

		if (need_swap) {
		    int *ide = idata;
		    idata = INTEGER(res);
		    for (; idata < ide; idata++)
			RX_swap32(*idata);
		}
	    } else if (pln == 3) { /* RGB */
		int x, y, *idata = INTEGER(res);
		for (y = 0; y < height; y++)
		    for (x = 0; x < rowbytes; x += 3)
			*(idata++) = R_RGB((unsigned int) row_pointers[y][x],
					   (unsigned int) row_pointers[y][x + 1],
					   (unsigned int) row_pointers[y][x + 2]);
	    } else if (pln == 2) { /* GA */
		int x, y, *idata = INTEGER(res);
		for (y = 0; y < height; y++)
		    for (x = 0; x < rowbytes; x += 2)
			*(idata++) = R_RGBA((unsigned int) row_pointers[y][x],
					    (unsigned int) row_pointers[y][x],
					    (unsigned int) row_pointers[y][x],
					    (unsigned int) row_pointers[y][x + 1]);
	    } else { /* gray */
		int x, y, *idata = INTEGER(res);
		for (y = 0; y < height; y++)
		    for (x = 0; x < rowbytes; x++)
			*(idata++) = R_RGB((unsigned int) row_pointers[y][x],
					   (unsigned int) row_pointers[y][x],
					   (unsigned int) row_pointers[y][x]);
	    }
	    dim = allocVector(INTSXP, 2);
	    INTEGER(dim)[0] = height;
	    INTEGER(dim)[1] = width;
	    setAttrib(res, R_DimSymbol, dim);
	    setAttrib(res, R_ClassSymbol, mkString("nativeRaster"));
	    setAttrib(res, install("channels"), ScalarInteger(pln));
	    UNPROTECT(1);
	} else {
	    int x, y, p, pln = rowbytes / width, pls = width * height;
	    double * data;
	    if (bit_depth == 16) {
		res = PROTECT(allocVector(REALSXP, (rowbytes * height) / 2));
		pln /= 2;
	    } else
		res = PROTECT(allocVector(REALSXP, rowbytes * height));

	    data = REAL(res);
	    if (bit_depth == 16)
		for(y = 0; y < height; y++)
		    for (x = 0; x < width; x++)
			for (p = 0; p < pln; p++)
			    data[y + x * height + p * pls] = ((double)(
								       (((unsigned int)(((unsigned char *)row_pointers[y])[2 * (x * pln + p)])) << 8) |
								        ((unsigned int)(((unsigned char *)row_pointers[y])[2 * (x * pln + p) + 1]))
								       )) / 65535.0;
	    else 
		for(y = 0; y < height; y++)
		    for (x = 0; x < width; x++)
			for (p = 0; p < pln; p++)
			    data[y + x * height + p * pls] = ((double)row_pointers[y][x * pln + p]) / 255.0;
	    dim = allocVector(INTSXP, (pln > 1) ? 3 : 2);
	    INTEGER(dim)[0] = height;
	    INTEGER(dim)[1] = width;
	    if (pln > 1)
		INTEGER(dim)[2] = pln;
	    setAttrib(res, R_DimSymbol, dim);
	    UNPROTECT(1);
	}
    }

    if (info) {
	PROTECT(res);
	setAttrib(res, install("info"), info_list);
	UNPROTECT(2);
    }
    
    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);

    return res;
}
Beispiel #16
0
/* create a new finfo record, open FITS file */
static Finfo FinfoNew(char *fname)
{
  int len;
  char *e=NULL;
  char *f=NULL;
  char *s=NULL;
#if FITS2PNG
  int i;
  unsigned char header[8];
  /* use volatile to make gcc [-Wclobbered] happy (because of setjmp below) */
  volatile Finfo finfo;	  
#else
  Finfo finfo;	  
#endif


  /* sanity check */
  if( !fname ) return NULL;
  /* return existing finfo, if possible */
  if( (finfo=FinfoLookup(fname)) ) return finfo;
  /* allocate record */
  if( !(finfo = (Finfo)xcalloc(sizeof(FinfoRec), 1)) ){
    fprintf(stderr, "ERROR: can't allocate rec for image\n");
    return NULL;
  }
  /* save file name */
  finfo->fname = xstrdup(fname);
  /* check for file type */
  if( (s = strrchr(fname, '.')) && !strcasecmp(s, ".png") ){
    /* its a PNG */
    finfo->ftype = FTYPE_PNG;
  } else {
    /* assume FITS type */
    finfo->ftype = FTYPE_FITS;
  }
  /* open file */
  switch(finfo->ftype){
  case FTYPE_PNG:
#if FITS2PNG
    /* code taken from "PNG: The Definitive Guide" by Greg Roelofs,
       Chapter 13 "Reading PNG Images" */
    /* set data path */
    datapath = getenv("JS9_DATAPATH");
    /* look for path of the PNG file */
    s = Find(fname, "r", NULL, datapath);
    if( s && *s ){
      if( !(finfo->fp = fopen(s, "rb")) ){
	fprintf(stderr, "ERROR: can't open PNG file '%s'\n", fname);
	goto error;
      }
      fread(header, 1, 8, finfo->fp);
      if( png_sig_cmp(header, 0, 8) ){
	fprintf(stderr, "ERROR: not recognized as a PNG file '%s'\n", fname);
	goto error;
      }
      /* initialize stuff */
      finfo->png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
					      NULL, NULL, NULL);
      if( !finfo->png_ptr ){
	fprintf(stderr, "ERROR: png_create_read_struct failed '%s'\n", fname);
	goto error;
      }
      finfo->info_ptr = png_create_info_struct(finfo->png_ptr);
      if( !finfo->info_ptr ){
	fprintf(stderr, "ERROR: png_create_info_struct failed '%s'\n", fname);
	goto error;
      }
      if( setjmp(png_jmpbuf(finfo->png_ptr)) ){
	fprintf(stderr, "ERROR: during png init_io '%s'\n", fname);
	goto error;
      }
      png_init_io(finfo->png_ptr, finfo->fp);
      png_set_sig_bytes(finfo->png_ptr, 8);
      png_read_info(finfo->png_ptr, finfo->info_ptr);
      /* get the text chunks that come before the image */
      if( png_get_text(finfo->png_ptr, finfo->info_ptr,
		       &(finfo->text_ptr), &(finfo->num_text)) > 0 ){
	/* process all known PNG keywords */
	for(i=0; i<finfo->num_text; i++){
	  if( !strcmp(finfo->text_ptr[i].key, FITSFILE) ){
	    finfo->fitsfile = xstrdup(finfo->text_ptr[i].text);
	    /* remove the extension that was used to generate png */
	    s = strchr(finfo->fitsfile, '[');
	    if( s ){
	      *s = '\0';
	    }
	  }
	}
      }
    } else {
      fprintf(stderr, "ERROR: can't find PNG file '%s' [data path: %s]\n",
	      fname, datapath?datapath:"none");
      goto error;
    }
#else
    fprintf(stderr,
	    "ERROR: for fits2png support, build JS9 using --with-png\n");
    goto error;
#endif
    break;
    /* look for an error */
  case FTYPE_FITS:
    /* fits file can have an extension */
    f = FileRoot(fname);
    /* set data path */
    datapath = getenv("JS9_DATAPATH");
    /* look for path of the FITS file */
    s = Find(f, "r", NULL, datapath);
    xfree(f);
    if( s && *s ){
      len = strlen(s) + 1;
      /* construct full path to fits file + extension */
      e = FileExtension(fname);
      if( e ){
        len += strlen(e);
      }
      finfo->fitsfile = xmalloc(len);
      strcpy(finfo->fitsfile, s);
      if( e ){
        strcat(finfo->fitsfile, e);
      }
      xfree(s);
    } else {
      fprintf(stderr, "ERROR: can't find FITS file '%s' [data path: %s]\n",
	      fname, datapath?datapath:"none");
      goto error;
    }
    break;
  default:
    fprintf(stderr, "ERROR: unknown file type '%s'\n", fname);
    goto error;
    break;
  }
  /* add this finfo to end of list of existing finfos */
  FinfoListAdd(&finfohead, finfo);
  /* return the news */
  return finfo;
error:
  /* free up struct and return nothing */
  _FinfoFree(finfo);
  return NULL;
}
int res_create_multi_display_surface(const char* name, int* frames, gr_surface** pSurface) {
    gr_surface* surface = NULL;
    int result = 0;
    png_structp png_ptr = NULL;
    png_infop info_ptr = NULL;
    png_uint_32 width, height;
    png_byte channels;
    int i;

    *pSurface = NULL;
    *frames = -1;

    result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
    if (result < 0) return result;

    *frames = 1;
    png_textp text;
    int num_text;
    if (png_get_text(png_ptr, info_ptr, &text, &num_text)) {
        for (i = 0; i < num_text; ++i) {
            if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) {
                *frames = atoi(text[i].text);
                break;
            }
        }
        printf("  found frames = %d\n", *frames);
    }

    if (height % *frames != 0) {
        printf("bad height (%d) for frame count (%d)\n", height, *frames);
        result = -9;
        goto exit;
    }

    surface = malloc(*frames * sizeof(gr_surface));
    if (surface == NULL) {
        result = -8;
        goto exit;
    }
    for (i = 0; i < *frames; ++i) {
        surface[i] = NULL;//init_display_surface(width, height / *frames);
        if (surface[i] == NULL) {
            result = -8;
            goto exit;
        }
    }

    /*unsigned char* p_row = malloc(width * 4);
    unsigned int y;
    for (y = 0; y < height; ++y) {
        png_read_row(png_ptr, p_row, NULL);
        int frame = y % *frames;
        unsigned char* out_row = surface[frame]->data +
            (y / *frames) * surface[frame]->row_bytes;
        transform_rgb_to_draw(p_row, out_row, channels, width);
    }
    free(p_row); this will need to be brought in line with the older resources and graphics code */

    *pSurface = (gr_surface*) surface;

exit:
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    if (result < 0) {
        if (surface) {
            for (i = 0; i < *frames; ++i) {
                if (surface[i]) free(surface[i]);
            }
            free(surface);
        }
    }
    return result;
}
Beispiel #18
0
/*!
    \internal
*/
bool QPngHandlerPrivate::readPngHeader()
{
    state = Error;
    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, 0, qt_png_warning);

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

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

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

    png_set_read_fn(png_ptr, q->device(), iod_read_fn);
    png_read_info(png_ptr, info_ptr);

#ifndef QT_NO_IMAGE_TEXT
    png_textp text_ptr;
    int num_text=0;
    png_get_text(png_ptr,info_ptr,&text_ptr,&num_text);

    while (num_text--) {
        QString key, value;
#if defined(PNG_iTXt_SUPPORTED)
        if (text_ptr->lang) {
            QTextCodec *codec = QTextCodec::codecForName(text_ptr->lang);
            if (codec) {
                key = codec->toUnicode(text_ptr->lang_key);
                value = codec->toUnicode(QByteArray(text_ptr->text, text_ptr->itxt_length));
            } else {
                key = QString::fromLatin1(text_ptr->key);
                value = QString::fromLatin1(QByteArray(text_ptr->text, int(text_ptr->text_length)));
            }
        } else
#endif
        {
            key = QString::fromLatin1(text_ptr->key);
            value = QString::fromLatin1(QByteArray(text_ptr->text, int(text_ptr->text_length)));
        }
        if (!description.isEmpty())
            description += QLatin1String("\n\n");
        description += key + QLatin1String(": ") + value.simplified();
        text_ptr++;
    }
#endif

    state = ReadHeader;
    return true;
}
Beispiel #19
0
Datei: png.c Projekt: GNOME/giv
GivImage *giv_plugin_load_file(const char *filename,
                               GError **error)
{
    GivImage *img=NULL;
    FILE *fp = fopen(filename, "rb");
    if (!fp) 
        return NULL;
    
    // Check again that this is a png file
    const int number = 8;
    guchar header[9];
    fread(header, 1, number, fp);
    gboolean is_png = !png_sig_cmp(header, 0, number);
    if (!is_png) {
        return NULL;
    }
    
    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL);
    if (!png_ptr)
        return NULL;

    // Comments may be stored in the beginning or the end so create
    // a structure for both.
    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 NULL;
    }

    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
        return NULL;
    }

    png_uint_32 width, height;
    int bit_depth, color_type, interlace_type, compression_type, filter_method;

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

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

#if 0
    printf("width height bit_depth color_type = %d %d %d %d\n",
           (int)width, (int)height,
           bit_depth, color_type);
#endif
    
    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);

    // Since giv doesn't support gray alpha, we upgrade to rgb
    if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_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);

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

    // Reread info
    png_read_update_info(png_ptr, info_ptr);
    png_get_IHDR(png_ptr, info_ptr, &width, &height,
       &bit_depth, &color_type, &interlace_type,
       &compression_type, &filter_method);
    
    GivImageType image_type;
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth <= 8)
        image_type = GIVIMAGE_U8;
    else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 16)
        image_type = GIVIMAGE_U16;
    else if (color_type == PNG_COLOR_TYPE_RGB && bit_depth == 16)
        image_type = GIVIMAGE_RGB_U16;
    else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA && bit_depth == 16)
        image_type = GIVIMAGE_RGBA_U16;
    else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA && bit_depth == 8)
        image_type = GIVIMAGE_RGBA_U8;
    else
        image_type = GIVIMAGE_RGB_U8;

    img = giv_image_new(image_type, width, height);
    if (!img) {
      *error = g_error_new(GIV_IMAGE_ERROR, -1, "Failed allocating memory for an image of size %dx%d pixels!", width, height);
      return NULL;
    }

    int png_transforms = PNG_TRANSFORM_PACKING;
    png_bytep *row_pointers = (png_bytep*)g_new0(gpointer, height);

    guchar *dst_buf = img->buf.buf;
    int dst_row_stride = img->row_stride;
    int row_idx;
    for (row_idx=0; row_idx<(int)height; row_idx++)
        row_pointers[row_idx] = dst_buf + dst_row_stride * row_idx;

    png_read_image(png_ptr, row_pointers);

    png_timep mod_time;
    if (png_get_tIME(png_ptr, info_ptr, &mod_time)) {
      gchar *mod_time_str = g_strdup_printf("%04d-%02d-%02d %02d:%02d:%02d",
                                            mod_time->year,
                                            mod_time->month,
                                            mod_time->day,
                                            mod_time->hour,
                                            mod_time->minute,
                                            mod_time->second);
      giv_image_set_attribute(img, "mod_time", mod_time_str);
      g_free(mod_time_str);
    }

    png_textp png_text;
    int num_text;
    if (png_get_text(png_ptr, info_ptr, &png_text, &num_text)) {
        int i;
        for (i=0; i<num_text; i++) 
            giv_image_set_attribute(img, png_text[i].key, png_text[i].text);
    }

    png_read_end(png_ptr, NULL);
    g_free(row_pointers);
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);

    return img;
}
Beispiel #20
0
/* Shared library entry point */
static GdkPixbuf *
gdk_pixbuf__png_image_load (FILE *f, GError **error)
{
        GdkPixbuf * volatile pixbuf = NULL;
	png_structp png_ptr;
	png_infop info_ptr;
        png_textp text_ptr;
	gint i, ctype;
	png_uint_32 w, h;
	png_bytepp volatile rows = NULL;
        gint    num_texts;
        gchar *key;
        gchar *value;
        gchar *icc_profile_base64;
        const gchar *icc_profile_title;
        const gchar *icc_profile;
        png_uint_32 icc_profile_size;
        guint32 retval;
        gint compression_type;

#ifdef PNG_USER_MEM_SUPPORTED
	png_ptr = png_create_read_struct_2 (PNG_LIBPNG_VER_STRING,
                                            error,
                                            png_simple_error_callback,
                                            png_simple_warning_callback,
                                            NULL, 
                                            png_malloc_callback, 
                                            png_free_callback);
#else
	png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,
                                          error,
                                          png_simple_error_callback,
                                          png_simple_warning_callback);
#endif
	if (!png_ptr)
		return NULL;

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

	if (setjmp (png_jmpbuf(png_ptr))) {
	    	g_free (rows);

		if (pixbuf)
			g_object_unref (pixbuf);

		png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
		return NULL;
	}

	png_init_io (png_ptr, f);
	png_read_info (png_ptr, info_ptr);

        if (!setup_png_transformations(png_ptr, info_ptr, error, &w, &h, &ctype)) {
                png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
                return NULL;
        }
        
        pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, ctype & PNG_COLOR_MASK_ALPHA, 8, w, h);

	if (!pixbuf) {
                if (error && *error == NULL) {
                        g_set_error_literal (error,
                                             GDK_PIXBUF_ERROR,
                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                             _("Insufficient memory to load PNG file"));
                }
                

		png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
		return NULL;
	}

	rows = g_new (png_bytep, h);

	for (i = 0; i < h; i++)
		rows[i] = pixbuf->pixels + i * pixbuf->rowstride;

	png_read_image (png_ptr, rows);
        png_read_end (png_ptr, info_ptr);

        if (png_get_text (png_ptr, info_ptr, &text_ptr, &num_texts)) {
                for (i = 0; i < num_texts; i++) {
                        png_text_to_pixbuf_option (text_ptr[i], &key, &value);
                        gdk_pixbuf_set_option (pixbuf, key, value);
                        g_free (key);
                        g_free (value);
                }
        }

#if defined(PNG_cHRM_SUPPORTED)
        /* Extract embedded ICC profile */
        retval = png_get_iCCP (png_ptr, info_ptr,
                               (png_charpp) &icc_profile_title, &compression_type,
                               (png_bytepp) &icc_profile, (png_uint_32*) &icc_profile_size);
        if (retval != 0) {
                icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, (gsize)icc_profile_size);
                gdk_pixbuf_set_option (pixbuf, "icc-profile", icc_profile_base64);
                g_free (icc_profile_base64);
        }
#endif

	g_free (rows);
	png_destroy_read_struct (&png_ptr, &info_ptr, NULL);

        return pixbuf;
}
Beispiel #21
0
static BOOL 
ReadMetadata(png_structp png_ptr, png_infop info_ptr, FIBITMAP *dib) {
	// XMP keyword
	const char *g_png_xmp_keyword = "XML:com.adobe.xmp";

	FITAG *tag = NULL;
	png_textp text_ptr = NULL;
	png_timep mod_time = NULL;
	int num_text = 0;

	// iTXt/tEXt/zTXt chuncks
	if(png_get_text(png_ptr, info_ptr, &text_ptr, &num_text) > 0) {
		for(int i = 0; i < num_text; i++) {
			// create a tag
			tag = FreeImage_CreateTag();
			if(!tag) return FALSE;

			DWORD tag_length = (DWORD) MAX(text_ptr[i].text_length, text_ptr[i].itxt_length);

			FreeImage_SetTagLength(tag, tag_length);
			FreeImage_SetTagCount(tag, tag_length);
			FreeImage_SetTagType(tag, FIDT_ASCII);
			FreeImage_SetTagValue(tag, text_ptr[i].text);

			if(strcmp(text_ptr[i].key, g_png_xmp_keyword) == 0) {
				// store the tag as XMP
				FreeImage_SetTagKey(tag, g_TagLib_XMPFieldName);
				FreeImage_SetMetadata(FIMD_XMP, dib, FreeImage_GetTagKey(tag), tag);
			} else {
				// store the tag as a comment
				FreeImage_SetTagKey(tag, text_ptr[i].key);
				FreeImage_SetMetadata(FIMD_COMMENTS, dib, FreeImage_GetTagKey(tag), tag);
			}
			
			// destroy the tag
			FreeImage_DeleteTag(tag);
		}
	}

	// timestamp chunk
	if(png_get_tIME(png_ptr, info_ptr, &mod_time)) {
		char timestamp[32];
		// create a tag
		tag = FreeImage_CreateTag();
		if(!tag) return FALSE;

		// convert as 'yyyy:MM:dd hh:mm:ss'
		sprintf(timestamp, "%4d:%02d:%02d %2d:%02d:%02d", mod_time->year, mod_time->month, mod_time->day, mod_time->hour, mod_time->minute, mod_time->second);

		DWORD tag_length = (DWORD)strlen(timestamp) + 1;
		FreeImage_SetTagLength(tag, tag_length);
		FreeImage_SetTagCount(tag, tag_length);
		FreeImage_SetTagType(tag, FIDT_ASCII);
		FreeImage_SetTagID(tag, TAG_DATETIME);
		FreeImage_SetTagValue(tag, timestamp);

		// store the tag as Exif-TIFF
		FreeImage_SetTagKey(tag, "DateTime");
		FreeImage_SetMetadata(FIMD_EXIF_MAIN, dib, FreeImage_GetTagKey(tag), tag);

		// destroy the tag
		FreeImage_DeleteTag(tag);
	}

	return TRUE;
}
Beispiel #22
0
/* Called at the start of the progressive load, once we have image info */
static void
png_info_callback   (png_structp png_read_ptr,
                     png_infop   png_info_ptr)
{
        LoadContext* lc;
        png_uint_32 width, height;
        png_textp png_text_ptr;
        int i, num_texts;
        int color_type;
        gboolean have_alpha = FALSE;
        gchar *icc_profile_base64;
        const gchar *icc_profile_title;
        const gchar *icc_profile;
        png_uint_32 icc_profile_size;
        guint32 retval;
        gint compression_type;

        lc = png_get_progressive_ptr(png_read_ptr);

        if (lc->fatal_error_occurred)
                return;

        if (!setup_png_transformations(lc->png_read_ptr,
                                       lc->png_info_ptr,
                                       lc->error,
                                       &width, &height, &color_type)) {
                lc->fatal_error_occurred = TRUE;
                return;
        }

        /* If we have alpha, set a flag */
        if (color_type & PNG_COLOR_MASK_ALPHA)
                have_alpha = TRUE;
        
        if (lc->size_func) {
                gint w = width;
                gint h = height;
                (* lc->size_func) (&w, &h, lc->notify_user_data);
                
                if (w == 0 || h == 0) {
                        lc->fatal_error_occurred = TRUE;
                        if (lc->error && *lc->error == NULL) {
                                g_set_error_literal (lc->error,
                                                     GDK_PIXBUF_ERROR,
                                                     GDK_PIXBUF_ERROR_FAILED,
                                                     _("Transformed PNG has zero width or height."));
                        }
                        return;
                }
        }

        lc->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, have_alpha, 8, width, height);

        if (lc->pixbuf == NULL) {
                /* Failed to allocate memory */
                lc->fatal_error_occurred = TRUE;
                if (lc->error && *lc->error == NULL) {
                        g_set_error (lc->error,
                                     GDK_PIXBUF_ERROR,
                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
                                     _("Insufficient memory to store a %lu by %lu image; try exiting some applications to reduce memory usage"),
                                     (gulong) width, (gulong) height);
                }
                return;
        }

        /* Extract text chunks and attach them as pixbuf options */
        
        if (png_get_text (png_read_ptr, png_info_ptr, &png_text_ptr, &num_texts)) {
                for (i = 0; i < num_texts; i++) {
                        gchar *key, *value;

                        if (png_text_to_pixbuf_option (png_text_ptr[i],
                                                       &key, &value)) {
                                gdk_pixbuf_set_option (lc->pixbuf, key, value);
                                g_free (key);
                                g_free (value);
                        }
                }
        }

#if defined(PNG_cHRM_SUPPORTED)
        /* Extract embedded ICC profile */
        retval = png_get_iCCP (png_read_ptr, png_info_ptr,
                               (png_charpp) &icc_profile_title, &compression_type,
                               (png_bytepp) &icc_profile, &icc_profile_size);
        if (retval != 0) {
                icc_profile_base64 = g_base64_encode ((const guchar *) icc_profile, (gsize)icc_profile_size);
                gdk_pixbuf_set_option (lc->pixbuf, "icc-profile", icc_profile_base64);
                g_free (icc_profile_base64);
        }
#endif

        /* Notify the client that we are ready to go */

        if (lc->prepare_func)
                (* lc->prepare_func) (lc->pixbuf, NULL, lc->notify_user_data);

        return;
}
Beispiel #23
0
Datei: png.c Projekt: jinjoh/NOOR
struct ImBuf *imb_loadpng(unsigned char *mem, int size, int flags)
{
    struct ImBuf *ibuf = 0;
    png_structp png_ptr;
    png_infop info_ptr;
    unsigned char *pixels = 0;
    png_bytepp row_pointers = 0;
    png_uint_32 width, height;
    int bit_depth, color_type;
    PNGReadStruct ps;

    unsigned char *from, *to;
    int i, bytesperpixel;

    if (imb_is_a_png(mem) == 0) return(0);

    png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                     NULL, NULL, NULL);
    if (png_ptr == NULL) {
        printf("Cannot png_create_read_struct\n");
        return 0;
    }

    info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == NULL) {
        png_destroy_read_struct(&png_ptr, (png_infopp)NULL,
                                (png_infopp)NULL);
        printf("Cannot png_create_info_struct\n");
        return 0;
    }

    ps.size = size;
    ps.data = mem;
    ps.seek = 0;

    png_set_read_fn(png_ptr, (void *) &ps, ReadData);

    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
        if (pixels) MEM_freeN(pixels);
        if (row_pointers) MEM_freeN(row_pointers);
        if (ibuf) IMB_freeImBuf(ibuf);
        return 0;
    }

    // png_set_sig_bytes(png_ptr, 8);

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

    if (bit_depth == 16) {
        png_set_strip_16(png_ptr);
        bit_depth = 8;
    }

    bytesperpixel = png_get_channels(png_ptr, info_ptr);

    switch(color_type) {
    case PNG_COLOR_TYPE_RGB:
    case PNG_COLOR_TYPE_RGB_ALPHA:
        break;
    case PNG_COLOR_TYPE_PALETTE:
        png_set_palette_to_rgb(png_ptr);
        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
            bytesperpixel = 4;
        } else {
            bytesperpixel = 3;
        }
        break;
    case PNG_COLOR_TYPE_GRAY:
    case PNG_COLOR_TYPE_GRAY_ALPHA:
        if (bit_depth < 8) {
            png_set_expand(png_ptr);
            bit_depth = 8;
        }
        break;
    default:
        printf("PNG format not supported\n");
        longjmp(png_jmpbuf(png_ptr), 1);
    }

    ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0, 0);

    if (ibuf) {
        ibuf->ftype = PNG;
    } else {
        printf("Couldn't allocate memory for PNG image\n");
    }

    if (ibuf && ((flags & IB_test) == 0)) {
        imb_addrectImBuf(ibuf);

        pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
        if (pixels == NULL) {
            printf("Cannot allocate pixels array\n");
            longjmp(png_jmpbuf(png_ptr), 1);
        }

        // allocate memory for an array of row-pointers
        row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
        if (row_pointers == NULL) {
            printf("Cannot allocate row-pointers array\n");
            longjmp(png_jmpbuf(png_ptr), 1);
        }

        // set the individual row-pointers to point at the correct offsets
        for (i = 0; i < ibuf->y; i++) {
            row_pointers[ibuf->y-1-i] = (png_bytep)
                                        ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
        }

        png_read_image(png_ptr, row_pointers);

        // copy image data

        to = (unsigned char *) ibuf->rect;
        from = pixels;

        switch (bytesperpixel) {
        case 4:
            for (i = ibuf->x * ibuf->y; i > 0; i--) {
                to[0] = from[0];
                to[1] = from[1];
                to[2] = from[2];
                to[3] = from[3];
                to += 4;
                from += 4;
            }
            break;
        case 3:
            for (i = ibuf->x * ibuf->y; i > 0; i--) {
                to[0] = from[0];
                to[1] = from[1];
                to[2] = from[2];
                to[3] = 0xff;
                to += 4;
                from += 3;
            }
            break;
        case 2:
            for (i = ibuf->x * ibuf->y; i > 0; i--) {
                to[0] = to[1] = to[2] = from[0];
                to[3] = from[1];
                to += 4;
                from += 2;
            }
            break;
        case 1:
            for (i = ibuf->x * ibuf->y; i > 0; i--) {
                to[0] = to[1] = to[2] = from[0];
                to[3] = 0xff;
                to += 4;
                from++;
            }
            break;
        }

        if (flags & IB_imginfo) {
            png_text* text_chunks;
            int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL);
            for(i = 0; i < count; i++) {
                IMB_imginfo_add_field(ibuf, text_chunks[i].key, text_chunks[i].text);
                ibuf->flags |= IB_imginfo;
            }
        }

        png_read_end(png_ptr, info_ptr);
    }

    // clean up
    MEM_freeN(pixels);
    MEM_freeN(row_pointers);
    png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);

    return(ibuf);
}
Beispiel #24
0
int main( int argc, char *argv[] ) {
	int f, rowbytes;
	char buf[256];
	static FILE *fpout;  /* "static" prevents setjmp corruption */
	png_structp write_ptr;
	png_infop write_info_ptr, end_info_ptr;
	png_bytep row_buf, here;
	png_uint_32 y;
	png_textp text_ptr, new_text_ptr;
	int num_text;

	int interlace_type, compression_type, filter_type, bit_depth, color_type;
	int it, ct, ft, bd, clrt;
	png_uint_32 width, height, w, h;

	int duration;

	if( argc < 4 ) {
		printf( "makeanim v0.2\nusage: makeanim <duration in milliseconds> <input files ...> <output file>\n" );
		printf( "example: makeanim 1500 a00.png a01.png a02.png a03.png a04.png a.anim\n" );
		return 1;
		}

	duration = atoi( argv[1] );
	if( duration < 1 ) {
		printf( "duration is incorrect\n" );
		return 1;
		}

	numfiles = argc - 3;
	input = (struct inputstruct *)malloc( sizeof( struct inputstruct ) * numfiles );
	if( !input ) return 1;

	for( f = 0; f < numfiles; f++ ) {
		input[f].name = argv[f + 2];
		printf( "opening file %d, \"%s\"\n", f, input[f].name );

		/* open the file handle */
		input[f].file = fopen( input[f].name, "rb" );
		if( input[f].file == NULL ) {
			printf( "fopen() failed\n" );
			return 1;
			}

		/* check if it's PNG */
		if( fread( buf, 1, 8, input[f].file ) != 8 ) {
			printf( "fread() failed for file \"%s\"\n", input[f].name );
			return 1;
			}
		if( png_sig_cmp( buf, (png_size_t)0, 8 ) ) {
			printf( "not a PNG file\n" );
			return 1;
			}
		fseek( input[f].file, 0, SEEK_SET );

		/* allocate read structure */
		input[f].read_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL );
		if( input[f].read_ptr == NULL ) {
			printf( "png_create_read_struct() failed\n" );
			return 1;
			}
		
		/* allocate read info structure */
		input[f].read_info_ptr = png_create_info_struct( input[f].read_ptr );
		if( input[f].read_info_ptr == NULL ) {
			printf( "png_create_info_struct() failed\n" );
			return 1;
			}


		/* set error handler code */
		if( setjmp( input[f].read_ptr->jmpbuf ) ) {
			printf( "libpng read error\n" );
			return 1;
			}

		/* initialize stream */
		png_init_io( input[f].read_ptr, input[f].file );
		png_set_read_status_fn( input[f].read_ptr, NULL );

		/* read png info struct */
		png_read_info( input[f].read_ptr, input[f].read_info_ptr );

		/* get the info */
		if( !png_get_IHDR( input[f].read_ptr, input[f].read_info_ptr, &w, &h, &bd, &clrt, &it, &ct, &ft ) ) {
			printf( "png_get_IHDR() failed\n" );
			return 1;
			}

		/* save the info of the first frame */
		if( f == 0 ) {
			width = w;
			height = h;
			bit_depth = bd;
			color_type = clrt;
			interlace_type = it;
			compression_type = ct;
			filter_type = ft;
			}
		/* compare all other frames to first frame */
		else if( (w != width) ||
				(h != height) ||
				(bd != bit_depth) ||
				(clrt != color_type) ||
				(it != interlace_type) ||
				(ct != compression_type) ||
				(ft != filter_type) ) {
			if( w != width ) printf( "width is different\n" );
			if( h != height ) printf( "height  is different\n" );
			if( bd != bit_depth ) printf( "bit depth is different\n" );
			if( clrt != color_type ) printf( "color type is different\n" );
			if( it != interlace_type ) printf( "interlace type is different\n" );
			if( ct != compression_type ) printf( "compression type is different\n" );
			if( ft != filter_type ) printf( "filter type is different\n" );
			return 1;
			}
		}
	
	row_buf = (png_bytep)NULL;
	
	/* open output file */
	printf( "opening file \"%s\"\n", argv[numfiles + 2] );
	fpout = fopen( argv[numfiles + 2], "wb" );
	if( fpout == NULL ) {
		printf( "fopen() failed\n" );
		return 1;
		}

	/* allocate write structure */
	write_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING, (png_voidp)NULL, (png_error_ptr)NULL, (png_error_ptr)NULL );

	/* allocate info structures */
	write_info_ptr = png_create_info_struct( write_ptr );
	end_info_ptr = png_create_info_struct( write_ptr );

	/* error handling */
	if( setjmp( write_ptr->jmpbuf ) ) {
		printf( "libpng write error\n" );
		return 1;
		}

	/* initialize output stream */
	png_init_io( write_ptr, fpout );
	png_set_write_status_fn( write_ptr, NULL );

	/* set info */
	png_set_IHDR( write_ptr, write_info_ptr, width * numfiles, height, bit_depth, color_type, PNG_INTERLACE_NONE, compression_type, filter_type);

	/* image characteristics */
	{
		png_color_16p background;
		double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
		double gamma;
		int intent;
		png_uint_16p hist;
		png_uint_32 offset_x, offset_y;
		int unit_type;
		png_charp purpose, units;
		png_charpp params;
		png_int_32 X0, X1;
		int type, nparams;
		png_uint_32 res_x, res_y;
		png_colorp palette;
		int num_palette;
		png_color_8p sig_bit;
		png_bytep trans;
		int num_trans;
		png_color_16p trans_values;

		/* background color */
		if( png_get_bKGD( input[0].read_ptr, input[0].read_info_ptr, &background ) ) {
			png_set_bKGD( write_ptr, write_info_ptr, background );
			}

		if( png_get_cHRM( input[0].read_ptr, input[0].read_info_ptr, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y ) ) {
			png_set_cHRM( write_ptr, write_info_ptr, white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y );
			}

		/* gamma */
		if( png_get_gAMA( input[0].read_ptr, input[0].read_info_ptr, &gamma ) ) {
			png_set_gAMA( write_ptr, write_info_ptr, gamma );
			}

		/* rendering intent */
		if( png_get_sRGB( input[0].read_ptr, input[0].read_info_ptr, &intent ) ) {
			png_set_sRGB( write_ptr, write_info_ptr, intent );
			}

		/* Histogram */
		if( png_get_hIST( input[0].read_ptr, input[0].read_info_ptr, &hist ) ) {
			png_set_hIST( write_ptr, write_info_ptr, hist );
			}

		/* offsets */
		if( png_get_oFFs( input[0].read_ptr, input[0].read_info_ptr, &offset_x, &offset_y, &unit_type ) ) {
			png_set_oFFs( write_ptr, write_info_ptr, offset_x, offset_y, unit_type );
			}

		if( png_get_pCAL( input[0].read_ptr, input[0].read_info_ptr, &purpose, &X0, &X1, &type, &nparams, &units, &params ) ) {
			png_set_pCAL( write_ptr, write_info_ptr, purpose, X0, X1, type, nparams, units, params );
			}

		/* pixel density */
		if( png_get_pHYs( input[0].read_ptr, input[0].read_info_ptr, &res_x, &res_y, &unit_type ) ) {
			png_set_pHYs( write_ptr, write_info_ptr, res_x, res_y, unit_type );
			}

		/* text chunks */
/*		if( png_get_text( input[0].read_ptr, input[0].read_info_ptr, &text_ptr, &num_text ) > 0 ) {
			printf( "Handling %d tEXt/zTXt chunks\n", num_text );
			png_set_text( write_ptr, write_info_ptr, text_ptr, num_text );
			}
*/
		/* palette */
		if( png_get_PLTE( input[0].read_ptr, input[0].read_info_ptr, &palette, &num_palette ) ) {
			png_set_PLTE( write_ptr, write_info_ptr, palette, num_palette );
			}

		/* significant bits */
		if( png_get_sBIT( input[0].read_ptr, input[0].read_info_ptr, &sig_bit ) ) {
			png_set_sBIT( write_ptr, write_info_ptr, sig_bit );
			}

		/* transparency */
		if( png_get_tRNS( input[0].read_ptr, input[0].read_info_ptr, &trans, &num_trans, &trans_values ) ) {
			png_set_tRNS( write_ptr, write_info_ptr, trans, num_trans, trans_values );
			}
		}

	/* text chunks */
	num_text = 0;
	if( !png_get_text( input[0].read_ptr, input[0].read_info_ptr, &text_ptr, &num_text ) ) num_text = 0;
	new_text_ptr = (struct png_text_struct *)malloc( sizeof( struct png_text_struct ) * num_text + 1 );
	if( !new_text_ptr ) {
		printf( "malloc() failed\n" );
		return 1;
		}
	
	memcpy( new_text_ptr, text_ptr, sizeof( struct png_text_struct ) * num_text );

	snprintf( buf, 255, "SDL_anim %d %d %d", duration, width, numfiles );
	buf[255] = 0;
	new_text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
	new_text_ptr[num_text].key = "format";
	new_text_ptr[num_text].text = buf;
	new_text_ptr[num_text].text_length = strlen( buf );
	num_text++;
	png_set_text( write_ptr, write_info_ptr, new_text_ptr, num_text );

	/* write info */
	png_write_info( write_ptr, write_info_ptr );

	/* allocate buffer */
	rowbytes = png_get_rowbytes( input[0].read_ptr, input[0].read_info_ptr );
	row_buf = (png_bytep)png_malloc( write_ptr, rowbytes * numfiles );
	if( row_buf == NULL ) {
		printf( "png_malloc() failed\n" );
		return 1;
		}

	/* copy raw data */
	for( y = 0; y < height; y++ ) {
		/* grab a scanline from each file */
		here = row_buf;
		for( f = 0; f < numfiles; f++ ) {
			png_read_rows( input[f].read_ptr, (png_bytepp)&here, (png_bytepp)NULL, 1 );
			here += rowbytes;
			}
		/* write the long scanline */
		png_write_rows( write_ptr, (png_bytepp)&row_buf, 1 );
		}

	/* end io */
	for( f = 0; f < numfiles; f++ ) png_read_end( input[f].read_ptr, end_info_ptr );
	png_write_end( write_ptr, end_info_ptr );

	/* cleanup */
	png_free( write_ptr, row_buf );
	for( f = 0; f < numfiles; f++ ) {
		png_destroy_read_struct( &input[f].read_ptr, &input[f].read_info_ptr, &end_info_ptr);
		fclose( input[f].file );
		}
	png_destroy_write_struct( &write_ptr, &write_info_ptr );
	fclose( fpout );

	return 0;
	}
Beispiel #25
0
ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
	struct ImBuf *ibuf = NULL;
	png_structp png_ptr;
	png_infop info_ptr;
	unsigned char *pixels = NULL;
	unsigned short *pixels16 = NULL;
	png_bytepp row_pointers = NULL;
	png_uint_32 width, height;
	int bit_depth, color_type;
	PNGReadStruct ps;

	unsigned char *from, *to;
	unsigned short *from16;
	float *to_float;
	int i, bytesperpixel;

	if (imb_is_a_png(mem) == 0) return(NULL);

	/* both 8 and 16 bit PNGs are default to standard byte colorspace */
	colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);

	png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
	                                 NULL, NULL, NULL);
	if (png_ptr == NULL) {
		printf("Cannot png_create_read_struct\n");
		return NULL;
	}

	info_ptr = png_create_info_struct(png_ptr);
	if (info_ptr == NULL) {
		png_destroy_read_struct(&png_ptr, (png_infopp)NULL, 
		                        (png_infopp)NULL);
		printf("Cannot png_create_info_struct\n");
		return NULL;
	}

	ps.size = size; /* XXX, 4gig limit! */
	ps.data = mem;
	ps.seek = 0;

	png_set_read_fn(png_ptr, (void *) &ps, ReadData);

	if (setjmp(png_jmpbuf(png_ptr))) {
		png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);
		if (pixels) MEM_freeN(pixels);
		if (pixels16) MEM_freeN(pixels16);
		if (row_pointers) MEM_freeN(row_pointers);
		if (ibuf) IMB_freeImBuf(ibuf);
		return NULL;
	}

	// png_set_sig_bytes(png_ptr, 8);

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

	bytesperpixel = png_get_channels(png_ptr, info_ptr);

	switch (color_type) {
		case PNG_COLOR_TYPE_RGB:
		case PNG_COLOR_TYPE_RGB_ALPHA:
			break;
		case PNG_COLOR_TYPE_PALETTE:
			png_set_palette_to_rgb(png_ptr);
			if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
				bytesperpixel = 4;
			}
			else {
				bytesperpixel = 3;
			}
			break;
		case PNG_COLOR_TYPE_GRAY:
		case PNG_COLOR_TYPE_GRAY_ALPHA:
			if (bit_depth < 8) {
				png_set_expand(png_ptr);
				bit_depth = 8;
			}
			break;
		default:
			printf("PNG format not supported\n");
			longjmp(png_jmpbuf(png_ptr), 1);
	}
	
	ibuf = IMB_allocImBuf(width, height, 8 * bytesperpixel, 0);

	if (ibuf) {
		ibuf->ftype = PNG;
		if (bit_depth == 16)
			ibuf->ftype |= PNG_16BIT;

		if (png_get_valid(png_ptr, info_ptr, PNG_INFO_pHYs)) {
			int unit_type;
			png_uint_32 xres, yres;

			if (png_get_pHYs(png_ptr, info_ptr, &xres, &yres, &unit_type))
				if (unit_type == PNG_RESOLUTION_METER) {
					ibuf->ppm[0] = xres;
					ibuf->ppm[1] = yres;
				}
		}
	}
	else {
		printf("Couldn't allocate memory for PNG image\n");
	}

	if (ibuf && ((flags & IB_test) == 0)) {
		if (bit_depth == 16) {
			imb_addrectfloatImBuf(ibuf);
			png_set_swap(png_ptr);

			pixels16 = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(png_uint_16), "pixels");
			if (pixels16 == NULL) {
				printf("Cannot allocate pixels array\n");
				longjmp(png_jmpbuf(png_ptr), 1);
			}

			/* allocate memory for an array of row-pointers */
			row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_uint_16p), "row_pointers");
			if (row_pointers == NULL) {
				printf("Cannot allocate row-pointers array\n");
				longjmp(png_jmpbuf(png_ptr), 1);
			}

			/* set the individual row-pointers to point at the correct offsets */
			for (i = 0; i < ibuf->y; i++) {
				row_pointers[ibuf->y - 1 - i] = (png_bytep)
				                                ((png_uint_16 *)pixels16 + (i * ibuf->x) * bytesperpixel);
			}

			png_read_image(png_ptr, row_pointers);

			/* copy image data */

			to_float = ibuf->rect_float;
			from16 = pixels16;

			switch (bytesperpixel) {
				case 4:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to_float[0] = from16[0] / 65535.0;
						to_float[1] = from16[1] / 65535.0;
						to_float[2] = from16[2] / 65535.0;
						to_float[3] = from16[3] / 65535.0;
						to_float += 4; from16 += 4;
					}
					break;
				case 3:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to_float[0] = from16[0] / 65535.0;
						to_float[1] = from16[1] / 65535.0;
						to_float[2] = from16[2] / 65535.0;
						to_float[3] = 1.0;
						to_float += 4; from16 += 3;
					}
					break;
				case 2:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to_float[0] = to_float[1] = to_float[2] = from16[0] / 65535.0;
						to_float[3] = from16[1] / 65535.0;
						to_float += 4; from16 += 2;
					}
					break;
				case 1:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to_float[0] = to_float[1] = to_float[2] = from16[0] / 65535.0;
						to_float[3] = 1.0;
						to_float += 4; from16++;
					}
					break;
			}
		}
		else {
			imb_addrectImBuf(ibuf);

			pixels = MEM_mallocN(ibuf->x * ibuf->y * bytesperpixel * sizeof(unsigned char), "pixels");
			if (pixels == NULL) {
				printf("Cannot allocate pixels array\n");
				longjmp(png_jmpbuf(png_ptr), 1);
			}

			/* allocate memory for an array of row-pointers */
			row_pointers = (png_bytepp) MEM_mallocN(ibuf->y * sizeof(png_bytep), "row_pointers");
			if (row_pointers == NULL) {
				printf("Cannot allocate row-pointers array\n");
				longjmp(png_jmpbuf(png_ptr), 1);
			}

			/* set the individual row-pointers to point at the correct offsets */
			for (i = 0; i < ibuf->y; i++) {
				row_pointers[ibuf->y - 1 - i] = (png_bytep)
				                                ((unsigned char *)pixels + (i * ibuf->x) * bytesperpixel * sizeof(unsigned char));
			}

			png_read_image(png_ptr, row_pointers);

			/* copy image data */

			to = (unsigned char *) ibuf->rect;
			from = pixels;

			switch (bytesperpixel) {
				case 4:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to[0] = from[0];
						to[1] = from[1];
						to[2] = from[2];
						to[3] = from[3];
						to += 4; from += 4;
					}
					break;
				case 3:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to[0] = from[0];
						to[1] = from[1];
						to[2] = from[2];
						to[3] = 0xff;
						to += 4; from += 3;
					}
					break;
				case 2:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to[0] = to[1] = to[2] = from[0];
						to[3] = from[1];
						to += 4; from += 2;
					}
					break;
				case 1:
					for (i = ibuf->x * ibuf->y; i > 0; i--) {
						to[0] = to[1] = to[2] = from[0];
						to[3] = 0xff;
						to += 4; from++;
					}
					break;
			}
		}

		if (flags & IB_metadata) {
			png_text *text_chunks;
			int count = png_get_text(png_ptr, info_ptr, &text_chunks, NULL);
			for (i = 0; i < count; i++) {
				IMB_metadata_add_field(ibuf, text_chunks[i].key, text_chunks[i].text);
				ibuf->flags |= IB_metadata;
			}
		}

		png_read_end(png_ptr, info_ptr);
	}

	/* clean up */
	if (pixels)
		MEM_freeN(pixels);
	if (pixels16)
		MEM_freeN(pixels16);
	if (row_pointers)
		MEM_freeN(row_pointers);
	png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL);

	return(ibuf);
}
Beispiel #26
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 #27
0
s32 pngDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr<u8> data, PDataControlParam data_control_param, PDataOutInfo data_out_info, PCbControlDisp cb_control_disp = vm::null, PDispParam disp_param = vm::null)
{
	if (cb_control_disp || disp_param)
	{
		throw EXCEPTION("Partial image decoding is not supported");
	}

	// Indicate, that the PNG decoding is stopped/failed. This is incase, we return an error code in the middle of decoding
	data_out_info->status = CELL_PNGDEC_DEC_STATUS_STOP;

	// Possibilities for decoding in different sizes aren't tested, so if anyone finds any of these cases, we'll know about it.
	if (stream->info.imageWidth != stream->out_param.outputWidth)
	{
		throw EXCEPTION("Image width doesn't match output width! (%d/%d)", stream->out_param.outputWidth, stream->info.imageWidth);
	}

	if (stream->info.imageHeight != stream->out_param.outputHeight)
	{
		throw EXCEPTION("Image width doesn't match output height! (%d/%d)", stream->out_param.outputHeight, stream->info.imageHeight);
	}

	// Get the amount of output bytes per line
	const u32 bytes_per_line = data_control_param->outputBytesPerLine;

	// Whether to recaculate bytes per row
	bool recalculate_bytes_per_row = false;

	// Check if the game is expecting the number of bytes per line to be lower, than the actual bytes per line on the image. (Arkedo Pixel for example)
	// In such case we strip the bit depth to be lower.
	if ((bytes_per_line < stream->out_param.outputWidthByte) && stream->out_param.outputBitDepth != 8)
	{
		// Check if the packing is really 1 byte per 1 pixel
		if (stream->packing != CELL_PNGDEC_1BYTE_PER_1PIXEL)
		{
			throw EXCEPTION("Unexpected packing value! (%d)", stream->packing);
		}

		// Scale 16 bit depth down to 8 bit depth. PS3 uses png_set_strip_16, since png_set_scale_16 wasn't available back then.
		png_set_strip_16(stream->png_ptr);
		recalculate_bytes_per_row = true;
	}
	// Check if the outputWidthByte is smaller than the intended output length of a line. For example an image might be in RGB, but we need to output 4 components, so we need to perform alpha padding.
	else if (stream->out_param.outputWidthByte < (stream->out_param.outputWidth * stream->out_param.outputComponents))
	{
		// If fixed alpha is not specified in such a case, the default value for the alpha is 0xFF (255)
		if (!stream->fixed_alpha)
		{
			stream->fixed_alpha_colour = 0xFF;
		}

		// We need to fill alpha (before or after, depending on the output colour format) using the fixed alpha value passed by the game.
		png_set_add_alpha(stream->png_ptr, stream->fixed_alpha_colour, stream->out_param.outputColorSpace == CELL_PNGDEC_RGBA ? PNG_FILLER_AFTER : PNG_FILLER_BEFORE);
		recalculate_bytes_per_row = true;
	}
	// We decode as RGBA, so we need to swap the alpha
	else if (stream->out_param.outputColorSpace == CELL_PNGDEC_ARGB)
	{
		// Swap the alpha channel for the ARGB output format, if the padding isn't needed
		png_set_swap_alpha(stream->png_ptr);
	}
	// Sometimes games pass in a RBG/RGBA image and want it as grayscale
	else if ((stream->out_param.outputColorSpace == CELL_PNGDEC_GRAYSCALE_ALPHA || stream->out_param.outputColorSpace == CELL_PNGDEC_GRAYSCALE)
		  && (stream->info.colorSpace == CELL_PNGDEC_RGB || stream->info.colorSpace == CELL_PNGDEC_RGBA))
	{
		// Tell libpng to convert it to grayscale
		png_set_rgb_to_gray(stream->png_ptr, PNG_ERROR_ACTION_NONE, PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT);
		recalculate_bytes_per_row = true;
	}

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

		// Recalculate the bytes per row
		stream->out_param.outputWidthByte = png_get_rowbytes(stream->png_ptr, stream->info_ptr);
	}

	// Calculate the image size
	u32 image_size = stream->out_param.outputWidthByte * stream->out_param.outputHeight;

	// Buffer for storing the image
	std::vector<u8> png(image_size);
	
	// Make an unique pointer for the row pointers
	std::vector<u8*> row_pointers(stream->out_param.outputHeight);

	// Allocate memory for rows
	for (u32 y = 0; y < stream->out_param.outputHeight; y++)
	{
		row_pointers[y] = &png[y * stream->out_param.outputWidthByte];
	}

	// Decode the image
	png_read_image(stream->png_ptr, row_pointers.data());

	// Check if the image needs to be flipped
	const bool flip = stream->out_param.outputMode == CELL_PNGDEC_BOTTOM_TO_TOP;

	// Copy the result to the output buffer
	switch (stream->out_param.outputColorSpace)
	{
	case CELL_PNGDEC_RGB:
	case CELL_PNGDEC_RGBA:
	case CELL_PNGDEC_ARGB:
	case CELL_PNGDEC_GRAYSCALE_ALPHA:
	{
		// Check if we need to flip the image or need to leave empty bytes at the end of a line
		if ((bytes_per_line > stream->out_param.outputWidthByte) || flip)
		{
			// Get how many bytes per line we need to output - bytesPerLine is total amount of bytes per line, rest is unused and the game can do as it pleases.
			const u32 line_size = std::min(bytes_per_line, stream->out_param.outputWidth * 4);

			// If the game wants more bytes per line to be output, than the image has, then we simply copy what we have for each line,
			// and continue on the next line, thus leaving empty bytes at the end of the line.
			for (u32 i = 0; i < stream->out_param.outputHeight; i++)
			{
				const u32 dst = i * bytes_per_line;
				const u32 src = stream->out_param.outputWidth * 4 * (flip ? stream->out_param.outputHeight - i - 1 : i);
				memcpy(&data[dst], &png[src], line_size);
			}
		}
		else
		{
			// We can simply copy the output to the data pointer specified by the game, since we already do alpha channel transformations in libpng, if needed
			memcpy(data.get_ptr(), png.data(), image_size);
		}
		break;
	}

	default: throw EXCEPTION("Unsupported color space (%d)", stream->out_param.outputColorSpace);
	}

	// Get the number of iTXt, tEXt and zTXt chunks
	s32 text_chunks = 0;
	png_get_text(stream->png_ptr, stream->info_ptr, nullptr, &text_chunks);

	// Set the chunk information and the previously obtained number of text chunks
	data_out_info->numText = (u32)text_chunks;
	data_out_info->chunkInformation = pngDecGetChunkInformation(stream, true);
	data_out_info->numUnknownChunk = 0; // TODO: Get this somehow. Does anything even use or need this?

	// Indicate that the decoding succeeded
	data_out_info->status = CELL_PNGDEC_DEC_STATUS_FINISH;

	return CELL_OK;
}
Beispiel #28
0
static GpStatus
gdip_load_png_properties (png_structp png_ptr, png_infop info_ptr, png_infop end_ptr, BitmapData *bitmap_data)
{
#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED)
    bitmap_data->image_flags |= ImageFlagsHasRealDPI;
    bitmap_data->dpi_horz = png_get_x_pixels_per_inch(png_ptr, info_ptr);
    bitmap_data->dpi_vert = png_get_y_pixels_per_inch(png_ptr, info_ptr);
#elif defined(PNG_pHYs_SUPPORTED)
    if ((info_ptr->valid & PNG_INFO_pHYs) && (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)) {
        bitmap_data->image_flags |= ImageFlagsHasRealDPI;
        bitmap_data->dpi_horz = info_ptr->x_pixels_per_unit * 0.0254;
        bitmap_data->dpi_vert = info_ptr->y_pixels_per_unit * 0.0254;
    }
#endif
    /* default to screen resolution (if nothing was provided or available) */
    if (bitmap_data->dpi_horz == 0 || bitmap_data->dpi_vert == 0) {
        bitmap_data->dpi_horz = bitmap_data->dpi_vert = gdip_get_display_dpi ();
    }

#if defined(PNG_iCCP_SUPPORTED)
    {
        png_charp	name;
        png_charp	profile;
        png_uint_32	proflen;
        int		compression_type;

        if (png_get_iCCP(png_ptr, info_ptr, &name, &compression_type, &profile, &proflen)) {
            gdip_bitmapdata_property_add_ASCII(bitmap_data, PropertyTagICCProfileDescriptor, (BYTE*)name);
            gdip_bitmapdata_property_add_byte(bitmap_data, PropertyTagICCProfile, (BYTE)compression_type);
        }
    }
#endif

#if defined(PNG_gAMA_SUPPORTED)
    {
        double	gamma;

        if (png_get_gAMA(png_ptr, info_ptr, &gamma)) {
            gdip_bitmapdata_property_add_rational(bitmap_data, PropertyTagGamma, 100000, gamma * 100000);
        }
    }
#endif

#if defined(PNG_cHRM_SUPPORTED)
    {
        double	white_x;
        double	white_y;
        double	red_x;
        double	red_y;
        double	green_x;
        double	green_y;
        double	blue_x;
        double	blue_y;

        if (png_get_cHRM(png_ptr, info_ptr, &white_x, &white_y, &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) {
            BYTE *buffer;
            guint32		*ptr;

            buffer = GdipAlloc(6 * (sizeof(png_uint_32) + sizeof(png_uint_32)));
            if (buffer != NULL)  {
                ptr = (guint32 *)buffer;

                ptr[0] = (guint32)(red_x * 100000);
                ptr[1] = 1000000;
                ptr[2] = (guint32)(red_y * 100000);
                ptr[3] = 100000;

                ptr[4] = (guint32)(green_x * 100000);
                ptr[5] = 1000000;
                ptr[6] = (guint32)(green_y * 100000);
                ptr[7] = 100000;

                ptr[8] = (guint32)(blue_x * 100000);
                ptr[9] = 100000;
                ptr[10] = (guint32)(blue_y * 100000);
                ptr[11] = 100000;

                gdip_bitmapdata_property_add (bitmap_data, PropertyTagPrimaryChromaticities,
                                              6 * (sizeof(guint32) + sizeof(guint32)), PropertyTagTypeRational, buffer);

                ptr[0] = (guint32)(white_x * 100000);
                ptr[1] = 1000000;
                ptr[2] = (guint32)(white_y * 100000);
                ptr[3] = 100000;
                gdip_bitmapdata_property_add (bitmap_data, PropertyTagWhitePoint,
                                              2 * (sizeof(guint32) + sizeof(guint32)), PropertyTagTypeRational, buffer);

                GdipFree(buffer);
            }
        }
    }
#endif

#if defined(PNG_pHYs_SUPPORTED)
    {
        int		unit_type;
        png_uint_32	res_x;
        png_uint_32	res_y;

        if (png_get_pHYs(png_ptr, info_ptr, &res_x, &res_y, &unit_type)) {
            gdip_bitmapdata_property_add_byte(bitmap_data, PropertyTagPixelUnit, (BYTE)unit_type);
            gdip_bitmapdata_property_add_long(bitmap_data, PropertyTagPixelPerUnitX, res_x);
            gdip_bitmapdata_property_add_long(bitmap_data, PropertyTagPixelPerUnitY, res_y);
        }
    }
#endif

#if defined(PNG_TEXT_SUPPORTED)
    {
        int		num_text;
        png_textp	text_ptr;

        if (png_get_text(png_ptr, info_ptr, &text_ptr, &num_text)) {
            if (num_text > 0) {
                gdip_bitmapdata_property_add_ASCII(bitmap_data, PropertyTagExifUserComment, (BYTE*)text_ptr[0].text);
            }
        }
    }
#endif

    return Ok;
}
Beispiel #29
0
// Looks for metadata at both the beginning and end of the PNG file, giving
// preference to the head.
// Returns true on success. The caller must use MetadataFree() on 'metadata' in
// all cases.
static int ExtractMetadataFromPNG(png_structp png,
                                  png_infop const head_info,
                                  png_infop const end_info,
                                  Metadata* const metadata) {
  int p;

  for (p = 0; p < 2; ++p)  {
    png_infop const info = (p == 0) ? head_info : end_info;
    png_textp text = NULL;
    const png_uint_32 num = png_get_text(png, info, &text, NULL);
    png_uint_32 i;
    // Look for EXIF / XMP metadata.
    for (i = 0; i < num; ++i, ++text) {
      int j;
      for (j = 0; kPNGMetadataMap[j].name != NULL; ++j) {
        if (!strcmp(text->key, kPNGMetadataMap[j].name)) {
          MetadataPayload* const payload =
              (MetadataPayload*)((uint8_t*)metadata +
                                 kPNGMetadataMap[j].storage_offset);
          png_size_t text_length;
          switch (text->compression) {
#ifdef PNG_iTXt_SUPPORTED
            case PNG_ITXT_COMPRESSION_NONE:
            case PNG_ITXT_COMPRESSION_zTXt:
              text_length = text->itxt_length;
              break;
#endif
            case PNG_TEXT_COMPRESSION_NONE:
            case PNG_TEXT_COMPRESSION_zTXt:
            default:
              text_length = text->text_length;
              break;
          }
          if (payload->bytes != NULL) {
            fprintf(stderr, "Ignoring additional '%s'\n", text->key);
          } else if (!kPNGMetadataMap[j].process(text->text, text_length,
                                                 payload)) {
            fprintf(stderr, "Failed to process: '%s'\n", text->key);
            return 0;
          }
          break;
        }
      }
    }
    // Look for an ICC profile.
    {
      png_charp name;
      int comp_type;
#if LOCAL_PNG_PREREQ(1,5)
      png_bytep profile;
#else
      png_charp profile;
#endif
      png_uint_32 len;

      if (png_get_iCCP(png, info,
                       &name, &comp_type, &profile, &len) == PNG_INFO_iCCP) {
        if (!MetadataCopy((const char*)profile, len, &metadata->iccp)) return 0;
      }
    }
  }
  return 1;
}
Beispiel #30
0
/* Read a png header.
 */
static int
png2vips_header( Read *read, VipsImage *out )
{
	png_uint_32 width, height;
	int bit_depth, color_type;
	int interlace_type;

	png_uint_32 res_x, res_y;
	int unit_type;

	png_charp name;
	int compression_type;

	png_textp text_ptr;
        int num_text;

	/* Well thank you, libpng.
	 */
#if PNG_LIBPNG_VER < 10400
	png_charp profile;
#else
	png_bytep profile;
#endif

	png_uint_32 proflen;

	int bands; 
	VipsInterpretation interpretation;
	double Xres, Yres;

	if( setjmp( png_jmpbuf( read->pPng ) ) ) 
		return( -1 );

	png_get_IHDR( read->pPng, read->pInfo, 
		&width, &height, &bit_depth, &color_type,
		&interlace_type, NULL, NULL );

	/* png_get_channels() gives us 1 band for palette images ... so look
	 * at colour_type for output bands.
	 *
	 * Ignore alpha, we detect that separately below.
	 */
	switch( color_type ) {
	case PNG_COLOR_TYPE_PALETTE: 
		bands = 3; 
		break;

	case PNG_COLOR_TYPE_GRAY_ALPHA: 
	case PNG_COLOR_TYPE_GRAY: 
		bands = 1; 
		break;

	case PNG_COLOR_TYPE_RGB: 
	case PNG_COLOR_TYPE_RGB_ALPHA: 
		bands = 3; 
		break;

	default:
		vips_error( "png2vips", "%s", _( "unsupported color type" ) );
		return( -1 );
	}

	if( bit_depth > 8 ) {
		if( bands < 3 )
			interpretation = VIPS_INTERPRETATION_GREY16;
		else
			interpretation = VIPS_INTERPRETATION_RGB16;
	}
	else {
		if( bands < 3 )
			interpretation = VIPS_INTERPRETATION_B_W;
		else
			interpretation = VIPS_INTERPRETATION_sRGB;
	}

	/* Expand palette images.
	 */
	if( color_type == PNG_COLOR_TYPE_PALETTE )
		png_set_palette_to_rgb( read->pPng );

	/* Expand transparency.
	 */
	if( png_get_valid( read->pPng, read->pInfo, PNG_INFO_tRNS ) ) {
		png_set_tRNS_to_alpha( read->pPng );
		bands += 1;
	}
	else if( color_type == PNG_COLOR_TYPE_GRAY_ALPHA || 
		color_type == PNG_COLOR_TYPE_RGB_ALPHA ) {
		/* Some images have no transparency chunk, but still set
		 * color_type to alpha.
		 */
		bands += 1;
	}

	/* Expand <8 bit images to full bytes.
	 */
	if( color_type == PNG_COLOR_TYPE_GRAY &&
		bit_depth < 8 ) 
		png_set_expand_gray_1_2_4_to_8( read->pPng );

	/* If we're an INTEL byte order machine and this is 16bits, we need
	 * to swap bytes.
	 */
	if( bit_depth > 8 && 
		!vips_amiMSBfirst() )
		png_set_swap( read->pPng );

	/* Get resolution. Default to 72 pixels per inch, the usual png value. 
	 */
	unit_type = PNG_RESOLUTION_METER;
	res_x = (72 / 2.54 * 100);
	res_y = (72 / 2.54 * 100);
	png_get_pHYs( read->pPng, read->pInfo, &res_x, &res_y, &unit_type );
	switch( unit_type ) {
	case PNG_RESOLUTION_METER:
		Xres = res_x / 1000.0;
		Yres = res_y / 1000.0;
		break;
	
	default:
		Xres = res_x;
		Yres = res_y;
		break;
	}

	/* Set VIPS header.
	 */
	vips_image_init_fields( out,
		width, height, bands,
		bit_depth > 8 ? 
			VIPS_FORMAT_USHORT : VIPS_FORMAT_UCHAR,
		VIPS_CODING_NONE, interpretation, 
		Xres, Yres );

	/* Uninterlaced images will be read in seq mode. Interlaced images are
	 * read via a huge memory buffer.
	 */
	if( interlace_type == PNG_INTERLACE_NONE ) 
		/* Sequential mode needs thinstrip to work with things like
		 * vips_shrink().
		 */
		vips_image_pipelinev( out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
	else 
		vips_image_pipelinev( out, VIPS_DEMAND_STYLE_ANY, NULL );

	/* Fetch the ICC profile. @name is useless, something like "icc" or
	 * "ICC Profile" etc. Ignore it.
	 *
	 * @profile was png_charpp in libpngs < 1.5, png_bytepp is the
	 * modern one. Ignore the warning, if any.
	 */
	if( png_get_iCCP( read->pPng, read->pInfo, 
		&name, &compression_type, &profile, &proflen ) ) {
		void *profile_copy;

#ifdef DEBUG
		printf( "png2vips_header: attaching %d bytes of ICC profile\n",
			proflen );
		printf( "png2vips_header: name = \"%s\"\n", name );
#endif /*DEBUG*/

		if( !(profile_copy = vips_malloc( NULL, proflen )) ) 
			return( -1 );
		memcpy( profile_copy, profile, proflen );
		vips_image_set_blob( out, VIPS_META_ICC_NAME, 
			(VipsCallbackFn) vips_free, profile_copy, proflen );
	}

	/* Sanity-check line size.
	 */
	png_read_update_info( read->pPng, read->pInfo );
	if( png_get_rowbytes( read->pPng, read->pInfo ) != 
		VIPS_IMAGE_SIZEOF_LINE( out ) ) {
		vips_error( "vipspng", 
			"%s", _( "unable to read PNG header" ) );
		return( -1 );
	}

	/* Let our caller know. These are very expensive to decode.
	 */
	if( interlace_type != PNG_INTERLACE_NONE ) 
		vips_image_set_int( out, "interlaced", 1 ); 

	if( png_get_text( read->pPng, read->pInfo, 
		&text_ptr, &num_text ) > 0 ) {
		int i;

		for( i = 0; i < num_text; i++ ) 
			/* .text is always a null-terminated C string.
			 */
			if( vips__set_text( out, i, 
				text_ptr[i].key, text_ptr[i].text ) ) 
				return( -1 ); 
	}

	return( 0 );
}