summaryrefslogtreecommitdiffstats
path: root/kernel/kls_svg/fmt_codec_png.cpp
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 17:43:19 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 17:43:19 +0000
commit0292059f4a16434600564cfa3f0ad2309a508a54 (patch)
treed95953cd53011917c4df679b96aedca39401b54f /kernel/kls_svg/fmt_codec_png.cpp
downloadlibksquirrel-0292059f4a16434600564cfa3f0ad2309a508a54.tar.gz
libksquirrel-0292059f4a16434600564cfa3f0ad2309a508a54.zip
Added libksquirrel for KDE3
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/libraries/libksquirrel@1095624 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kernel/kls_svg/fmt_codec_png.cpp')
-rw-r--r--kernel/kls_svg/fmt_codec_png.cpp655
1 files changed, 655 insertions, 0 deletions
diff --git a/kernel/kls_svg/fmt_codec_png.cpp b/kernel/kls_svg/fmt_codec_png.cpp
new file mode 100644
index 0000000..66c43ee
--- /dev/null
+++ b/kernel/kls_svg/fmt_codec_png.cpp
@@ -0,0 +1,655 @@
+/* This file is part of ksquirrel-libs (http://ksquirrel.sf.net)
+
+ Copyright (c) 2004 Dmitry Baryshev <ksquirrel@tut.by>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation;
+ either version 2 of the License, or (at your option) any later
+ version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ as32 with this library; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <iostream>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "ksquirrel-libs-png/png.h"
+
+#include "ksquirrel-libs/fmt_types.h"
+#include "ksquirrel-libs/fileio.h"
+#include "ksquirrel-libs/error.h"
+#include "ksquirrel-libs/fmt_utils.h"
+
+#include "fmt_codec_png_defs.h"
+#include "fmt_codec_png.h"
+
+#if defined CODEC_SVG || defined CODEC_DICOM
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <cstdio>
+#endif
+
+#ifdef CODEC_SVG
+#include "../xpm/codec_svg.xpm"
+#elif defined CODEC_DICOM
+#include "../xpm/codec_dicom.xpm"
+#else
+#include "../xpm/codec_png.xpm"
+#endif
+
+/*
+ *
+ * PNG (pronounced "ping") is a bitmap file format used to transmit and
+ * store bitmapped images. PNG supports the capability of storing up to
+ * 16 bits (gray-scale) or 48 bits (truecolor) per pixel, and up to 16 bits
+ * of alpha data. It handles the progressive display
+ * of image data and the storage of gamma,
+ * transparency and textual information, and it uses an efficient and
+ * lossless form of data compression.
+ *
+ */
+
+inline bool MALLOC_ROWS(png_bytep **A, const int RB, const int H)
+{
+ *A = (png_bytep*)malloc(H * sizeof(png_bytep*));
+
+ if(!*A)
+ return false;
+
+ for(s32 row = 0; row < H; row++)
+ (*A)[row] = 0;
+
+ for(s32 row = 0; row < (s32)H; row++)
+ {
+ (*A)[row] = (png_bytep)malloc(RB);
+
+ if(!(*A)[row])
+ return false;
+
+ memset((*A)[row], 0, RB);
+ }
+
+ return true;
+}
+
+inline void FREE_ROWS(png_bytep **A, const int H)
+{
+ if(*A)
+ {
+ for(s32 i = 0;i < H;i++)
+ {
+ if((*A)[i])
+ free((*A)[i]);
+ }
+
+ free(*A);
+ *A = 0;
+ }
+}
+
+fmt_codec::fmt_codec() : fmt_codec_base()
+{}
+
+fmt_codec::~fmt_codec()
+{}
+
+void fmt_codec::options(codec_options *o)
+{
+#ifdef CODEC_SVG
+ o->version = "0.1.2";
+ o->name = "Scalable Vector Graphics";
+ o->filter = "*.svg *.svgz ";
+ o->config = std::string(SVG_UI); // SVG_UI comes from Makefile.am
+ o->mime = "";
+ o->mimetype = "image/svg+xml";
+ o->pixmap = codec_svg;
+ o->readable = true;
+ o->canbemultiple = false;
+ o->writestatic = false;
+ o->writeanimated = false;
+ o->needtempfile = true;
+#elif defined CODEC_DICOM
+ o->version = "1.1.3";
+ o->name = "DICOM";
+ o->filter = "*.dcm ";
+ o->config = "";
+ o->mime = "";
+ o->mimetype = "image/x-dicom";
+ o->pixmap = codec_dicom;
+ o->readable = true;
+ o->canbemultiple = false;
+ o->writestatic = false;
+ o->writeanimated = false;
+ o->needtempfile = true;
+#else
+ o->version = "1.1.3";
+ o->name = "Portable Network Graphics";
+ o->filter = "*.png ";
+ o->config = "";
+ o->mime = "\x0089\x0050\x004E\x0047\x000D\x000A\x001A\x000A";
+ o->mimetype = "image/png";
+ o->pixmap = codec_png;
+ o->readable = true;
+ o->canbemultiple = false;
+ o->writestatic = true;
+ o->writeanimated = false;
+ o->needtempfile = false;
+#endif
+}
+
+#ifdef CODEC_ANOTHER
+void fmt_codec::fill_default_settings()
+{
+ settings_value val;
+
+ // scale factor in percents
+ val.type = settings_value::v_int;
+ val.iVal = 1;
+
+ m_settings["scale"] = val;
+}
+#endif
+
+s32 fmt_codec::read_init(const std::string &file)
+{
+ png_ptr = 0;
+ info_ptr = 0;
+ fptr = 0;
+ frame = 0;
+ prev = 0;
+ cur = 0;
+ zerror = false;
+
+#ifdef CODEC_SVG
+ int status;
+
+ fmt_settings::iterator it = m_settings.find("scale");
+
+ // percents / 100
+ int scale = (it == m_settings.end() || (*it).second.type != settings_value::v_int)
+ ? 1 : (*it).second.iVal;
+
+ if(scale < 1 || scale > 10)
+ scale = 1;
+
+ char z[32];
+ snprintf(z, 32, "%d", scale);
+
+ pid_t pid = fork();
+
+ if(!pid)
+ {
+ execlp(SVG2PNG, SVG2PNG, "--binary", RSVG, "--input", file.c_str(), "--output", tmp.c_str(), "-z", z, (char *)0);
+ exit(1);
+ }
+ else if(pid == -1)
+ return SQE_R_BADFILE;
+
+ ::waitpid(pid, &status, 0);
+
+ if(WIFEXITED(status))
+ if(WEXITSTATUS(status))
+ return SQE_R_BADFILE;
+ else;
+ else
+ return SQE_R_BADFILE;
+
+ fptr = fopen(tmp.c_str(), "rb");
+
+#elif defined CODEC_DICOM
+
+ int status;
+
+ pid_t pid = fork();
+
+ if(!pid)
+ {
+ execlp(DICOM, DICOM, file.c_str(), tmp.c_str(), (char *)0);
+ exit(1);
+ }
+ else if(pid == -1)
+ return SQE_R_BADFILE;
+
+ ::waitpid(pid, &status, 0);
+
+ if(WIFEXITED(status))
+ if(WEXITSTATUS(status))
+ return SQE_R_BADFILE;
+ else;
+ else
+ return SQE_R_BADFILE;
+
+ fptr = fopen(tmp.c_str(), "rb");
+
+#else
+ fptr = fopen(file.c_str(), "rb");
+#endif
+
+ if(!fptr)
+ return SQE_R_NOFILE;
+
+ currentImage = -1;
+
+ if((png_ptr = my_png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0)) == NULL)
+ {
+ zerror = true;
+ return SQE_R_NOMEMORY;
+ }
+
+ if((info_ptr = my_png_create_info_struct(png_ptr)) == NULL)
+ {
+ zerror = true;
+ return SQE_R_NOMEMORY;
+ }
+
+ if(setjmp(png_jmpbuf(png_ptr)))
+ {
+ zerror = true;
+ return SQE_R_BADFILE;
+ }
+
+ my_png_init_io(png_ptr, fptr);
+ my_png_read_info(png_ptr, info_ptr);
+ my_png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*)0, (int*)0);
+
+ img.w = next_frame_width = width;
+ img.h = next_frame_height = height;
+ img.bpp = bit_depth;
+
+ if(img.bpp == 16)
+ my_png_set_strip_16(png_ptr);
+
+ if(img.bpp < 8)
+ my_png_set_packing(png_ptr);
+
+ if(color_type == PNG_COLOR_TYPE_GRAY && img.bpp < 8)
+ my_png_set_gray_1_2_4_to_8(png_ptr);
+
+ if(color_type == PNG_COLOR_TYPE_PALETTE)
+ my_png_set_palette_to_rgb(png_ptr);
+
+ if(color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ my_png_set_gray_to_rgb(png_ptr);
+
+ if(my_png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
+ my_png_set_tRNS_to_alpha(png_ptr);
+
+ my_png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
+
+ number_passes = my_png_set_interlace_handling(png_ptr);
+
+ my_png_read_update_info(png_ptr, info_ptr);
+
+ finfo.animated = !!my_png_get_valid(png_ptr, info_ptr, PNG_INFO_acTL);
+
+ frames = finfo.animated ? my_png_get_num_frames(png_ptr, info_ptr) : 1;
+
+ if(!frames) return SQE_R_BADFILE;
+
+ img.interlaced = number_passes > 1;
+ img.passes = finfo.animated ? 1 : number_passes;
+
+ if(finfo.animated)
+ {
+ if(!MALLOC_ROWS(&prev, width * sizeof(RGBA), height))
+ return SQE_R_NOMEMORY;
+
+ if(!MALLOC_ROWS(&cur, width * sizeof(RGBA), height))
+ return SQE_R_NOMEMORY;
+ }
+
+ std::string color_;
+
+ img.hasalpha = (color_type & PNG_COLOR_MASK_ALPHA);
+
+ switch((color_type & ~PNG_COLOR_MASK_ALPHA))
+ {
+ case PNG_COLOR_TYPE_RGB: color_ = "RGB"; break;
+ case PNG_COLOR_TYPE_PALETTE: color_ = "Color indexed"; break;
+ case PNG_COLOR_TYPE_GRAY: color_ = "Grayscale"; break;
+
+ default:
+ color_ = "Unknown";
+ }
+
+ if(img.hasalpha)
+ color_ += " with ALPHA";
+
+ img.compression = "Deflate method 8, 32K window";
+ img.colorspace = color_;
+ if(!finfo.animated) img.delay = 0;
+
+#ifdef PNG_TEXT_SUPPORTED
+ png_textp lines = info_ptr->text;
+
+ if(!lines || !info_ptr->num_text)
+ return SQE_OK;
+
+ for(s32 i = 0;i < info_ptr->num_text;i++)
+ {
+ fmt_metaentry mt;
+
+ mt.group = lines[i].key;
+ mt.data = lines[i].text;
+
+ addmeta(mt);
+ }
+#endif
+
+ return SQE_OK;
+}
+
+s32 fmt_codec::read_next()
+{
+ currentImage++;
+
+ if(currentImage == frames)
+ return SQE_NOTOK;
+
+ if(setjmp(png_jmpbuf(png_ptr)))
+ {
+ zerror = true;
+ return SQE_R_BADFILE;
+ }
+
+ if(finfo.animated)
+ {
+ if(currentImage)
+ {
+ if(next_frame_dispose_op == PNG_DISPOSE_OP_BACKGROUND)
+ {
+ for(u32 j = next_frame_y_offset,i = 0;i < next_frame_height;j++,i++)
+ memset(cur[j]+next_frame_x_offset*sizeof(RGBA), 0, next_frame_width * sizeof(RGBA));
+ }
+ else if(next_frame_dispose_op == PNG_DISPOSE_OP_PREVIOUS)
+ {
+ for(u32 i = 0;i < height;i++)
+ memcpy(cur[i], prev[i], width*sizeof(RGBA));
+ }
+ else // next_frame_dispose_op == PNG_DISPOSE_OP_NONE
+ {
+ }
+
+ for(u32 i = 0;i < height;i++)
+ memcpy(prev[i], cur[i], width*sizeof(RGBA));
+ }
+ else if(my_png_get_first_frame_is_hidden(png_ptr, info_ptr))
+ {
+ if(!MALLOC_ROWS(&frame, width * sizeof(RGBA), height))
+ return SQE_R_NOMEMORY;
+
+ my_png_read_frame_head(png_ptr, info_ptr);
+ my_png_read_image(png_ptr, frame);
+
+ FREE_ROWS(&frame, height);
+
+ frames--;
+
+ if(frames == 1)
+ {
+ my_png_read_frame_head(png_ptr, info_ptr);
+ finfo.animated = false;
+ img.passes = number_passes;
+ finfo.image.push_back(img);
+ return SQE_OK;
+ }
+ else if(!frames)
+ return SQE_R_BADFILE; // oops?
+ }
+
+ FREE_ROWS(&frame, next_frame_height);
+
+ my_png_read_frame_head(png_ptr, info_ptr);
+
+ if(my_png_get_valid(png_ptr, info_ptr, PNG_INFO_fcTL))
+ {
+ my_png_get_next_frame_fcTL(png_ptr, info_ptr,
+ &next_frame_width, &next_frame_height,
+ &next_frame_x_offset, &next_frame_y_offset,
+ &next_frame_delay_num, &next_frame_delay_den,
+ &next_frame_dispose_op, &next_frame_blend_op);
+ }
+ else
+ {
+ next_frame_width = width;
+ next_frame_height = height;
+ next_frame_x_offset = 0;
+ next_frame_y_offset = 0;
+ next_frame_dispose_op = PNG_DISPOSE_OP_BACKGROUND;
+ next_frame_blend_op = PNG_BLEND_OP_SOURCE;
+ }
+
+ if(!next_frame_delay_den) next_frame_delay_den = 100;
+
+ img.delay = (s32)(((double)next_frame_delay_num / next_frame_delay_den) * 1000);
+
+ if(next_frame_width + next_frame_x_offset > width || next_frame_height + next_frame_y_offset > height)
+ return SQE_R_BADFILE;
+
+ if(!MALLOC_ROWS(&frame, next_frame_width * sizeof(RGBA), next_frame_height))
+ return SQE_R_NOMEMORY;
+
+ my_png_read_image(png_ptr, frame);
+
+ // copy all pixel values including alpha
+ if(!currentImage || next_frame_blend_op == PNG_BLEND_OP_SOURCE)
+ {
+ for(u32 j = next_frame_y_offset,i = 0;i < next_frame_height;j++,i++)
+ memcpy(cur[j]+next_frame_x_offset*sizeof(RGBA), frame[i], next_frame_width * sizeof(RGBA));
+ }
+ else // over
+ {
+ RGBA *src, *dst;
+
+ for(u32 j = next_frame_y_offset,i = 0;i < next_frame_height;j++,i++)
+ {
+ src = (RGBA *)frame[i];
+ dst = (RGBA *)(cur[j]+next_frame_x_offset*sizeof(RGBA));
+ u32 k = next_frame_width;
+
+ while(k--)
+ {
+ // fully transparent foreground
+ if(src->a == 0)
+ ;
+ else if(src->a == 255 || dst->a == 0)
+ *dst = *src;
+ else // composite
+ {
+ dst->r = ((src->a * (src->r - dst->r))>>8) + dst->r;
+ dst->g = ((src->a * (src->g - dst->g))>>8) + dst->g;
+ dst->b = ((src->a * (src->b - dst->b))>>8) + dst->b;
+ //dst->a = ((src->a * (src->a - dst->a))>>8) + dst->a;
+ }
+
+ src++;
+ dst++;
+ }
+ }
+ }
+ }
+
+ finfo.image.push_back(img);
+
+ return SQE_OK;
+}
+
+s32 fmt_codec::read_next_pass()
+{
+ line = -1;
+
+ return SQE_OK;
+}
+
+s32 fmt_codec::read_scanline(RGBA *scan)
+{
+ fmt_image *im = image(currentImage);
+
+ line++;
+
+ if(zerror || setjmp(png_jmpbuf(png_ptr)))
+ {
+ zerror = true;
+ return SQE_R_BADFILE;
+ }
+
+ if(finfo.animated)
+ memcpy(scan, cur[line], im->w * sizeof(RGBA));
+ else
+ my_png_read_row(png_ptr, (png_bytep)scan, png_bytep_NULL);
+
+ return SQE_OK;
+}
+
+void fmt_codec::read_close()
+{
+ if(png_ptr) my_png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
+
+ if(fptr) fclose(fptr);
+
+ FREE_ROWS(&frame, next_frame_height);
+ FREE_ROWS(&prev, height);
+ FREE_ROWS(&cur, height);
+
+ finfo.meta.clear();
+ finfo.image.clear();
+}
+
+#ifdef CODEC_PNG
+
+void fmt_codec::getwriteoptions(fmt_writeoptionsabs *opt)
+{
+ opt->interlaced = true;
+ opt->compression_scheme = CompressionInternal;
+ opt->compression_min = 1;
+ opt->compression_max = 9;
+ opt->compression_def = 7;
+ opt->passes = 8;
+ opt->needflip = false;
+ opt->palette_flags = 0 | fmt_image::pure32;
+}
+
+s32 fmt_codec::write_init(const std::string &file, const fmt_image &image, const fmt_writeoptions &opt)
+{
+ m_png_ptr = 0;
+ m_info_ptr = 0;
+ m_fptr = 0;
+ m_zerror = false;
+
+ if(!image.w || !image.h || file.empty())
+ return SQE_W_WRONGPARAMS;
+
+ writeimage = image;
+ writeopt = opt;
+
+ m_fptr = fopen(file.c_str(), "wb");
+
+ if(!m_fptr)
+ return SQE_W_NOFILE;
+
+ m_png_ptr = my_png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+
+ if(!m_png_ptr)
+ {
+ m_zerror = true;
+ return SQE_W_NOMEMORY;
+ }
+
+ m_info_ptr = my_png_create_info_struct(m_png_ptr);
+
+ if(!m_info_ptr)
+ {
+ m_zerror = true;
+ return SQE_W_NOMEMORY;
+ }
+
+ if(setjmp(png_jmpbuf(m_png_ptr)))
+ {
+ m_zerror = true;
+ return SQE_W_ERROR;
+ }
+
+ my_png_init_io(m_png_ptr, m_fptr);
+
+ my_png_set_IHDR(m_png_ptr, m_info_ptr, writeimage.w, writeimage.h, 8, PNG_COLOR_TYPE_RGB_ALPHA,
+ ((writeopt.interlaced) ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE),
+ PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+ png_color_8 sig_bit;
+
+ sig_bit.red = 8;
+ sig_bit.green = 8;
+ sig_bit.blue = 8;
+ sig_bit.alpha = 8;
+
+ my_png_set_sBIT(m_png_ptr, m_info_ptr, &sig_bit);
+
+ s32 factor = (writeopt.compression_level < 1 || writeopt.compression_level > 9) ? 1 : writeopt.compression_level;
+
+ my_png_set_compression_level(m_png_ptr, factor);
+
+ my_png_write_info(m_png_ptr, m_info_ptr);
+
+ my_png_set_shift(m_png_ptr, &sig_bit);
+
+ return SQE_OK;
+}
+
+s32 fmt_codec::write_next()
+{
+ my_png_set_swap(m_png_ptr);
+
+ my_png_set_packswap(m_png_ptr);
+
+ my_png_set_interlace_handling(m_png_ptr);
+
+ return SQE_OK;
+}
+
+s32 fmt_codec::write_next_pass()
+{
+ return SQE_OK;
+}
+
+s32 fmt_codec::write_scanline(RGBA *scan)
+{
+ if(m_zerror || setjmp(png_jmpbuf(m_png_ptr)))
+ {
+ m_zerror = true;
+ return SQE_W_ERROR;
+ }
+
+ m_row_pointer = (png_bytep)scan;
+
+ my_png_write_rows(m_png_ptr, &m_row_pointer, 1);
+
+ return SQE_OK;
+}
+
+void fmt_codec::write_close()
+{
+ if(m_png_ptr && !m_zerror) my_png_write_end(m_png_ptr, m_info_ptr);
+ if(m_png_ptr) my_png_destroy_write_struct(&m_png_ptr, &m_info_ptr);
+ if(m_fptr) fclose(m_fptr);
+}
+
+std::string fmt_codec::extension(const s32 /*bpp*/)
+{
+ return std::string("png");
+}
+
+#endif
+
+#include "fmt_codec_cd_func.h"