1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
|
/*
* Copyright (C) 2006 - 2015 René Rebe, ExactCODE GmbH
*
* 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; version 2. A copy of the GNU General
* Public License can be found in the file LICENSE.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANT-
* ABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* Alternatively, commercial licensing options are available from the
* copyright holder ExactCODE GmbH Germany.
*/
#include <stdlib.h>
#include <png.h>
#include <zlib.h>
#include <iostream>
#include "png.hh"
#include "Endianess.hh"
void stdstream_read_data(png_structp png_ptr,
png_bytep data, png_size_t length)
{
std::istream* stream = (std::istream*) png_get_io_ptr (png_ptr);
stream->read ((char*)data, length);
}
void stdstream_write_data(png_structp png_ptr,
png_bytep data, png_size_t length)
{
std::ostream* stream = (std::ostream*) png_get_io_ptr (png_ptr);
stream->write ((char*)data, length);
}
void stdstream_flush_data(png_structp png_ptr)
{
std::ostream* stream = (std::ostream*) png_get_io_ptr (png_ptr);
stream = stream;
}
int PNGCodec::readImage (std::istream* stream, Image& image, const std::string& decompress)
{
{ // quick magic check
char buf [4];
stream->read (buf, sizeof (buf));
int cmp = png_sig_cmp ((png_byte*)buf, (png_size_t)0, sizeof (buf));
stream->seekg (0);
if (cmp != 0)
return false;
}
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type, num_trans;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL /*user_error_ptr*/,
NULL /*user_error_fn*/,
NULL /*user_warning_fn*/);
if (png_ptr == NULL)
return 0;
/* Allocate/initialize the memory for image information. REQUIRED. */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
return 0;
}
/* Set error handling if you are using the setjmp/longjmp method (this is
* the normal method of doing things with libpng). REQUIRED unless you
* set up your own error handlers in the png_create_read_struct() earlier.
*/
if (setjmp(png_jmpbuf(png_ptr))) {
/* Free all of the memory associated with the png_ptr and info_ptr */
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
/* If we get here, we had a problem reading the file */
return 0;
}
/* Set up our STL stream input control */
png_set_read_fn (png_ptr, stream, &stdstream_read_data);
///* If we have already read some of the signature */
//png_set_sig_bytes(png_ptr, sig_read);
/* The call to png_read_info() gives us all of the information from the
* PNG file before the first IDAT (image data chunk). REQUIRED
*/
png_read_info (png_ptr, info_ptr);
png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, NULL, NULL);
image.w = width;
image.h = height;
image.bps = bit_depth;
image.spp = png_get_channels(png_ptr, info_ptr);
png_uint_32 res_x, res_y;
res_x = png_get_x_pixels_per_meter(png_ptr, info_ptr);
res_y = png_get_y_pixels_per_meter(png_ptr, info_ptr);
image.setResolution((2.54 * res_x + .5) / 100, (2.54 * res_y + .5) / 100);
/* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
* byte into separate bytes (useful for paletted and grayscale images) */
// png_set_packing(png_ptr);
/* Change the order of packed pixels to least significant bit first
* (not useful if you are using png_set_packing). */
// png_set_packswap(png_ptr);
png_get_tRNS(png_ptr, info_ptr, NULL, &num_trans, NULL);
/* Expand paletted colors into true RGB triplets */
if (color_type == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb(png_ptr);
image.bps = 8;
if (num_trans)
image.spp = 4;
else
image.spp = 3;
}
#if 0 // no longer needed
/* Expand grayscale images to the full 8 bits from 2, or 4 bits/pixel */
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth > 1 && bit_depth < 8) {
png_set_gray_1_2_4_to_8(png_ptr);
image.bps = 8;
}
#endif
/* Expand paletted or RGB images with transparency to full alpha channels
* so the data will be available as RGBA quartets.
*/
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(png_ptr);
/* Set the background color to draw transparent and alpha images over.
* It is possible to set the red, green, and blue components directly
* for paletted images instead of supplying a palette index. Note that
* even if the PNG file supplies a background, you are not required to
* use it - you should use the (solid) application background if it has one.
*/
#if 0
png_color_16* image_background;
if (png_get_bKGD(png_ptr, info_ptr, &image_background)) {
png_set_background(png_ptr, image_background,
PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
image.spp = 3;
}
#endif
/* If you want to shift the pixel values from the range [0,255] or
* [0,65535] to the original [0,7] or [0,31], or whatever range the
* colors were originally in:
*/
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) {
png_color_8p sig_bit;
png_get_sBIT(png_ptr, info_ptr, &sig_bit);
png_set_shift(png_ptr, sig_bit);
}
/* swap bytes of 16 bit files to least significant byte first
we store them in CPU byte order in memory */
if (Exact::NativeEndianTraits::IsBigendian)
png_set_swap(png_ptr);
/* Turn on interlace handling. REQURIED if you are not using
* png_read_image(). To see how to handle interlacing passes,
* see the png_read_row() method below:
*/
int number_passes = png_set_interlace_handling (png_ptr);
/* Optional call to gamma correct and add the background to the palette
* and update info structure. REQUIRED if you are expecting libpng to
* update the palette for you (ie you selected such a transform above).
*/
png_read_update_info(png_ptr, info_ptr);
/* Allocate the memory to hold the image using the fields of info_ptr. */
int stride = png_get_rowbytes (png_ptr, info_ptr);
image.resize (image.w, image.h);
png_bytep row_pointers[1];
/* The other way to read images - deal with interlacing: */
for (int pass = 0; pass < number_passes; ++pass)
for (unsigned int y = 0; y < height; ++y) {
row_pointers[0] = image.getRawData() + y * stride;
png_read_rows(png_ptr, row_pointers, NULL, 1);
}
/* clean up after the read, and free any memory allocated - REQUIRED */
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
/* that's it */
return true;
}
bool PNGCodec::writeImage (std::ostream* stream, Image& image, int quality,
const std::string& compress)
{
png_structp png_ptr;
png_infop info_ptr;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL /*user_error_ptr*/,
NULL /*user_error_fn*/,
NULL /*user_warning_fn*/);
if (png_ptr == NULL) {
return false;
}
/* Allocate/initialize the memory for image information. REQUIRED. */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_write_struct(&png_ptr, NULL);
return false;
}
/* Set error handling if you are using the setjmp/longjmp method (this is
* the normal method of doing things with libpng). REQUIRED unless you
* set up your own error handlers in the png_create_read_struct() earlier.
*/
if (setjmp(png_jmpbuf(png_ptr))) {
/* Free all of the memory associated with the png_ptr and info_ptr */
png_destroy_write_struct(&png_ptr, &info_ptr);
/* If we get here, we had a problem reading the file */
return false;
}
quality = Z_BEST_COMPRESSION * (quality + Z_BEST_COMPRESSION) / 100;
if (quality < 1) quality = 1;
else if (quality > Z_BEST_COMPRESSION) quality = Z_BEST_COMPRESSION;
png_set_compression_level(png_ptr, quality);
/* Need?
png_info_init (info_ptr);
*/
/* Set up our STL stream output control */
png_set_write_fn (png_ptr, stream, &stdstream_write_data, &stdstream_flush_data);
///* If we have already read some of the signature */
//png_set_sig_bytes(png_ptr, sig_read);
int color_type;
switch (image.spp) {
case 1:
color_type = PNG_COLOR_TYPE_GRAY;
break;
case 4:
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
break;
default:
color_type = PNG_COLOR_TYPE_RGB;
}
png_set_IHDR (png_ptr, info_ptr, image.w, image.h, image.bps, color_type,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_BASE);
png_set_pHYs (png_ptr, info_ptr,
(int)(image.resolutionX() * 100 / 2.54),
(int)(image.resolutionY() * 100 / 2.54),
PNG_RESOLUTION_METER);
png_write_info (png_ptr, info_ptr);
/* swap bytes of 16 bit data as PNG stores in network-byte-order */
if (!Exact::NativeEndianTraits::IsBigendian)
png_set_swap(png_ptr);
/* The other way to write images */
int number_passes = 1;
const int stride = image.stride();
png_bytep row_pointers[1];
for (int pass = 0; pass < number_passes; ++pass)
for (int y = 0; y < image.h; ++y) {
row_pointers[0] = image.getRawData() + y * stride;
png_write_rows(png_ptr, (png_byte**)&row_pointers, 1);
}
png_write_end(png_ptr, NULL);
/* clean up after the read, and free any memory allocated - REQUIRED */
png_destroy_write_struct(&png_ptr, &info_ptr);
return true;
}
PNGCodec png_loader;
|