openjpeg/src/bin/fltk/flviewer/PNG.cxx

365 lines
7.9 KiB
C++

#include <config.h>
#include "opj_apps_config.h"
#ifdef OPJ_HAVE_LIBPNG
/*
* author(s) and license
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#include <png.h>
#include <zlib.h>
}
#else
#include <png.h>
#include <zlib.h>
#endif /* __cplusplus */
#include "opj_stdint.h"
#include <FL/fl_ask.H>
#include "flviewer.hh"
#include "PNG.hh"
#include "lang/png_lang.h_utf8"
/* #define USE_PNG_IMAGE */
static unsigned char *png_buf;
static void PNG_postlude(void)
{
if(png_buf) { free(png_buf); png_buf = NULL; }
}
void PNG_load(Canvas *canvas, FILE *reader, const char *read_idf,
int64_t fsize)
{
#ifndef USE_PNG_IMAGE // uses reader
png_bytep row;
png_structp png;
png_infop info;
unsigned char *buf;
double gamma, display_exponent;
int unit, pass, nr_passes, depth;
png_uint_32 resx, resy;
png_uint_32 width, height;
unsigned int i, src_w;
int color_type, has_alpha;
int bit_depth, interlace_type,compression_type, filter_type;
/* libpng-VERSION/example.c:
* PC : screen_gamma = 2.2;
* Mac: screen_gamma = 1.7 or 1.0;
*/
display_exponent = 2.2;
if((png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL)) == NULL)
goto fin;
if((info = png_create_info_struct(png)) == NULL)
goto fin;
if(setjmp(png_jmpbuf(png)))
goto fin;
FLViewer_wait();
png_init_io(png, reader);
png_read_info(png, info);
png_get_IHDR(png, info, &width, &height,
&bit_depth, &color_type, &interlace_type,
&compression_type, &filter_type);
if(color_type == PNG_COLOR_TYPE_PALETTE)
png_set_expand(png);
else
if(color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
png_set_expand(png);
if(png_get_valid(png, info, PNG_INFO_tRNS))
png_set_expand(png);
if(bit_depth == 16)
png_set_strip_16(png);
/* GRAY => RGB; GRAY_ALPHA => RGBA
*/
if(color_type == PNG_COLOR_TYPE_GRAY
|| color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
{
png_set_gray_to_rgb(png);
color_type =
(color_type == PNG_COLOR_TYPE_GRAY? PNG_COLOR_TYPE_RGB:
PNG_COLOR_TYPE_RGB_ALPHA);
}
if( !png_get_gAMA(png, info, &gamma))
gamma = 0.45455;
png_set_gamma(png, display_exponent, gamma);
nr_passes = png_set_interlace_handling(png);
png_read_update_info(png, info);
png_get_pHYs(png, info, &resx, &resy, &unit);
color_type = png_get_color_type(png, info);
has_alpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA);
if(has_alpha)
depth = 4;
else
depth = 3;
src_w = width * (3 + has_alpha);
buf = (unsigned char*)malloc(src_w * height);
if(buf == NULL)
{
fprintf(stderr,"PNG.cxx:%d:\n\tmemory out\n",__LINE__);
goto fin;
}
for(pass = 0; pass < nr_passes; pass++)
{
row = buf;
for(i = 0; i < height; i++)
{
/* libpng.3:
* If you want the "sparkle" effect, just call png_read_rows() as
* normal, with the third parameter NULL.
*/
png_read_rows(png, &row, NULL, 1);
row += src_w;
}
}
FLViewer_url(read_idf, width, height);
FLViewer_use_buffer(buf, width, height, depth);
png_buf = buf;
canvas->cleanup = &PNG_postlude;
fin:
if(png)
png_destroy_read_struct(&png, &info, NULL);
FLViewer_close_reader();
#else // USE_PNG_IMAGE uses read_idf
unsigned char *buf;
png_image image;
int depth = 3;
buf = NULL;
memset(&image, 0, (sizeof image));
image.version = PNG_IMAGE_VERSION;
FLViewer_close_reader();
FLViewer_wait();
if(png_image_begin_read_from_file(&image, read_idf))
{
png_bytep buffer;
depth = PNG_IMAGE_SAMPLE_CHANNELS(image.format);
if(depth == 3 || depth == 1)
{
image.format = PNG_FORMAT_RGB; depth = 3;
}
else
if(depth == 4 || depth == 2)
{
image.format = PNG_FORMAT_RGBA; depth = 4;
}
buffer = (png_bytep)malloc(PNG_IMAGE_SIZE(image));
if(buffer != NULL
&& png_image_finish_read(&image, NULL/*background*/,
buffer,
0/*row_stride*/, NULL/*colormap*/))
{
buf = buffer;
}
else
{
if(buffer == NULL)
png_image_free(&image);
else
free(buffer);
}
}
if(buf == NULL) return;
FLViewer_url(read_idf, image.width, image.height);
FLViewer_use_buffer(buf, image.width, image.height, depth);
png_buf = buf;
canvas->cleanup = &PNG_postlude;
#endif /* USE_PNG_IMAGE */
}/* PNG_load() */
static int to_png(unsigned char *buf, int width, int height, int nr_comp,
FILE *writer)
{
png_structp png;
png_infop info;
unsigned char *s;
int color_type, step;
int y, ok;
png_color_8 sig_bit;
ok = 0;
info = NULL;
/* Create and initialize the png_struct with the desired error handler
* functions. If you want to use the default stderr and longjump method,
* you can supply NULL for the last three parameters. We also check that
* the library version is compatible with the one used at compile time,
* in case we are using dynamically linked libraries. REQUIRED.
*/
png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
if(png == NULL) goto fin;
/* Allocate/initialize the image information data. REQUIRED
*/
info = png_create_info_struct(png);
if(info == NULL) goto fin;
/* Set error handling. REQUIRED if you are not supplying your own
* error handling functions in the png_create_write_struct() call.
*/
if(setjmp(png_jmpbuf(png))) goto fin;
/* I/O initialization functions is REQUIRED
*/
png_init_io(png, writer);
/* Set the image information here. Width and height are up to 2^31,
* bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
* the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
* PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
* or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
* PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
* currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE.
* REQUIRED
*
* ERRORS:
*
* color_type == PNG_COLOR_TYPE_PALETTE && bit_depth > 8
* color_type == PNG_COLOR_TYPE_RGB && bit_depth < 8
* color_type == PNG_COLOR_TYPE_GRAY_ALPHA && bit_depth < 8
* color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8
*
*/
png_set_compression_level(png, Z_BEST_COMPRESSION);
if(nr_comp == 4)
{
step = 4 * width;
sig_bit.alpha = 8;
sig_bit.red = sig_bit.green = sig_bit.blue = 8;
color_type = PNG_COLOR_TYPE_RGB_ALPHA;
}
else
if(nr_comp == 3)
{
step = 3 * width;
sig_bit.alpha = 0;
sig_bit.red = sig_bit.green = sig_bit.blue = 8;
color_type = PNG_COLOR_TYPE_RGB;
}
else
if(nr_comp == 2)
{
step = 2 * width;
sig_bit.gray = 8;
sig_bit.red = sig_bit.green = sig_bit.blue = 0;
sig_bit.alpha = 8;
color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
}
else /* 1 */
{
step = width;
sig_bit.gray = 8;
sig_bit.red = sig_bit.green = sig_bit.blue = sig_bit.alpha = 0;
color_type = PNG_COLOR_TYPE_GRAY;
}
png_set_sBIT(png, info, &sig_bit);
png_set_IHDR(png, info, width, height, 8,
color_type,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
png_set_gamma(png, 2.2, 1./2.2);
if(nr_comp > 2)
{
png_set_sRGB(png, info, PNG_sRGB_INTENT_PERCEPTUAL);
}
png_write_info(png, info);
s = buf;
for(y = 0; y < height; ++y)
{
png_write_row(png, s);
s += step;
}
png_write_end(png, info);
ok = 1;
fin:
if(png)
{
png_destroy_write_struct(&png, &info);
}
return ok;
}/* to_png() */
void PNG_save_file(Canvas *canvas, const char *write_idf)
{
FILE *writer;
int width, height, nr_comp;
width = canvas->new_iwidth;
height = canvas->new_iheight;
nr_comp = canvas->new_idepth;
if((writer = fopen(write_idf, "wb")) == NULL)
{
fl_alert(DST_DID_NOT_OPEN_s, write_idf);
return;
}
if(to_png((unsigned char*)canvas->cbuf,
width, height, nr_comp, writer) == 0)
{
fl_alert("%s", WRITE_PNG_FAILS_s);
}
fclose(writer);
}/* PNG_save_file() */
#endif /* OPJ_HAVE_LIBPNG */