diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 17:43:19 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-24 17:43:19 +0000 |
commit | 0292059f4a16434600564cfa3f0ad2309a508a54 (patch) | |
tree | d95953cd53011917c4df679b96aedca39401b54f /kernel/kls_svg/fmt_codec_png.cpp | |
download | libksquirrel-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.cpp | 655 |
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" |