summaryrefslogtreecommitdiffstats
path: root/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/depends/native/TexturePacker/src/decoder/PNGDecoder.cpp')
-rw-r--r--tools/depends/native/TexturePacker/src/decoder/PNGDecoder.cpp244
1 files changed, 244 insertions, 0 deletions
diff --git a/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.cpp b/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.cpp
new file mode 100644
index 0000000..f327400
--- /dev/null
+++ b/tools/depends/native/TexturePacker/src/decoder/PNGDecoder.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2014 Team Kodi
+ * http://kodi.tv
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "PNGDecoder.h"
+
+#include "SimpleFS.h"
+
+#include <png.h>
+
+#ifndef png_jmpbuf
+# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
+#endif
+
+/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp()
+ * returns zero if the image is a PNG and nonzero if it isn't a PNG.
+ *
+ * The function check_if_png() shown here, but not used, returns nonzero (true)
+ * if the file can be opened and is a PNG, 0 (false) otherwise.
+ *
+ * If this call is successful, and you are going to keep the file open,
+ * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once
+ * you have created the png_ptr, so that libpng knows your application
+ * has read that many bytes from the start of the file. Make sure you
+ * don't call png_set_sig_bytes() with more than 8 bytes read or give it
+ * an incorrect number of bytes read, or you will either have read too
+ * many bytes (your fault), or you are telling libpng to read the wrong
+ * number of magic bytes (also your fault).
+ *
+ * Many applications already read the first 2 or 4 bytes from the start
+ * of the image to determine the file type, so it would be easiest just
+ * to pass the bytes to png_sig_cmp() or even skip that if you know
+ * you have a PNG file, and call png_set_sig_bytes().
+ */
+bool PNGDecoder::CanDecode(const std::string &filename)
+{
+ #define PNG_BYTES_TO_CHECK 4
+ CFile fp;
+ char buf[PNG_BYTES_TO_CHECK];
+
+ /* Open the prospective PNG file. */
+ if (!fp.Open(filename))
+ return false;
+
+ /* Read in some of the signature bytes */
+ if (fp.Read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK)
+ {
+ fprintf(stderr, "error reading header ...\n");
+ return false;
+ }
+ fp.Close();
+
+ /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
+ Return nonzero (true) if they match */
+ return(!png_sig_cmp((png_bytep)buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
+}
+
+bool PNGDecoder::LoadFile(const std::string &filename, DecodedFrames &frames)
+{
+ png_byte header[8];
+
+ CFile fp;
+ if (!fp.Open(filename))
+ {
+ perror(filename.c_str());
+ return false;
+ }
+
+ // read the header
+ fp.Read(header, 8);
+
+ if (png_sig_cmp(header, 0, 8))
+ {
+ fprintf(stderr, "error: %s is not a PNG.\n", filename.c_str());
+ return false;
+ }
+
+ png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ {
+ fprintf(stderr, "error: png_create_read_struct returned 0.\n");
+ return false;
+ }
+
+ // create png info struct
+ png_infop info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ {
+ fprintf(stderr, "error: png_create_info_struct returned 0.\n");
+ png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
+ return false;
+ }
+
+ // create png info struct
+ png_infop end_info = png_create_info_struct(png_ptr);
+ if (!end_info)
+ {
+ fprintf(stderr, "error: png_create_info_struct returned 0.\n");
+ png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp) NULL);
+ return false;
+ }
+
+ // the code in this if statement gets called if libpng encounters an error
+ if (setjmp(png_jmpbuf(png_ptr))) {
+ fprintf(stderr, "error from libpng\n");
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ return false;
+ }
+
+ // init png reading
+ png_init_io(png_ptr, fp.getFP());
+
+ // let libpng know you already read the first 8 bytes
+ png_set_sig_bytes(png_ptr, 8);
+
+ // read all the info up to the image data
+ png_read_info(png_ptr, info_ptr);
+
+ // variables to pass to get info
+ int bit_depth, color_type;
+ png_uint_32 temp_width, temp_height;
+
+ // get info about png
+ png_get_IHDR(png_ptr, info_ptr, &temp_width, &temp_height, &bit_depth, &color_type,
+ NULL, NULL, NULL);
+
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ {
+ png_set_tRNS_to_alpha(png_ptr);
+ }
+
+ //set it to 32bit pixeldepth
+ png_color_8 sig_bit;
+ sig_bit.red = 32;
+ sig_bit.green = 32;
+ sig_bit.blue = 32;
+ // if the image has an alpha channel then
+ sig_bit.alpha = 32;
+ png_set_sBIT(png_ptr, info_ptr, &sig_bit);
+
+
+ /* Add filler (or alpha) byte (before/after each RGB triplet) */
+ png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+
+
+ if (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ png_set_bgr(png_ptr);
+
+ // convert indexed color to rgb
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ png_set_palette_to_rgb(png_ptr);
+
+ /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
+ //png_set_swap_alpha(png_ptr);
+
+ //libsquish only eats 32bit RGBA, must convert grayscale into this format
+ if (color_type == PNG_COLOR_TYPE_GRAY ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ png_set_expand_gray_1_2_4_to_8(png_ptr);
+ png_set_gray_to_rgb(png_ptr);
+ }
+
+ // Update the png info struct.
+ png_read_update_info(png_ptr, info_ptr);
+
+ // Row size in bytes.
+ int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+
+ // glTexImage2d requires rows to be 4-byte aligned
+ // rowbytes += 3 - ((rowbytes-1) % 4);
+
+ // Allocate the image_data as a big block, to be given to opengl
+ png_byte * image_data;
+ image_data = (png_byte*)new png_byte[rowbytes * temp_height * sizeof(png_byte)+15];
+ if (image_data == NULL)
+ {
+ fprintf(stderr, "error: could not allocate memory for PNG image data\n");
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ return false;
+ }
+
+ // row_pointers is for pointing to image_data for reading the png with libpng
+ png_bytep * row_pointers = (png_bytep*) new png_bytep[temp_height * sizeof(png_bytep)];
+ if (row_pointers == NULL)
+ {
+ fprintf(stderr, "error: could not allocate memory for PNG row pointers\n");
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ delete [] image_data;
+ return false;
+ }
+
+ // set the individual row_pointers to point at the correct offsets of image_data
+ for (unsigned int i = 0; i < temp_height; i++)
+ {
+ row_pointers[i] = image_data + i * rowbytes;
+ }
+
+ // read the png into image_data through row_pointers
+ png_read_image(png_ptr, row_pointers);
+
+ DecodedFrame frame;
+
+ frame.rgbaImage.pixels = (char *)image_data;
+ frame.rgbaImage.height = temp_height;
+ frame.rgbaImage.width = temp_width;
+ frame.rgbaImage.bbp = 32;
+ frame.rgbaImage.pitch = 4 * temp_width;
+
+ frame.decoder = this;
+
+ frames.frameList.push_back(frame);
+ // clean up
+ png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
+ delete [] row_pointers;
+ return true;
+}
+
+void PNGDecoder::FreeDecodedFrame(DecodedFrame &frame)
+{
+ delete [] frame.rgbaImage.pixels;
+}
+
+void PNGDecoder::FillSupportedExtensions()
+{
+ m_supportedExtensions.emplace_back(".png");
+}