Created
July 17, 2012 06:46
-
-
Save zrbecker/3127677 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * PNGImage.cpp | |
| * | |
| * Created on: Jul 16, 2012 | |
| * Author: zrbecker | |
| */ | |
| #include "PNGImage.h" | |
| #include <png.h> | |
| #include <iostream> | |
| #include <algorithm> | |
| PNGImage::PNGImage(unsigned int width, unsigned int height, bool hasAlpha, unsigned char *pixels) | |
| : m_width(width), m_height(height), m_hasAlpha(hasAlpha), m_pixels(NULL) { | |
| int bytes_per_pixel = (hasAlpha) ? 4 : 3; | |
| m_pixels = new unsigned char[bytes_per_pixel * width * height]; | |
| std::copy(pixels, pixels + bytes_per_pixel * width * height, m_pixels); | |
| } | |
| PNGImage::PNGImage(const std::string &filename) | |
| : m_width(0), m_height(0), m_hasAlpha(false), m_pixels(NULL) { | |
| FILE *file; | |
| file = fopen(filename.c_str(), "rb"); | |
| if (file == NULL) { | |
| std::cerr << "Error: Could not open " << filename << "." << std::endl; | |
| return; | |
| } | |
| png_struct *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
| if (png_ptr == NULL) { | |
| std::cerr << "Error: Could not create png_struct struct." << std::endl; | |
| fclose(file); | |
| return; | |
| } | |
| png_info *info_ptr = png_create_info_struct(png_ptr); | |
| if (info_ptr == NULL) { | |
| std::cerr << "Error: Could not create png_info struct." << std::endl; | |
| png_destroy_read_struct(&png_ptr, NULL, NULL); | |
| fclose(file); | |
| return; | |
| } | |
| if (setjmp(png_jmpbuf(png_ptr))) { | |
| std::cerr << "Error: libpng failed to load " << filename << "." << std::endl; | |
| png_destroy_read_struct(&png_ptr, NULL, NULL); | |
| if (m_pixels != NULL) { | |
| free(m_pixels); | |
| m_pixels = NULL; | |
| } | |
| fclose(file); | |
| return; | |
| } | |
| const int sig_bytes = 8; | |
| unsigned char header[sig_bytes]; | |
| fread(header, 1, sig_bytes, file); | |
| if (png_sig_cmp(header, 0, sig_bytes) != 0) { | |
| std::cerr << "Error: " << filename << " is not a png file." << std::endl; | |
| png_destroy_read_struct(&png_ptr, NULL, NULL); | |
| fclose(file); | |
| return; | |
| } | |
| unsigned int width, height; | |
| bool hasAlpha; | |
| png_init_io(png_ptr, file); | |
| png_set_sig_bytes(png_ptr, sig_bytes); | |
| png_read_png(png_ptr, info_ptr, | |
| PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND, | |
| NULL); | |
| width = png_get_image_width(png_ptr, info_ptr); | |
| height = png_get_image_height(png_ptr, info_ptr); | |
| switch (png_get_color_type(png_ptr, info_ptr)) { | |
| case PNG_COLOR_TYPE_RGBA: hasAlpha = true; break; | |
| case PNG_COLOR_TYPE_RGB: hasAlpha = false; break; | |
| default: | |
| std::cerr << "Error: " << filename << " has unsupported color type." << std::endl; | |
| png_destroy_read_struct(&png_ptr, NULL, NULL); | |
| fclose(file); | |
| return; | |
| } | |
| unsigned int rowbytes = png_get_rowbytes(png_ptr, info_ptr); | |
| m_pixels = new unsigned char[rowbytes * height]; | |
| png_byte **row_pointers = png_get_rows(png_ptr, info_ptr); | |
| for (int i = 0; i < height; ++i) | |
| std::copy(row_pointers[i], row_pointers[i] + rowbytes, m_pixels + i * rowbytes); | |
| png_destroy_read_struct(&png_ptr, NULL, NULL); | |
| fclose(file); | |
| m_width = width; | |
| m_height = height; | |
| m_hasAlpha = hasAlpha; | |
| } | |
| PNGImage::~PNGImage() { | |
| if (m_pixels != NULL) { | |
| delete[] m_pixels; | |
| m_pixels = NULL; | |
| } | |
| } | |
| bool PNGImage::Good() { | |
| return (m_pixels != NULL); | |
| } | |
| bool PNGImage::Save(const std::string &filename) { | |
| FILE *file = fopen(filename.c_str(), "wb"); | |
| if (file == NULL) { | |
| std::cerr << "Could not open " << filename << " for writing." << std::endl; | |
| return false; | |
| } | |
| png_struct *png_s = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
| if (png_s == NULL) { | |
| std::cerr << "Error: Could not create png_struct struct." << std::endl; | |
| fclose(file); | |
| return false; | |
| } | |
| png_info *png_i = png_create_info_struct(png_s); | |
| if (png_i == NULL) { | |
| std::cerr << "Error: Could not create png_info struct." << std::endl; | |
| png_destroy_write_struct(&png_s, &png_i); | |
| fclose(file); | |
| return false; | |
| } | |
| if (setjmp(png_jmpbuf(png_s))) { | |
| std::cerr << "Error: libpng failed to save " << filename << "." << std::endl; | |
| png_destroy_write_struct(&png_s, &png_i); | |
| fclose(file); | |
| return false; | |
| } | |
| png_init_io(png_s, file); | |
| int color_type = (m_hasAlpha) ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB; | |
| png_set_IHDR(png_s, png_i, m_width, m_height, 8, color_type, 0, 0, 0); | |
| png_write_info(png_s, png_i); | |
| int bytes_per_pixel = (m_hasAlpha) ? 4 : 3; | |
| png_bytep row_pointers[m_height]; | |
| if (m_height > PNG_UINT_32_MAX / png_sizeof(png_bytep)) | |
| png_error(png_s, "Image is too tall to process in memory."); | |
| for (png_uint_32 k = 0; k < m_height; ++k) | |
| row_pointers[k] = m_pixels + k * m_width * bytes_per_pixel; | |
| png_write_image(png_s, row_pointers); | |
| png_write_end(png_s, png_i); | |
| png_destroy_write_struct(&png_s, &png_i); | |
| fclose(file); | |
| return true; | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| * PNGImage.h | |
| * | |
| * Created on: Jul 16, 2012 | |
| * Author: zrbecker | |
| */ | |
| #ifndef PNGIMAGE_H_ | |
| #define PNGIMAGE_H_ | |
| #include <string> | |
| class PNGImage { | |
| public: | |
| PNGImage(const std::string &filename); | |
| PNGImage(unsigned int width, unsigned int height, bool hasAlpha, unsigned char *pixels); | |
| virtual ~PNGImage(); | |
| bool Good(); | |
| bool Save(const std::string &filename); | |
| private: | |
| unsigned int m_width; | |
| unsigned int m_height; | |
| bool m_hasAlpha; | |
| unsigned char *m_pixels; | |
| }; | |
| #endif /* PNGIMAGE_H_ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment