exact-image-0.9.1/0000755000076400007640000000000012467664356012404 5ustar renereneexact-image-0.9.1/frontends/0000755000076400007640000000000012467664254014403 5ustar renereneexact-image-0.9.1/frontends/Makefile0000644000076400007640000000107312427205777016041 0ustar renereneinclude build/top.make ifneq "$(WITHLIBTIFF)" "1" NOT_SRCS += e2mtiff.cc endif # build each .cc file as executable - if this is not desired # in the future a list must be supplied manually ... BINARY = $(basename $(filter-out $(NOT_SRCS), $(notdir $(wildcard $(X_MODULE)/*.cc $(X_MODULE)/*.c))) $(SRCS)) BINARY_EXT = $(X_EXEEXT) DEPS = $(lib_BINARY) $(codecs_BINARY) $(bardecode_BINARY) $(X_OUTARCH)/utility/ArgumentList$(X_OBJEXT) $(X_OUTARCH)/utility/File$(X_OBJEXT) CPPFLAGS += -I utility #LDFLAGS += -lGL -lGLU -lglut -L/usr/X11/lib64 include build/bottom.make exact-image-0.9.1/frontends/optimize2bw.cc0000644000076400007640000001535111352355732017160 0ustar renerene/* * Copyright (C) 2005 - 2010 René Rebe, ExactCODE GmbH * (C) 2005, 2006 Archivista GmbH, CH-8042 Zuerich * * 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 #include #include #include #include "ArgumentList.hh" #include "Image.hh" #include "Codecs.hh" #include "Colorspace.hh" #include "Matrix.hh" #include "scale.hh" #include "optimize2bw.hh" using namespace Utility; ArgumentList arglist; bool usage(const Argument& arg) { std::cerr << "Color, gray image to bi-level optimizer" << " - Copyright 2005 - 2010 by René Rebe" << std::endl << "Usage:" << std::endl; arglist.Usage (std::cerr); exit(1); } int main (int argc, char* argv[]) { // setup the argument list Argument arg_help ("", "help", "display this help text and exit"); Argument arg_input ("i", "input", "input file", 1, std::numeric_limits::max()); Argument arg_output ("o", "output", "output file", 1, std::numeric_limits::max()); Argument arg_low ("l", "low", "low normalization value", 0, 0, 1); Argument arg_high ("h", "high", "high normalization value", 0, 0, 1); Argument arg_threshold ("t", "threshold", "threshold value", 0, 0, 1); Argument arg_radius ("r", "radius", "\"unsharp mask\" radius", 0, 0, 1); Argument arg_denoise ("n", "denoise", "remove (\"denoise\") single bit pixel noise"); Argument arg_scale ("s", "scale", "scale output by factor", 0.0, 0, 1); Argument arg_dpi ("d", "dpi", "scale to specified DPI", 0, 0, 1); Argument arg_sd ("sd", "standard-deviation", "standard deviation for Gaussian distribution", 0.0, 0, 1); arg_help.Bind (usage); arglist.Add (&arg_help); arglist.Add (&arg_input); arglist.Add (&arg_output); arglist.Add (&arg_low); arglist.Add (&arg_high); arglist.Add (&arg_threshold); arglist.Add (&arg_radius); arglist.Add (&arg_scale); arglist.Add (&arg_dpi); arglist.Add (&arg_sd); arglist.Add (&arg_denoise); // parse the specified argument list - and maybe output the Usage if (!arglist.Read (argc, argv)) { usage(arg_help); } int errors = 0; ImageCodec* codec = 0; std::fstream* stream = 0; Image image; int f2 = 0; for (int f = 0, i2 = 0; f < arg_input.Size(); ++f) { for (int n = 1, i = 0; i < n; ++i) { int ret = ImageCodec::Read(arg_input.Get(f), image, "", i); if (!ret) { std::cerr << "Error reading input file." << std::endl; ++errors; break; } if (i == 0) n = ret; int low = 0; int high = 0; int sloppy_threshold = 0; int radius = 3; double sd = 2.1; if (arg_low.Get() != 0) { low = arg_low.Get(); std::cerr << "Low value overwritten: " << low << std::endl; } if (arg_high.Get() != 0) { high = arg_high.Get(); std::cerr << "High value overwritten: " << high << std::endl; } if (arg_radius.Get() != 0) { radius = arg_radius.Get(); std::cerr << "Radius: " << radius << std::endl; } if (arg_sd.Get() != 0) { sd = arg_sd.Get(); std::cerr << "SD overwritten: " << sd << std::endl; } // convert to 1-bit (threshold) int threshold = 0; if (arg_threshold.Get() != 0) { threshold = arg_threshold.Get(); std::cerr << "Threshold: " << threshold << std::endl; } optimize2bw (image, low, high, threshold, sloppy_threshold, radius, sd); // scale image using interpolation double scale = arg_scale.Get (); int dpi = arg_dpi.Get (); if (scale != 0.0 && dpi != 0) { std::cerr << "DPI and scale argument must not be specified at once!" << std::endl; ++errors; break; } if (dpi != 0) { if (image.resolutionX() == 0) image.setResolution(image.resolutionY(), image.resolutionY()); if (image.resolutionX() == 0) { std::cerr << "Image does not include DPI information!" << std::endl; ++errors; break; } scale = (double)(dpi) / image.resolutionX(); } if (scale < 0.0) { std::cerr << "Scale must not be negativ!" << std::endl; ++errors; break; } if (scale > 0.0) { if (scale < 1.0) box_scale (image, scale, scale); else bilinear_scale (image, scale, scale); } if (arg_threshold.Get() == 0) threshold = 200; // denoise? only if more than 1bps in the source image if (arg_denoise.Get() && image.bps > 1) { colorspace_gray8_threshold (image, threshold); colorspace_gray8_denoise_neighbours (image); colorspace_gray8_to_gray1 (image); } else { if (image.bps > 1) colorspace_gray8_to_gray1 (image, threshold); } if (!codec) { if (f2 >= arg_output.Size()) { std::cerr << "Error: no more output filename for image input" << std::endl; break; } i2 = 0; // no multi-page codec, yet, try to create one std::string file = arg_output.Get(f2); std::string cod = ImageCodec::getCodec(file); std::string ext = ImageCodec::getExtension(file); stream = new std::fstream(file.c_str(), std::ios::in | std::ios::out | std::ios::trunc); codec = ImageCodec::MultiWrite(stream, cod, ext); // if we got no codec, write a classic, single-page file if (!codec) { if (!ImageCodec::Write(stream, image, cod, ext, 75, "")) std::cerr << "Error writing output file, image " << i2 << std::endl; delete stream; stream = 0; } ++f2; // filename used, next } // do we (now) have a codec?, write multi-page image if (codec) { if (!codec->Write(image, 75, "", i2)) { std::cerr << "Error writing output file, image " << i2 << std::endl; ++errors; } ++i2; } } } if (f2 < arg_output.Size()) std::cerr << "Error: " << arg_output.Size() - f2 << " filename(s) left for writing" << std::endl; // if we had a multi-page codec and stream free them now if (codec) delete codec; if (stream) delete stream; return errors; } exact-image-0.9.1/frontends/bardecode.cc0000644000076400007640000001173511406676147016625 0ustar renerene/* * The ExactImage library's any to multi-page TIFF converted * Copyright (C) 2007 - 2010 René Rebe, ExactCODE GmbH Germany * Copyright (C) 2007 Lars Kuhtz, ExactCODE GmbH Germany * * 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 #include #include #include #include #include "ArgumentList.hh" #include "Codecs.hh" #include "Tokenizer.hh" #include "Scanner.hh" using namespace Utility; //#define BARDECODE_DEBUG #ifdef BARDECODE_DEBUG void down_test(Image& img) { for (Image::const_iterator it = img.begin(); it != img.end(); it.down()) { *it; } } #endif using namespace BarDecode; namespace { struct comp { bool operator() (const scanner_result_t& a, const scanner_result_t& b) const { if (a.type < b.type) return true; else if (a.type > b.type) return false; else return (a.code < b.code); } }; std::string filter_non_printable(const std::string& s) { std::string result; for (size_t i = 0; i < s.size(); ++i) { if ( std::isprint(s[i]) ) result.push_back(s[i]); } return result; } }; int main (int argc, char* argv[]) { ArgumentList arglist (true); // enable residual gathering // setup the argument list Argument arg_help ("h", "help", "display this help text and exit"); Argument arg_threshold ("t", "threshold", "bi-level threshold value", 150, 0, 1); Argument arg_concurrent_lines ("c", "concurrent-lines", "number of lines that are scanned concurrently", 4, 0, 1); Argument arg_line_skip ("s", "line-skip", "number of lines that are skipped", 8, 0, 1); Argument arg_directions ( "d", "directions", "bitfield of directions to be scanned (0 none,1 left-to-right,2 top-down, 4 right-to-left, 8-down-top, 15 any)", 15, 0, 1); arglist.Add (&arg_help); arglist.Add (&arg_threshold); arglist.Add (&arg_directions); arglist.Add (&arg_concurrent_lines); arglist.Add (&arg_line_skip); // parse the specified argument list - and maybe output the Usage if (!arglist.Read (argc, argv) || arg_help.Get() == true) { std::cerr << "barcode recognition module of the exact-image library" << std::endl << " - Copyright 2007-2010 by René Rebe, ExactCODE" << std::endl << " - Copyright 2007 by Lars Kuhtz, ExactCODE" << std::endl << "Usage:" << std::endl; arglist.Usage (std::cerr); return 1; } const std::vector& filenames = arglist.Residuals(); Image image; int errors = 0; bool multiple_files = filenames.size () > 1; for (std::vector::const_iterator file = filenames.begin(); file != filenames.end (); ++file) { if (!ImageCodec::Read (*file, image)) { std::cerr << "Error reading " << *file << std::endl; ++errors; continue; } int threshold = arg_threshold.Get(); directions_t directions = (directions_t) arg_directions.Get(); int concurrent_lines = arg_concurrent_lines.Get(); int line_skip = arg_line_skip.Get(); std::map codes; if ( directions&(left_right|right_left) ) { BarDecode::BarcodeIterator<> it(&image,threshold,ean|code128|gs1_128|code39|code25i,directions,concurrent_lines,line_skip); while (! it.end() ) { ++codes[*it]; ++it; } } if ( directions&(top_down|down_top) ) { directions_t dir = (directions_t) ((directions&(top_down|down_top))>>1); BarDecode::BarcodeIterator it(&image,threshold,ean|code128|gs1_128|code39|code25i,dir,concurrent_lines,line_skip); while (! it.end() ) { ++codes[*it]; ++it; } } for (std::map::const_iterator it = codes.begin(); it != codes.end(); ++it) { if (it->first.type&(ean|code128|gs1_128) || it->second > 1) { if (multiple_files) std::cout << *file << ": "; std::cout << filter_non_printable(it->first.code) << " [type: " << it->first.type << " at: (" << it->first.x << "," << it->first.y << ")]" << std::endl; } } #ifdef BARDECODE_DEBUG down_test(image); #endif if (codes.empty()) ++errors; } return errors; } exact-image-0.9.1/frontends/edentify.cc0000644000076400007640000001427412201416445016510 0ustar renerene/* * The ExactImage library's identify compatible command line frontend. * Copyright (C) 2006 - 2013 René Rebe, ExactCODE GmbH * Copyright (C) 2006 Archivista * * 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 #include #include #include "config.h" #include "ArgumentList.hh" #include "File.hh" #include "Image.hh" #include "Codecs.hh" #include "Colorspace.hh" #include "scale.hh" #include "rotate.hh" #include "Matrix.hh" #include "riemersma.h" #include "floyd-steinberg.h" #include using namespace Utility; Image image; // the global Image we work on int main (int argc, char* argv[]) { ArgumentList arglist (true); // enable residual gathering // setup the argument list Argument arg_help ("h", "help", "display this help text and exit"); arglist.Add (&arg_help); Argument arg_verbose ("v", "verbose", "more verbose output"); arglist.Add (&arg_verbose); Argument arg_format ("f", "format", "user defined format string", 0, 1); arglist.Add (&arg_format); Argument arg_decompression ("d", "decompress", "decompression method for reading images e.g. thumb\n\t\t" "depending on the input format, allowing to read partial data", 0, 1); arglist.Add (&arg_decompression); // parse the specified argument list - and maybe output the Usage if (!arglist.Read (argc, argv)) return 1; if (arg_help.Get() == true || arglist.Residuals().empty()) { std::cerr << "Exact image identification (edentify)." << std::endl << "Version " VERSION << " - Copyright (C) 2006 - 2013 by ExactCODE and Archivista" << std::endl << "Usage:" << std::endl; arglist.Usage (std::cerr); return 1; } // for all residual arguments (image files) int errors = 0; const std::vector& list = arglist.Residuals(); for (std::vector::const_iterator file = list.begin(); file != list.end(); ++file) { for (int i = 0, n = 1; i < n; ++i) { int ret = ImageCodec::Read(*file, image, arg_decompression.Size() > 0 ? arg_decompression.Get() : "", i); if (ret < 1) { std::cout << "edentify: unable to open image '" << *file << "'." << std::endl; continue; } if (i == 0) n = ret; if (arg_format.Size() > 0) { const std::string& format = arg_format.Get(); for (std::string::const_iterator it = format.begin(); it != format.end(); ++it) { if (*it == '%') { if (++it == format.end()) --it; // print the % if at the end switch (*it) { // case 'b': break; // file size // case 'c': break; // comment case 'd': // directory case 'e': // filename extension case 'f': // filename case 't': // top of filename { Utility::File f (*file); switch (*it) { case 'd': std::cout << f.Dirname(); break; case 'e': std::cout << f.Extension(); break; case 'f': std::cout << f.Basename(); break; case 't': std::cout << f.BasenameWOExtension(); break; } } break; // %g page geometry case 'h': // height std::cout << image.h; break; case 'i': // input filename std::cout << *file; break; //case 'k': break; // number of unique colors // %l label // %m magick // %n number of scenes // %o output filename // %p page number case 'q': // quantum depth std::cout << image.bps; break; // TODO: report file container? break; // %r image class and colorspace // %s scene number // %u unique temporary filename case 'w': // width std::cout << image.w; break; case 'x': // x resolution std::cout << image.resolutionX() << " PixelsPerInch"; break; case 'y': // y resolution std::cout << image.resolutionY() << " PixelsPerInch"; break; case 'z': // image depth std::cout << image.bps; break; // %D image dispose method // %O page offset case 'P': // page width and height std::cout << image.w << "x" << image.h; break; // %Q image compression quality // %T image delay // %@ bounding box // %# signature case '%': std::cout << *it; break; default: if (it != format.begin()) --it; std::cout << *it; } } else if (*it == '\\') { if (++it == format.end()) --it; // print the \ if at the end switch (*it) { case 'n': std::cout << std::endl; break; case 't': std::cout << "\t"; break; case 'r': std::cout << "\r"; break; case '\\': std::cout << *it; break; default: if (it != format.begin()) --it; std::cout << *it; } } else std::cout << *it; } } else if (arg_verbose.Get()) { std::cout << "TODO: implement verbose output" << std::endl; } else { std::cout << *file; if (n > 1) std::cout << "[" << i << "]"; std::cout << ": " << (image.getDecoderID().empty() ? "NONE" : image.getDecoderID() ) << " " << image.w << "x" << image.h; if (image.resolutionY() && image.resolutionY()) std::cout << " @ " << image.resolutionX() << "x" << image.resolutionY() << "dpi (" << 254 * image.w / image.resolutionX() / 10 << "x" << 254 * image.h / image.resolutionY() / 10 << "mm)"; int bits = image.bps * image.spp; std::cout << " " << bits << " bit" << (bits>1 ? "s" : "") << ", " << image.spp << " channel" << (image.spp>1 ? "s" : "") << std::endl; std::cout << std::endl; } } } return errors; } exact-image-0.9.1/frontends/empty-page.cc0000644000076400007640000000523412160543173016750 0ustar renerene/* * Copyright (C) 2005-2013 René Rebe * (C) 2005 Archivista GmbH, CH-8042 Zuerich * * 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 #include "Image.hh" #include "Codecs.hh" #include "ArgumentList.hh" #include "empty-page.hh" using namespace Utility; ArgumentList arglist; bool usage(const Argument& arg) { std::cerr << "Empty page detector" << " - Copyright 2005-2010 by René Rebe" << std::endl << "Usage:" << std::endl; arglist.Usage(std::cerr); exit(1); } int main (int argc, char* argv[]) { // setup the argument list Argument arg_help ("h", "help", "display this help text and exit"); Argument arg_input ("i", "input", "input file", 1, 1); Argument arg_margin ("m", "margin", "border margin to skip", 16, 0, 1); Argument arg_percent ("p", "percentage", "coverate for non-empty page", 0.05, 0, 1); arg_help.Bind (usage); arglist.Add (&arg_help); arglist.Add (&arg_input); arglist.Add (&arg_margin); arglist.Add (&arg_percent); // parse the specified argument list - and maybe output the Usage if (!arglist.Read (argc, argv)) { usage(arg_help); } const int margin = arg_margin.Get(); if (margin % 8 != 0) { std::cerr << "For speed reasons, the margin has to be a multiple of 8." << std::endl; return 1; } Image image; if (!ImageCodec::Read (arg_input.Get(), image)) { std::cerr << "Error reading input file." << std::endl; return 1; } int set_pixels; const double percent = arg_percent.Get(); bool is_empty = detect_empty_page (image, percent, margin, margin, &set_pixels); double image_percent = (float) set_pixels / (image.w * image.h) * 100; std::cerr << "The image has " << set_pixels << " dark pixels from a total of " << image.w * image.h << " (" << image_percent << "%)." << std::endl; if (!is_empty) { std::cerr << "non-empty" << std::endl; return 1; } std::cerr << "empty" << std::endl; return 0; } exact-image-0.9.1/frontends/econvert.cc0000644000076400007640000006770312406317230016532 0ustar renerene/* * The ExactImage library's convert compatible command line frontend. * Copyright (C) 2005 - 2014 René Rebe, ExactCODE GmbH * Copyright (C) 2005, 2008 Archivista 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 #include #include #include #include #include #include #include #include "config.h" #include "ArgumentList.hh" #include "Image.hh" #include "Codecs.hh" #include "Colorspace.hh" #include "low-level.hh" #include "scale.hh" #include "crop.hh" #include "rotate.hh" #include "canvas.hh" #include "Matrix.hh" #include "riemersma.h" #include "floyd-steinberg.h" #include "vectorial.hh" #include "GaussianBlur.hh" #include "agg_trans_affine.h" /* Let's reuse some parts of the official, stable API to avoid * duplicating code. * * This also includes the foreground/background color and vector * drawing style. */ #include "api/api.cc" #include "C.h" #include using namespace Utility; // the global "stack" of images we work on std::list images; typedef std::list::iterator images_iterator; #define FOR_ALL_IMAGES(f,...) \ for (images_iterator it = images.begin(); it != images.end(); ++it) \ f(**it, ##__VA_ARGS__) static void freeImages() { while (!images.empty()) { delete(images.back()); images.pop_back(); } } Argument arg_quality ("", "quality", "quality setting used for writing compressed images\n\t\t" "integer range 0-100, the default is 75", 0, 1, true, true); Argument arg_compression ("", "compress", "compression method for writing images e.g. G3, G4, Zip, ...\n\t\t" "depending on the output format, a reasonable setting by default", 0, 1, true, true); Argument arg_decompression ("", "decompress", "decompression method for reading images e.g. thumb\n\t\t" "depending on the input format, allowing to read partial data", 0, 1, true, true); Argument arg_stroke_width ("", "stroke-width", "the stroke width for vector primitives", 0, 1, true, true); #if WITHFREETYPE == 1 Argument arg_text_rotation ("", "text-rotation", "draw text using specified rotation", 0, 1, true, true); Argument arg_font ("", "font", "draw text using specified font file", 0, 1, true, true); #endif bool convert_input (const Argument& arg) { Image* image = 0; // save an empty template if we got one (for loading RAW images) if (!images.empty() && images.front()->getRawData() == 0) { image = images.front(); images.pop_front(); } freeImages(); for (int j = 0; j < arg.Size(); ++j) { std::string file = arg.Get(j); std::string cod = ImageCodec::getCodec(file); std::string ext = ImageCodec::getExtension(file); std::ifstream stream(file.c_str(), std::ios::in | std::ios::binary); std::string decompression = ""; if (arg_decompression.Size()) decompression = arg_decompression.Get(); for (int i = 0, n = 1; i < n; ++i) { if (!image) image = new Image; int ret = ImageCodec::Read(&stream, *image, cod, decompression, i); if (ret <= 0) { std::cerr << "Error reading input file " << arg.Get(j) << ", image: " << i << std::endl; delete image; return false; } if (i == 0) n = ret; images.push_back(image); image = 0; } } if (image) delete image; return true; } bool convert_append (const Argument& arg) { Image* base = 0; for (images_iterator it = images.begin(); it != images.end(); ++it) { if (it == images.begin()) base = *it; else append(*base, **it); } return true; } bool convert_output (const Argument& arg) { int quality = 75; if (arg_quality.Size()) quality = arg_quality.Get(); std::string compression = ""; if (arg_compression.Size()) compression = arg_compression.Get(); int i = 0, f = 0; images_iterator it = images.begin(); ImageCodec* codec = 0; std::fstream* stream = 0; for (; it != images.end(); ++it) { if (!codec) { if (f >= arg.Size()) break; i = 0; // no multi-page codec, yet, try to create one std::string file = arg.Get(f); std::string cod = ImageCodec::getCodec(file); std::string ext = ImageCodec::getExtension(file); stream = new std::fstream(file.c_str(), std::ios::in | std::ios::out | std::ios::trunc); codec = ImageCodec::MultiWrite(stream, cod, ext); // if we got no codec, write a classic, single-page file if (!codec) { if (!ImageCodec::Write(stream, **it, cod, ext, quality, compression)) std::cerr << "Error writing output file, image " << i << std::endl; delete stream; stream = 0; } ++f; // filename used, next } // do we (now) have a codec?, write multi-page image if (codec) { if (!codec->Write(**it, quality, compression, i)) std::cerr << "Error writing output file, image " << i << std::endl; ++i; } } // if we had a multi-page codec and stream free them now if (codec) delete codec; if (stream) delete stream; if (it != images.end()) std::cerr << "Error: " << std::distance(it, images.end()) << " image(s) left for writing" << std::endl; if (f < arg.Size()) std::cerr << "Error: " << arg.Size() - f << " filename(s) left for writing" << std::endl; return true; } bool convert_split (const Argument& arg) { // TODO: we could split the result into the iamge stack if (images.empty() || (*images.begin())->getRawData() == 0) { std::cerr << "No image available." << std::endl; return false; } Image& image = **images.begin(); Image split_image; split_image.copyMeta(**images.begin()); split_image.h /= arg.count; if (split_image.h == 0) { std::cerr << "Resulting image size too small." << std::endl << "The resulting slices must have at least a height of one pixel." << std::endl; return false; } int quality = 70; if (arg_quality.Size()) quality = arg_quality.Get(); std::string compression = ""; if (arg_compression.Size()) compression = arg_compression.Get(); int err = 0; for (int i = 0; i < arg.Size(); ++i) { std::cerr << "Writing file: " << arg.Get(i) << std::endl; split_image.setRawDataWithoutDelete (image.getRawData() + i * split_image.stride() * split_image.h); if (!ImageCodec::Write (arg.Get(i), split_image, quality, compression)) { err = 1; std::cerr << "Error writing output file." << std::endl; } } split_image.setRawDataWithoutDelete(0); // not deallocate in dtor return err == 0; } bool convert_colorspace (const Argument& arg) { FOR_ALL_IMAGES(colorspace_by_name, arg.Get().c_str()); return true; // TODO return value } bool convert_normalize (const Argument& arg) { FOR_ALL_IMAGES(normalize); return true; } bool convert_brightness (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(brightness_contrast_gamma, f, .0, 1.0); return true; } bool convert_contrast (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(brightness_contrast_gamma, .0, f, 1.0); return true; } bool convert_gamma (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(brightness_contrast_gamma, .0, .0, f); return true; } bool convert_blur (const Argument& arg) { double standard_deviation = arg.Get(); FOR_ALL_IMAGES(GaussianBlur, standard_deviation); return true; } bool convert_scale (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(scale, f, f); return true; } bool convert_thumbnail_scale (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(thumbnail_scale, f, f); return true; } bool convert_hue (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(hue_saturation_lightness, f, 0, 0); return true; } bool convert_saturation (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(hue_saturation_lightness, 0, f, 0); return true; } bool convert_lightness (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(hue_saturation_lightness, 0, 0, f); return true; } bool convert_nearest_scale (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(nearest_scale, f, f); return true; } bool convert_bilinear_scale (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(bilinear_scale, f, f); return true; } bool convert_bicubic_scale (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(bicubic_scale, f, f); return true; } bool convert_box_scale (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(box_scale, f, f); return true; } bool convert_ddt_scale (const Argument& arg) { double f = arg.Get(); FOR_ALL_IMAGES(ddt_scale, f, f); return true; } bool convert_flip (const Argument& arg) { FOR_ALL_IMAGES(flipY); return true; } bool convert_flop (const Argument& arg) { FOR_ALL_IMAGES(flipX); return true; } bool convert_rotate (const Argument& arg) { FOR_ALL_IMAGES(rotate, arg.Get(), background_color); return true; } bool convert_convolve (const Argument& arg) { double divisor = 0; const std::vector& v = arg.Values (); int n = (int)sqrt(v.size()); for (unsigned int i = 0; i < v.size(); ++i) divisor += v[i]; if (divisor == 0) divisor = 1; FOR_ALL_IMAGES(convolution_matrix, &v[0], n, n, divisor); return true; } bool convert_dither_floyd_steinberg (const Argument& arg) { FOR_ALL_IMAGES(FloydSteinberg, arg.Get()); return true; } bool convert_dither_riemersma (const Argument& arg) { FOR_ALL_IMAGES(Riemersma, arg.Get()); return true; } bool convert_edge (const Argument& arg) { matrix_type matrix[] = { -1.0, 0.0, 1.0, -2.0, 0.0, 2.0, -1.0, 0.0, -1.0 }; FOR_ALL_IMAGES(convolution_matrix, matrix, 3, 3, (matrix_type)3.0); return true; } bool convert_resolution (const Argument& arg) { int xres, yres, n; // parse // TODO: pretty C++ parser if ((n = sscanf(arg.Get().c_str(), "%dx%d", &xres, &yres))) { if (n < 2) yres = xres; for (images_iterator it = images.begin(); it != images.end(); ++it) (*it)->setResolution(xres, yres); return true; } std::cerr << "Resolution '" << arg.Get() << "' could not be parsed." << std::endl; return false; } bool convert_size (const Argument& arg) { int w, h, n; // parse // TODO: pretty C++ parser if ((n = sscanf(arg.Get().c_str(), "%dx%d", &w, &h)) == 2) { // this is mostly used to set the size for raw data loads // so we need to have at least one (empty) image if (images.empty()) { Image* image = new Image; image->spp = image->bps = 1; images.push_back(image); } for (images_iterator it = images.begin(); it != images.end(); ++it) { (*it)->resize(w, h); } return true; } std::cerr << "Size '" << arg.Get() << "' could not be parsed." << std::endl; return false; } bool convert_crop (const Argument& arg) { int x,y, w, h, n; // parse // TODO: pretty C++ parser if ((n = sscanf(arg.Get().c_str(), "%d,%d,%d,%d", &x, &y, &w, &h)) == 4) { FOR_ALL_IMAGES(crop, x, y, w, h); return true; } std::cerr << "Crop '" << arg.Get() << "' could not be parsed." << std::endl; return false; } bool convert_fast_auto_crop (const Argument& arg) { FOR_ALL_IMAGES(fastAutoCrop); return true; } bool convert_invert (const Argument& arg) { FOR_ALL_IMAGES(invert); return true; } bool convert_deinterlace (const Argument& arg) { // TODO: if this does what I think change to yield 2 images? FOR_ALL_IMAGES(deinterlace); return true; } /* #RGB (R,G,B are hex numbers, 4 bits each) #RRGGBB (8 bits each) #RRRGGGBBB (12 bits each) #RRRRGGGGBBBB (16 bits each) TODO: #RGBA (4 bits each) #RRGGBBOO (8 bits each) #RRRGGGBBBOOO (12 bits each) #RRRRGGGGBBBBOOOO (16 bits each) X11, SVG standard colors name (identify -list color to see names) rgb(r,g,b) 0-255 for each of rgb rgba(r,g,b,a) 0-255 for each of rgb and 0-1 for alpha cmyk(c,m,y,k) 0-255 for each of cmyk cmyka(c,m,y,k,a) 0-255 for each of cmyk and 0-1 for alpha hsl(0, 100%, 50%) } */ static struct { const char* name; const char* color; } named_colors[] = { // CSS2 { "white", "#ffffff" }, { "yellow", "#ffff00" }, { "orange", "#ffA500" }, { "red", "#ff0000" }, { "fuchsia", "#ff00ff" }, { "silver", "#c0c0c0" }, { "gray", "#808080" }, { "olive", "#808000" }, { "purple", "#800080" }, { "maroon", "#800000" }, { "aqua", "#00ffff" }, { "lime", "#00ff00" }, { "teal", "#008080" }, { "green", "#008000" }, { "blue", "#0000ff" }, { "navy", "#000080" }, { "black", "#000000" }, // TODO: HTML, X11, SVG; ... }; static bool parse_color (Image::iterator& it, const char* color) { unsigned int r, g, b; int strl = strlen(color); if (strl == 4 && sscanf(color, "#%1x%1x%1x", &r, &g, &b) == 3) { double _r, _g, _b; _r = 1. / 0xf * r; _g = 1. / 0xf * g; _b = 1. / 0xf * b; it.setRGB(_r, _g, _b); return true; } else if (strl == 7 && sscanf(color, "#%2x%2x%2x", &r, &g, &b) == 3) { double _r, _g, _b; _r = 1. / 0xff * r; _g = 1. / 0xff * g; _b = 1. / 0xff * b; it.setRGB(_r, _g, _b); return true; } else if (strl == 10 && sscanf(color, "#%3x%3x%3x", &r, &g, &b) == 3) { double _r, _g, _b; _r = 1. / 0xfff * r; _g = 1. / 0xfff * g; _b = 1. / 0xfff * b; it.setRGB(_r, _g, _b); return true; } else if (strl == 13 && sscanf(color, "#%4x%4x%4x", &r, &g, &b) == 3) { double _r, _g, _b; _r = 1. / 0xffff * r; _g = 1. / 0xffff * g; _b = 1. / 0xffff * b; it.setRGB(_r, _g, _b); return true; } else for (unsigned i = 0; i < ARRAY_SIZE(named_colors); ++i) { if (strcmp(color, named_colors[i].name) == 0) return parse_color(it, named_colors[i].color); } return false; } bool convert_background (const Argument& arg) { if (!parse_color(background_color, arg.Get().c_str())) { std::cerr << "Error parsing color: '" << arg.Get() << "'" << std::endl; return false; } return true; } bool convert_foreground (const Argument& arg) { if (!parse_color(foreground_color, arg.Get().c_str())) { std::cerr << "Error parsing color: '" << arg.Get() << "'" << std::endl; return false; } return true; } bool convert_line (const Argument& arg) { float x1, y1, x2, y2; if (sscanf(arg.Get().c_str(), "%f,%f,%f,%f", &x1, &y1, &x2, &y2) == 4) { Path path; path.moveTo (x1, y1); path.addLineTo (x2, y2); double r = 0, g = 0, b = 0; foreground_color.getRGB (r, g, b); path.setFillColor (r, g, b); if (arg_stroke_width.Size()) path.setLineWidth(arg_stroke_width.Get()); FOR_ALL_IMAGES(path.draw); return true; } std::cerr << "Error parsing line: '" << arg.Get() << "'" << std::endl; return false; } #if WITHFREETYPE == 1 bool convert_text (const Argument& arg) { double x = 0, y = 0, xoff = 0, yoff = 0, height = 0; char* text = 0; char* gravity = 0; if (sscanf(arg.Get().c_str(), "%lf,%lf,%lf,%a[^\r]", &x, &y, &height, &text) != 4) if (sscanf(arg.Get().c_str(), "%a[^,],%lf,%a[^\r]", &gravity, &height, &text) != 3) { std::cerr << "Error parsing text: '" << arg.Get() << "'" << std::endl; return false; } // parse gravity offset if (gravity) { char* gravity2 = 0; if (sscanf(gravity, "%a[^+-]%lf%lf", &gravity2, &xoff, &yoff) == 3) { free(gravity); gravity = gravity2; } } for (images_iterator it = images.begin(); it != images.end(); ++it) { Path path; path.moveTo (0, 0); double r = 0, g = 0, b = 0; foreground_color.getRGB (r, g, b); path.setFillColor (r, g, b); const double strokeWidth = arg_stroke_width.Size() ? arg_stroke_width.Get() : 0; if (strokeWidth > 0) path.setLineWidth(strokeWidth); agg::trans_affine mtx; mtx *= agg::trans_affine_rotation(arg_text_rotation.Size() ? arg_text_rotation.Get() / 180 * M_PI : 0); if (gravity) { std::string c(gravity); std::transform (c.begin(), c.end(), c.begin(), tolower); enum align {A, B, C}; align x_align = A, y_align = A; if (c == "northwest") { x_align = A; y_align = A; } else if (c == "north" || c == "top") { x_align = B; y_align = A; } else if (c == "northeast") { x_align = C; y_align = A; } else if (c == "west" || c == "left") { x_align = A; y_align = B; } else if (c == "center") { x_align = B; y_align = B; } else if (c == "east" || c == "right") { x_align = C; y_align = B; } else if (c == "southwest") { x_align = A; y_align = C; } else if (c == "south" || c == "bottom") { x_align = B; y_align = C; } else if (c == "southeast") { x_align = C; y_align = C; } else { std::cerr << "Unknown gravity: " << gravity << std::endl; return false; } double w = 0, h = 0, dx = 0, dy = 0; path.drawText(**it, text, height, arg_font.Size() ? arg_font.Get().c_str() : NULL, mtx, strokeWidth > 0 ? Path::fill_none : Path::fill_non_zero, &w, &h, &dx, &dy); switch (x_align) { case A: x = 0; break; case B: x = ((*it)->w - w) / 2; break; case C: x = (*it)->w - w; break; } switch (y_align) { case A: y = 0; break; case B: y = ((*it)->h - h) / 2; break; case C: y = (*it)->h - h; break; } mtx *= agg::trans_affine_translation(dx + x + xoff, dy + y + yoff); path.drawText(**it, text, height, arg_font.Size() ? arg_font.Get().c_str() : NULL, mtx, strokeWidth > 0 ? Path::fill_none : Path::fill_non_zero); } else { mtx *= agg::trans_affine_translation(x + xoff, y + yoff); path.drawText(**it, text, height, arg_font.Size() ? arg_font.Get().c_str() : NULL, mtx, strokeWidth > 0 ? Path::fill_none : Path::fill_non_zero); } } free(text); free(gravity); return true; } #endif int main (int argc, char* argv[]) { ArgumentList arglist; background_color.type = Image::RGB8; background_color.setL (255); foreground_color.type = Image::RGB8; foreground_color.setL (0); // setup the argument list Argument arg_help ("h", "help", "display this help text and exit"); arglist.Add (&arg_help); Argument arg_input ("i", "input", "input file or '-' for stdin, optionally prefixed with format:" "\n\t\te.g: jpg:- or raw:rgb8-dump", 0, std::numeric_limits::max(), true, true); arg_input.Bind (convert_input); arglist.Add (&arg_input); Argument arg_output ("o", "output", "output file or '-' for stdout, optinally prefix with format:" "\n\t\te.g. jpg:- or raw:rgb8-dump", 0, std::numeric_limits::max(), true, true); arg_output.Bind (convert_output); arglist.Add (&arg_output); // TODO: more args for the stack? Argument arg_append ("a", "append", "append file or '-' for stdin, optionally prefixed with format:" "\n\t\te.g: jpg:- or raw:rgb8-dump", 0, 1, true, true); arg_append.Bind (convert_append); arglist.Add (&arg_append); // global arglist.Add (&arg_quality); arglist.Add (&arg_compression); arglist.Add (&arg_decompression); Argument arg_split ("", "split", "filenames to save the images split in Y-direction into n parts", 0, 1, true, true); arg_split.Bind (convert_split); arglist.Add (&arg_split); Argument arg_colorspace ("", "colorspace", "convert image colorspace (BW, BILEVEL, GRAY, GRAY1, GRAY2, GRAY4,\n\t\tRGB, YUV, CYMK)", 0, 1, true, true); arg_colorspace.Bind (convert_colorspace); arglist.Add (&arg_colorspace); Argument arg_normalize ("", "normalize", "transform the image to span the full color range", 0, 0, true, true); arg_normalize.Bind (convert_normalize); arglist.Add (&arg_normalize); Argument arg_brightness ("", "brightness", "change image brightness", 0.0, 0, 1, true, true); arg_brightness.Bind (convert_brightness); arglist.Add (&arg_brightness); Argument arg_contrast ("", "contrast", "change image contrast", 0.0, 0, 1, true, true); arg_contrast.Bind (convert_contrast); arglist.Add (&arg_contrast); Argument arg_gamma ("", "gamma", "change image gamma", 0.0, 0, 1, true, true); arg_gamma.Bind (convert_gamma); arglist.Add (&arg_gamma); Argument arg_hue ("", "hue", "change image hue", 0.0, 0, 1, true, true); arg_hue.Bind (convert_hue); arglist.Add (&arg_hue); Argument arg_saturation ("", "saturation", "change image saturation", 0.0, 0, 1, true, true); arg_saturation.Bind (convert_saturation); arglist.Add (&arg_saturation); Argument arg_lightness ("", "lightness", "change image lightness", 0.0, 0, 1, true, true); arg_lightness.Bind (convert_lightness); arglist.Add (&arg_lightness); Argument arg_blur ("", "blur", "gaussian blur", 0.0, 0, 1, true, true); arg_blur.Bind (convert_blur); arglist.Add (&arg_blur); Argument arg_scale ("", "scale", "scale image data using a method suitable for specified factor", 0.0, 0, 1, true, true); arg_scale.Bind (convert_scale); arglist.Add (&arg_scale); Argument arg_nearest_scale ("", "nearest-scale", "scale image data to nearest neighbour", 0.0, 0, 1, true, true); arg_nearest_scale.Bind (convert_nearest_scale); arglist.Add (&arg_nearest_scale); Argument arg_bilinear_scale ("", "bilinear-scale", "scale image data with bi-linear filter", 0.0, 0, 1, true, true); arg_bilinear_scale.Bind (convert_bilinear_scale); arglist.Add (&arg_bilinear_scale); Argument arg_bicubic_scale ("", "bicubic-scale", "scale image data with bi-cubic filter", 0.0, 0, 1, true, true); arg_bicubic_scale.Bind (convert_bicubic_scale); arglist.Add (&arg_bicubic_scale); Argument arg_ddt_scale ("", "ddt-scale", "scale image data with data dependent triangulation", 0.0, 0, 1, true, true); arg_ddt_scale.Bind (convert_ddt_scale); arglist.Add (&arg_ddt_scale); Argument arg_box_scale ("", "box-scale", "(down)scale image data with box filter", 0.0, 0, 1, true, true); arg_box_scale.Bind (convert_box_scale); arglist.Add (&arg_box_scale); Argument arg_thumbnail_scale ("", "thumbnail", "quick and dirty down-scale for a thumbnail", 0.0, 0, 1, true, true); arg_thumbnail_scale.Bind (convert_thumbnail_scale); arglist.Add (&arg_thumbnail_scale); Argument arg_rotate ("", "rotate", "rotation angle", 0, 1, true, true); arg_rotate.Bind (convert_rotate); arglist.Add (&arg_rotate); Argument arg_convolve ("", "convolve", "convolution matrix", 0, 9999, true, true); arg_convolve.Bind (convert_convolve); arglist.Add (&arg_convolve); Argument arg_flip ("", "flip", "flip the image vertically", 0, 0, true, true); arg_flip.Bind (convert_flip); arglist.Add (&arg_flip); Argument arg_flop ("", "flop", "flip the image horizontally", 0, 0, true, true); arg_flop.Bind (convert_flop); arglist.Add (&arg_flop); Argument arg_floyd ("", "floyd-steinberg", "Floyd Steinberg dithering using n shades", 0, 1, true, true); arg_floyd.Bind (convert_dither_floyd_steinberg); arglist.Add (&arg_floyd); Argument arg_riemersma ("", "riemersma", "Riemersma dithering using n shades", 0, 1, true, true); arg_riemersma.Bind (convert_dither_riemersma); arglist.Add (&arg_riemersma); Argument arg_edge ("", "edge", "edge detect filter", 0, 0, true, true); arg_edge.Bind (convert_edge); arglist.Add (&arg_edge); Argument arg_resolution ("", "resolution", "set meta data resolution in dpi to x[xy] e.g. 200 or 200x400", 0, 1, true, true); arg_resolution.Bind (convert_resolution); arglist.Add (&arg_resolution); Argument arg_size ("", "size", "width and height of raw images whose dimensions are unknown", 0, 1, true, true); arg_size.Bind (convert_size); arglist.Add (&arg_size); Argument arg_crop ("", "crop", "crop an area out of an image: x,y,w,h", 0, 1, true, true); arg_crop.Bind (convert_crop); arglist.Add (&arg_crop); Argument arg_fast_auto_crop ("", "fast-auto-crop", "fast auto crop", 0, 0, true, true); arg_fast_auto_crop.Bind (convert_fast_auto_crop); arglist.Add (&arg_fast_auto_crop); Argument arg_invert ("", "negate", "negates the image", 0, 0, true, true); arg_invert.Bind (convert_invert); arglist.Add (&arg_invert); Argument arg_deinterlace ("", "deinterlace", "shuffle every 2nd line", 0, 0, true, true); arg_deinterlace.Bind (convert_deinterlace); arglist.Add (&arg_deinterlace); Argument arg_background ("", "background", "background color used for operations", 0, 1, true, true); arg_background.Bind (convert_background); arglist.Add (&arg_background); Argument arg_foreground ("", "foreground", "foreground color used for operations", 0, 1, true, true); arg_foreground.Bind (convert_foreground); arglist.Add (&arg_foreground); arglist.Add (&arg_stroke_width); Argument arg_line ("", "line", "draw a line: x1, y1, x2, y2", 0, 1, true, true); arg_line.Bind (convert_line); arglist.Add (&arg_line); #if WITHFREETYPE == 1 Argument arg_text ("", "text", "draw text: x1, y1, height, text", 0, 1, true, true); arg_text.Bind (convert_text); arglist.Add (&arg_text); arglist.Add (&arg_font); arglist.Add (&arg_text_rotation); #endif // parse the specified argument list - and maybe output the Usage if (!arglist.Read (argc, argv)) { freeImages(); return 1; } // print the usage if no argument was given or help requested if (argc == 1 || arg_help.Get() == true) { std::cerr << "ExactImage converter, version " VERSION << std::endl << "Copyright (C) 2005 - 2014 René Rebe, ExactCODE" << std::endl << "Copyright (C) 2005, 2008 Archivista" << std::endl << "Usage:" << std::endl; arglist.Usage (std::cerr); freeImages(); return 1; } // stack: insert, append, delete, swap, clone // all is done inside the argument callback functions freeImages(); return 0; } exact-image-0.9.1/frontends/e2mtiff.cc0000644000076400007640000000551611352355072016240 0ustar renerene/* * The ExactImage library's any to multi-page TIFF converted * Copyright (C) 2008 - 2010 René Rebe * * 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 #include #include #include "ArgumentList.hh" #include "Codecs.hh" using namespace Utility; ArgumentList arglist(true); // enable residual gathering bool usage(const Argument& arg) { std::cerr << "any to multi-page TIFF convert" << std::endl << " - Copyright 2008-2010 by René Rebe, ExactCODE" << std::endl << "Usage:" << std::endl; arglist.Usage(std::cerr); std::cerr << " ...\n\t\tinput file(s)" << std::endl; exit(1); } int main (int argc, char* argv[]) { // setup the argument list Argument arg_help ("h", "help", "display this help text and exit"); arg_help.Bind (usage); arglist.Add (&arg_help); Argument arg_output ("o", "output", "output file", 1, 1, true, true); arglist.Add (&arg_output); // parse the specified argument list - and maybe output the Usage if (!arglist.Read(argc, argv) || arglist.Residuals().empty()) { if (arglist.Residuals().empty()) std::cerr << "Error: No arguments as input!" << std::endl; usage(arg_help); } int errors = 0; int tiff_page = 1; std::fstream stream(arg_output.Get().c_str(), std::ios::in | std::ios::out | std::ios::trunc); ImageCodec* codec = ImageCodec::MultiWrite(&stream, "tiff", ImageCodec::getExtension(arg_output.Get())); if(!codec) { std::cerr << "Error writing file: " << arg_output.Get() << std::endl; return 1; } Image image; const std::vector& filenames = arglist.Residuals(); for (std::vector::const_iterator file = filenames.begin(); file != filenames.end (); ++file) { for (int i = 0, n = 1; i < n; ++i) { int ret = ImageCodec::Read (*file, image, "", i); if (ret == 0) { std::cerr << "Error reading " << *file << std::endl; ++errors; break; } else { if (i == 0) n = ret; // std::cerr << "adding [" << tiff_page << "] " << *file << std::endl; codec->Write (image, 75, ""/*compression*/, tiff_page++); } } } delete(codec); codec = 0; return errors; } exact-image-0.9.1/frontends/hocr2pdf.cc0000644000076400007640000001064712406515434016415 0ustar renerene/* * The ExactImage library's hOCR to PDF command line frontend * Copyright (C) 2008 - 2014 René Rebe, ExactCODE GmbH Germany * Copyright (C) 2008 Archivista * * 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 #include #include #include #include #include #include #include "ArgumentList.hh" #include "config.h" #include "Codecs.hh" #include "pdf.hh" #include "hocr.hh" using namespace Utility; int main(int argc, char* argv[]) { ArgumentList arglist(false); // setup the argument list Argument arg_help("h", "help", "display this help text and exit"); arglist.Add(&arg_help); Argument arg_input("i", "input", "input image filename", 1, 1, true, true); arglist.Add(&arg_input); Argument arg_output("o", "output", "output PDF filename", 1, 1, true, true); arglist.Add(&arg_output); Argument arg_resolution("r", "resolution", "resolution overwrite", 0, 1, true, true); arglist.Add(&arg_resolution); Argument arg_no_image("n", "no-image", "do not place the image over the text", 0, 0, true, true); arglist.Add(&arg_no_image); Argument arg_sloppy_text("s", "sloppy-text", "sloppily place text, group words, do not draw single glyphs", 0, 0, true, true); arglist.Add(&arg_sloppy_text); Argument arg_text("t", "text", "extract text, including trying to remove hyphens", 0, 1, true, true); arglist.Add(&arg_text); Argument arg_quality ("", "quality", "quality setting used for writing compressed images\n\t\t" "integer range 0-100, the default is 75", 0, 1, true, true); arglist.Add(&arg_quality); Argument arg_compression ("", "compress", "compression method for writing images e.g. ascii85, hex, flate,\n" "\t\tjpeg, jpeg2000 ... auto default based on bit-depth", 0, 1, true, true); arglist.Add(&arg_compression); // parse the specified argument list - and maybe output the Usage if (!arglist.Read(argc, argv) || arg_help.Get() == true) { std::cerr << "hOCR to PDF converter, version " VERSION << std::endl << "Copyright (C) 2008-2014 René Rebe, ExactCODE" << std::endl << "Copyright (C) 2008 Archivista" << std::endl << "Usage:" << std::endl; arglist.Usage(std::cerr); return 1; } // load the image, if specified and possible Image image; image.w = image.h = 0; if (arg_input.Size()) { if (!ImageCodec::Read(arg_input.Get(), image)) { std::cerr << "Error reading input file." << std::endl; return 1; } } if (arg_resolution.Size()) image.setResolution(arg_resolution.Get(), arg_resolution.Get()); if (image.resolutionX() <= 0 || image.resolutionY() <= 0) { std::cerr << "Warning: Image x/y resolution not set, defaulting to: " << 300 << std::endl; image.setResolution(300, 300); } unsigned int res = image.resolutionX(); bool sloppy = arg_sloppy_text.Get(); std::ofstream* txtStream = 0; if (arg_text.Size()) { txtStream = new std::ofstream(arg_text.Get().c_str()); } std::ofstream s(arg_output.Get().c_str()); PDFCodec* pdfContext = new PDFCodec(&s); pdfContext->beginPage(72. * image.w / res, 72. * image.h / res); pdfContext->setFillColor(0, 0, 0); hocr2pdf(std::cin, pdfContext, res, sloppy, txtStream); int quality = 75; if (arg_quality.Size()) quality = arg_quality.Get(); std::string compression = ""; if (arg_compression.Size()) compression = arg_compression.Get(); if (!arg_no_image.Get()) pdfContext->showImage(image, 0, 0, 72. * image.w / res, 72. * image.h / res, quality, compression); delete pdfContext; if (txtStream) { txtStream->close(); delete txtStream; } return 0; } exact-image-0.9.1/codecs/0000755000076400007640000000000012467664251013636 5ustar renereneexact-image-0.9.1/codecs/png.cc0000644000076400007640000002304111343547354014725 0ustar renerene/* * Copyright (C) 2006 - 2009 René Rebe * * 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 #include #include #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& decompres) { { // 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; 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, png_infopp_NULL, png_infopp_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, png_infopp_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, int_p_NULL, int_p_NULL); image.w = width; image.h = height; image.bps = bit_depth; image.spp = info_ptr->channels; 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); /* 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 (info_ptr->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, png_bytepp_NULL, 1); } /* clean up after the read, and free any memory allocated - REQUIRED */ png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_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, png_infopp_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); 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); int stride = png_get_rowbytes (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); png_bytep row_pointers[1]; /* The other way to write images */ int number_passes = 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; exact-image-0.9.1/codecs/tga.cc0000644000076400007640000001261612160553024014707 0ustar renerene/* * C++ PCX library. * Copyright (C) 2008 - 2009 René Rebe, ExactCODE GmbH Germany * * 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 #include "tga.hh" #include "Colorspace.hh" #include #include #include #include using Exact::EndianessConverter; using Exact::LittleEndianTraits; /* Header Footer */ typedef struct { uint8_t IDLength; uint8_t ColorMapType; uint8_t ImageType; EndianessConverter ColorMapIndex; EndianessConverter ColorMapLength; uint8_t ColorMapEntrySize; EndianessConverter ImageXOrigin; EndianessConverter ImageYOrigin; EndianessConverter ImageWidth; EndianessConverter ImageHeight; uint8_t ImageDepth; uint8_t ImageDescriptor; } __attribute__((packed)) TGAHeader; typedef struct { EndianessConverter ExtensionOffset; EndianessConverter DeveloperOffset; char Signature[16]; uint8_t ReservedCharacter; uint8_t ZeroTerminator; } __attribute__((packed)) TGAFooter; int TGACodec::readImage(std::istream* stream, Image& image, const std::string& decompres) { bool rle = false; /* if (!stream->seekg(26, std::ios::end)) return false; TGAFooter footer; if (!stream->read((char*)&footer, sizeof(footer))) return false; */ TGAHeader header; if (!stream->read((char*)&header, sizeof(header))) { goto no_tga; } // TODO: differentiate between "maybe be old TGA" and definetly // should be new-style TGA with footer switch (header.ImageDepth) { case 1: case 8: case 16: case 24: case 32: break; default: goto no_tga; }; // TODO: harden checks for "maybe TGA", ... switch (header.ImageType) { case 9: // RLE, color mapped case 10: // RLE, true color rle = true; case 1: // color mapped case 2: // true color image.spp = 3; break; case 11: // RLE, b&w rle = true; case 3: // b&w image.spp = 1; break; default: goto no_tga; } std::cerr << "TGA: " << (int)header.IDLength << ", " << (int)header.ImageType << ", " << (int)header.ImageDepth << ", " << (int)header.ColorMapType << ", " << header.ImageWidth << ", " << header.ImageHeight << ", " << header.ImageDescriptor << std::endl; if (header.ImageDepth == 32) image.spp = 4; image.bps = header.ImageDepth / image.spp; image.setResolution(0, 0); // TODO image.resize(header.ImageWidth, header.ImageHeight); if (header.ColorMapType == 1) { // seek to color map stream->seekg(sizeof(header) + header.IDLength); } // seek to image data stream->seekg(sizeof(header) + header.IDLength); if (!rle) { // TODO: interpret flip/flop bits stream->read((char*)image.getRawData(), image.stride() * image.h); } else { const int bytes = header.ImageDepth / 8; uint8_t* data = image.getRawData(); uint8_t payload[4]; // TODO: I got one RLE which shows up RGB reversed?! for (int i = 0; i < image.stride() * image.h;) { uint8_t t = stream->get(); uint8_t n = (t & 0x7f) + 1; if (t & 0x80) // RLE { stream->read((char*)payload, bytes); while (n-- > 0 && i < image.stride() * image.h) for (int j = 0; j < bytes; ++j) data[i++] = payload[j]; } else // RAW { stream->read((char*)data + i, n * bytes); i += n * bytes; } } } { unsigned ori = (header.ImageDescriptor >> 4) & 2; if (ori != 2) std::cerr << "unimplemented TGA orientation: " << ori << std::endl; } return true; no_tga: stream->seekg(0); return false; } bool TGACodec::writeImage(std::ostream* stream, Image& image, int quality, const std::string& compress) { TGAHeader header; header.IDLength = 0; header.ColorMapType = 0; header.ImageType = image.spp == 1 ? 3 /*Truecolor*/ : 2/*bw*/; header.ColorMapIndex = 0; header.ColorMapLength = 0; header.ColorMapEntrySize = 0; header.ImageXOrigin = 0; header.ImageYOrigin = 0; header.ImageWidth = image.width(); header.ImageHeight = image.height(); header.ImageDepth = image.spp * image.bps; header.ImageDescriptor = 0x20; // top-left stream->write((char*)&header, sizeof(header)); stream->write((char*)image.getRawData(), image.stride() * image.height()); TGAFooter footer; footer.ExtensionOffset = 0; footer.DeveloperOffset = 0; memcpy(footer.Signature, "TRUEVISION-XFILE", sizeof(footer.Signature)); footer.ReservedCharacter = '.'; footer.ZeroTerminator = 0; stream->write((char*)&footer, sizeof(footer)); return true; } TGACodec tga_codec; exact-image-0.9.1/codecs/dcraw.cc0000644000076400007640000002071712231502150015226 0ustar renerene/* * Copyright (C) 2006 - 2013 René Rebe * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for wrapped printf/scanf #include #include "dcraw.hh" #include "rotate.hh" /* Now this is an very crude macro++ hackery to convert the C FILE* API to to C++ iostream for our codec, to be able to not only read from regular files. -ReneR */ static inline int wrapped_fread (std::iostream* stream, char* mem, int n) { return stream->read (mem, n) ? n : 0; } static inline int wrapped_fwrite (std::iostream* stream, char* mem, int n) { stream->write (mem,n); return stream->good() ? n : 0; } static inline int wrapped_fprintf (std::ostream* stream, const char* fmt, ...) { int size = 96; // probably less than a "terminal line" char *p, *np; va_list ap; if ((p = (char*)malloc(size)) == NULL) return -1; while (1) { // try to print into the allocated space va_start(ap, fmt); int n = vsnprintf(p, size, fmt, ap); va_end(ap); // if that worked, print the string if (n > -1 && n < size) { stream->write(p, size); free(p); return n; } // else try again with more space, ... if (n > -1) // new libc's size = n + 1; // precisely what is needed else // unknown amount required, try twice the previous size size *= 2; if ((np = (char*)realloc(p, size)) == NULL) { free(p); return -1; } else { p = np; } } } static inline int wrapped_fscanf (std::istream* stream, const char* buf, ...) { std::cerr << "TODO: " << __PRETTY_FUNCTION__ << std::endl; // TODO: so far only %d and %f are used return 0; } #define FILE std::iostream #undef stderr #define stderr (&std::cerr) #undef SEEK_SET #undef SEEK_CUR #undef SEEK_END #define SEEK_SET std::ios::beg #define SEEK_CUR std::ios::cur #define SEEK_END std::ios::end #define fread(mem,n,m,stream) wrapped_fread (stream, (char*)mem,n*m) #define fwrite(mem,n,m,stream) wrapped_fwrite (stream, (char*)mem,n*m) #define fprintf wrapped_fprintf #define fscanf wrapped_fscanf #define fgetc(stream) stream->get () #undef getc #define getc(stream) stream->get () #define fgets(mem,n,stream) stream->get ((char*)mem, n) #undef putc #define putc(c,stream) stream->put (c) #define fputc(c,stream) stream->put (c) #define tmpfile new std::stringstream #define fopen(name, mode) new std::fstream(name) #define fclose(stream) delete (stream); #define feof(stream) stream->eof() #define ftello(stream) ((off_t)stream->tellg()) #define fseek(stream,pos,kind) (stream->clear(), stream->seekg(pos, kind)) #define ftell(stream) (int) stream->tellg () #define fseeko(stream,pos,kind) (stream->clear(), stream->seekg(pos, kind)) // now include the original dcraw source with our translation macros in-place #include "dcraw.h" int DCRAWCodec::readImage (std::istream* stream, Image& im, const std::string& decompress) { // dcraw namespace, to not tinker with the missign static linkage of the // upstream C source on every update using namespace dcraw; #ifndef NO_LCMS char *cam_profile = NULL, *out_profile = NULL; #endif std::iostream ios (stream->rdbuf()); ifp = &ios; // dcraw::main() flip = 0; int use_fuji_rotate=1, quality, i; #ifndef NO_LCMS char *cam_profile=0, *out_profile=0; #endif if (use_camera_matrix < 0) use_camera_matrix = use_camera_wb; // TODO: cleanup on failure if (setjmp (failure)) return false; identify(); if (!is_raw) return false; // TODO: lowercase and find in comma seperated list if (decompress == "thumb") { if (!thumb_offset) { std::cerr << "has no thumbnail." << std::endl; } else if (thumb_load_raw) { load_raw = thumb_load_raw; data_offset = thumb_offset; width = thumb_width; height = thumb_height; filters = 0; // TODO: test this case } else { fseek (ifp, thumb_offset, SEEK_SET); write_fun = write_thumb; std::stringstream thumbnail; ofp = &thumbnail; (*write_fun)(); // we can have a jpeg or pnm dump here bool ret = ImageCodec::Read(&thumbnail, im, "", decompress); if (ret) { if (meta_data) free (meta_data); if (oprof) free (oprof); if (image) free (image); return true; } // else: there was an error, we have no thumbnail, so decode regular: // TODO: test } } if (load_raw == &CLASS kodak_ycbcr_load_raw) { height += height & 1; width += width & 1; } shrink = filters && (half_size || threshold || aber[0] != 1 || aber[2] != 1); iheight = (height + shrink) >> shrink; iwidth = (width + shrink) >> shrink; if (use_camera_matrix && cmatrix[0][0] > 0.25) { memcpy (rgb_cam, cmatrix, sizeof cmatrix); raw_color = 0; } if (meta_length) { meta_data = (char *) malloc (meta_length); merror (meta_data, "main()"); } if (filters || colors == 1) { raw_image = (ushort *) calloc ((raw_height+7), raw_width*2); merror (raw_image, "main()"); } else { image = (ushort (*)[4]) calloc (iheight, iwidth*sizeof *image); merror (image, "main()"); } if (shot_select >= is_raw) fprintf (stderr,_("%s: \"-s %d\" requests a nonexistent image!\n"), ifname, shot_select); fseeko (ifp, data_offset, SEEK_SET); (*load_raw)(); if (document_mode == 3) { top_margin = left_margin = fuji_width = 0; height = raw_height; width = raw_width; } iheight = (height + shrink) >> shrink; iwidth = (width + shrink) >> shrink; if (raw_image) { image = (ushort (*)[4]) calloc (iheight, iwidth*sizeof *image); merror (image, "main()"); crop_masked_pixels(); free (raw_image); } if (zero_is_bad) remove_zeroes(); // bad_pixels(); quality = 2 + !fuji_width; if (is_foveon) { if (document_mode || load_raw == &CLASS foveon_dp_load_raw) { for (i=0; i < height*width*4; i++) if ((short) image[0][i] < 0) image[0][i] = 0; } else foveon_interpolate(); } else if (document_mode < 2) scale_colors(); pre_interpolate(); if (filters && !document_mode) { if (quality == 0) lin_interpolate(); else if (quality == 1 || colors > 3) vng_interpolate(); else if (quality == 2 && filters > 1000) ppg_interpolate(); else if (filters == 9) xtrans_interpolate (quality*2-3); else ahd_interpolate(); } if (mix_green) for (colors=3, i=0; i < height*width; i++) image[i][1] = (image[i][1] + image[i][3]) >> 1; if (!is_foveon && colors == 3) median_filter(); if (!is_foveon && highlight == 2) blend_highlights(); if (!is_foveon && highlight > 2) recover_highlights(); if (use_fuji_rotate) fuji_rotate(); #ifndef NO_LCMS if (cam_profile) apply_profile (cam_profile, out_profile); #endif convert_to_rgb(); if (use_fuji_rotate) stretch(); convert_to_rgb(); im.bps = 16; im.spp = 3; im.resize(width, height); // the non-linear gamma by default uint16_t lut [0x10000]; const double gamma = 2.2; const double one_over_gamma = 1. / gamma; for (int i = 0; i < 0x10000; ++i) lut [i] = pow( (double) i / 0xFFFF, one_over_gamma) * 0xFFFF; uint16_t* ptr = (uint16_t*) im.getRawData(); for (int row = 0; row < height; ++row) for (int col = 0; col < width; ++col) for (int c = 0; c < colors; ++c) *ptr++ = lut[ image[row*width+col][c] ]; if (meta_data) free (meta_data); if (oprof) free (oprof); if (image) free (image); // compensate for Exif encoded orientation exif_rotate(im, flip); return true; } bool DCRAWCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { return false; } DCRAWCodec dcraw_loader; exact-image-0.9.1/codecs/svg.cc0000644000076400007640000000553611352361372014743 0ustar renerene/* * Copyright (C) 2008-2010 René Rebe * * 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. /* * Based on the svg_test application window, * Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) */ #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_rasterizer_scanline_aa.h" #include "agg_scanline_p.h" #include "agg_renderer_scanline.h" #include "agg_svg_parser.hh" #include "svg.hh" #include "agg.hh" // EI Agg int SVGCodec::readImage (std::istream* stream, Image& image, const std::string& decompres) { agg::svg::path_renderer m_path; agg::svg::parser p (m_path); if (stream->peek () != '<') return false; try { p.parse(*stream); } catch(agg::svg::exception& e) { std::cerr << e.msg() << std::endl; return false; } double min_x = 0; double min_y = 0; double max_x = 0; double max_y = 0; const double expand = 0; const double gamma = 1; m_path.arrange_orientations(); m_path.bounding_rect (&min_x, &min_y, &max_x, &max_y); // prevent crash for invalid constraints if (min_x > max_x) { double t = max_x; max_x = min_x; min_x = t; } else if (min_x == max_x) max_x += 1; if (min_y > max_y) { double t = max_y; max_y = min_y; min_y = t; } else if (min_y == max_y) max_y += 1; image.bps = 8; image.spp = 3; image.resize ((int)(max_x - min_x), (int)(max_y - min_y)); renderer_exact_image rb (image); typedef agg::renderer_scanline_aa_solid renderer_solid; renderer_solid ren (rb); rb.clear (agg::rgba(1,1,1)); agg::rasterizer_scanline_aa<> ras; agg::scanline_p8 sl; agg::trans_affine mtx; ras.gamma(agg::gamma_power(gamma)); mtx *= agg::trans_affine_translation ((min_x + max_x) * -0.5, (min_y + max_y) * -0.5); //mtx *= agg::trans_affine_scaling (scale); mtx *= agg::trans_affine_translation ((min_x + max_x) * 0.5, (min_y + max_y) * 0.5); m_path.expand(expand); m_path.render(ras, sl, ren, mtx, rb.clip_box(), 1.0); //std::cerr << "Vertices=" << m_path.vertex_count() << " Time=" << tm << " ms" std::endl; return true; } bool SVGCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { return false; } SVGCodec svg_loader; exact-image-0.9.1/codecs/Codecs.cc0000644000076400007640000001720111737001550015330 0ustar renerene/* * Copyright (C) 2006 - 2010 René Rebe * * 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 "Codecs.hh" #include // tolower #include #include std::list* ImageCodec::loader = 0; ImageCodec::ImageCodec () : _image (0) { } ImageCodec::ImageCodec (Image* __image) : _image (__image) { } ImageCodec::~ImageCodec () { // if not freestanding if (!_image) unregisterCodec (this); } std::string ImageCodec::getExtension (const std::string& filename) { // parse the filename extension std::string::size_type idx_ext = filename.rfind ('.'); if (idx_ext && idx_ext != std::string::npos) return filename.substr (idx_ext + 1); else return ""; } std::string ImageCodec::getCodec (std::string& filename) { // parse the codec spec, prefixed to the filename, e.g. jpg:, tif:, raw:, ... std::string::size_type idx_colon = filename.find (':'); // unfortunately, Windows has this silly concept of drive "letters", // just limit the codec spec to anything longer than a single char #ifdef _WIN32 if (idx_colon && idx_colon < 2) idx_colon = filename.find (':', idx_colon + 1); #endif if (idx_colon && idx_colon != std::string::npos) { std::string codec = filename.substr (0, idx_colon); filename.erase (0, idx_colon+1); return codec; } else return ""; } // NEW API int ImageCodec::Read (std::istream* stream, Image& image, std::string codec, const std::string& decompress, int index) { std::transform (codec.begin(), codec.end(), codec.begin(), tolower); std::list::iterator it; if (loader) for (it = loader->begin(); it != loader->end(); ++it) { if (codec.empty()) // try via magic { // use primary entry to only try each codec once if (it->primary_entry && !it->via_codec_only) { int res = it->loader->readImage (stream, image, decompress, index); if (res > 0) { image.setDecoderID (it->loader->getID ()); return res; } // TODO: remove once the codecs are clean stream->clear (); stream->seekg (0); } } else // manual codec spec { if (it->primary_entry && it->ext == codec) { return it->loader->readImage (stream, image, decompress, index); } } } //std::cerr << "No matching codec found." << std::endl; return false; } bool ImageCodec::Write (std::ostream* stream, Image& image, std::string codec, std::string ext, int quality, const std::string& compress) { std::transform (codec.begin(), codec.end(), codec.begin(), tolower); std::transform (ext.begin(), ext.end(), ext.begin(), tolower); std::list::iterator it; if (loader) for (it = loader->begin(); it != loader->end(); ++it) { if (codec.empty()) // match extension { if (it->ext == ext) goto do_write; } else // manual codec spec { if (it->primary_entry && it->ext == codec) { goto do_write; } } } //std::cerr << "No matching codec found." << std::endl; return false; do_write: // reuse attached codec (if any and the image is unmodified) if (image.getCodec() && !image.isModified() && image.getCodec()->getID() == it->loader->getID()) return (image.getCodec()->writeImage (stream, image, quality, compress)); else return (it->loader->writeImage (stream, image, quality, compress)); } ImageCodec* ImageCodec::MultiWrite (std::ostream* stream, std::string codec, std::string ext) { std::transform (codec.begin(), codec.end(), codec.begin(), tolower); std::transform (ext.begin(), ext.end(), ext.begin(), tolower); std::list::iterator it; if (loader) for (it = loader->begin(); it != loader->end(); ++it) { if (codec.empty()) // match extension { if (it->ext == ext) goto do_write; } else // manual codec spec { if (it->primary_entry && it->ext == codec) { goto do_write; } } } //std::cerr << "No matching codec found." << std::endl; return 0; do_write: // TODO: reuse attached codec (if any and the image is unmodified) return it->loader->instanciateForWrite(stream); } // OLD API int ImageCodec::Read (std::string file, Image& image, const std::string& decompress, int index) { std::string codec = getCodec (file); std::istream* s; if (file != "-") s = new std::ifstream (file.c_str(), std::ios::in | std::ios::binary); else s = &std::cin; if (!*s) { //std::cerr << "Can not open file " << file.c_str() << std::endl; return false; } int res = Read (s, image, codec, decompress, index); if (s != &std::cin) delete s; return res; } bool ImageCodec::Write (std::string file, Image& image, int quality, const std::string& compress) { std::string codec = getCodec (file); std::string ext = getExtension (file); std::ostream* s; if (file != "-") s = new std::ofstream (file.c_str(), std::ios::out | std::ios::binary); else s = &std::cout; if (!*s) { //std::cerr << "Can not write file " << file.c_str() << std::endl; return false; } bool res = Write (s, image, codec, ext, quality, compress); if (s != &std::cout) delete s; return res; } void ImageCodec::registerCodec (const char* _ext, ImageCodec* _loader, bool _via_codec_only, bool push_back) { static ImageCodec* last_loader = 0; if (!loader) loader = new std::list; loader_ref ref = {_ext, _loader, _loader != last_loader, _via_codec_only}; if (push_back) loader->push_back(ref); else loader->push_front(ref); last_loader = _loader; } void ImageCodec::unregisterCodec (ImageCodec* _loader) { // sanity check if (!loader) { std::cerr << "unregisterCodec: no codecs, unregister impossible!" << std::endl; } // remove from array std::list::iterator it; for (it = loader->begin(); it != loader->end();) if (it->loader == _loader) it = loader->erase (it); else ++it; if (loader->empty()) { delete loader; loader = 0; } } int ImageCodec::readImage (std::istream* stream, Image& image, const std::string& decompress) { return 0; } int ImageCodec::readImage (std::istream* stream, Image& image, const std::string& decompress, int index) { if (index == 0) return readImage(stream, image, decompress); else return 0; } ImageCodec* ImageCodec::instanciateForWrite (std::ostream* stream) { return 0; } bool ImageCodec::Write (Image& image, int quality, const std::string& compress, int index) { return false; } /*bool*/ void ImageCodec::decodeNow (Image* image) { // intentionally left blank } // optional, return false (unsupported) by default bool ImageCodec::flipX (Image& image) { return false; } bool ImageCodec::flipY (Image& image) { return false; } bool ImageCodec::rotate (Image& image, double ayngle) { return false; } bool ImageCodec::crop (Image& image, unsigned int x, unsigned int y, unsigned int w, unsigned int h) { return false; } bool ImageCodec::toGray (Image& image) { return false; } bool ImageCodec::scale (Image& image, double xscale, double yscale) { return false; } exact-image-0.9.1/codecs/pdf.cc0000644000076400007640000005465711556323062014725 0ustar renerene/* * Copyright (c) 2007 - 2009 Susanne Klaus * Copyright (c) 2008 - 2011 René Rebe * * 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 "pdf.hh" #include "config.h" #ifndef WITHZLIB #define WITHZLIB 1 #endif #include "Encodings.hh" #if WITHLIBJPEG == 1 #include "jpeg.hh" #endif #if WITHJASPER == 1 #include "jpeg2000.hh" #endif #include #include #include #include #include #include /* Concept: * buffer drawing commands as they come * write out images, fonts, and other objects / streams immediately * write out bufferd page content at "endPage" * keep track of object id's and positions to write out at the end In theory we could use any resource name (some PDF writers use R*). However, for the prettification of it we use /F for Fonts and /I for images. We also format the stream quite readable, maybe we later (optionally) do not print most of the formating whitespace. */ /* Object types: * Catalog (Pages, Outlines, ...) * Outlines * Pages (Kids) * Page (Contents) * Font * XObject, Subtype Image * Number et al. (e.g. for stream length) * Resources * Xref * Trailer */ struct PDFObject; // fwd struct PDFPage; // fwd std::ostream& operator<< (std::ostream& s, PDFObject& obj); // fwd // keeps track of objects, writes out xref obj table struct PDFXref { PDFXref() : imageCount(0), fontCount(0) {} void write(std::ostream& s); std::vector objects; uint64_t streamPos; // UUID of font and image references uint32_t imageCount, fontCount; }; std::ostream& operator<< (std::ostream& s, PDFXref& obj) { obj.write(s); return s; } // any PDF object, storing ID, generation and position in stream struct PDFObject { PDFObject(PDFXref& xref) : generation(0), streamPos(0) { xref.objects.push_back(this); id = xref.objects.size(); // after adding, 1-based } virtual ~PDFObject() {} void write(std::ostream& s) { // save position in stream for further reference s << "\n"; streamPos = s.tellp(); s << id << " " << generation << " obj\n"; writeImpl(s); s << "endobj\n"; while (!pendingObjWriteout.empty()) { PDFObject* obj = pendingObjWriteout.front(); s << *obj; pendingObjWriteout.pop_front(); } } virtual void writeImpl(std::ostream& s) = 0; // generate in-file indirect reference spec std::string indirectRef() const { std::stringstream s; s << id << " " << generation << " R"; return s.str(); } // due to C++ design bug, actually I would wante to have them pure virtual, // but then each derived class would need to define them anyway ... :-( virtual std::string resourceName() const { return ""; } virtual std::string resourceType() const { return ""; }; uint64_t getStreamPos() const { return streamPos; } uint32_t id, generation; uint64_t streamPos; std::list pendingObjWriteout; }; std::ostream& operator<< (std::ostream& s, PDFObject& obj) { obj.write(s); return s; } struct PDFNumber : public PDFObject { PDFNumber (PDFXref& xref) : PDFObject(xref) {} virtual void writeImpl(std::ostream& s) { s << value << "\n"; } uint64_t value; }; struct PDFStream : public PDFObject { PDFStream (PDFXref& xref) : PDFObject(xref), number(xref) {} virtual void writeStreamTagsImpl(std::ostream& s) { } virtual void writeStreamImpl(std::ostream& s) { } virtual void writeImpl(std::ostream& s) { s << "<<\n"; writeStreamTagsImpl(s); s << "/Length " << number.indirectRef() << "\n" ">>\n" "stream\n"; uint64_t o1 = s.tellp(), o2; writeStreamImpl(s); s.flush(); o2 = s.tellp(); s << "\nendstream\n"; number.value = o2 - o1; pendingObjWriteout.push_back (&number); } PDFNumber number; }; // TODO: optional and obsolete, hardcode somewhere struct PDFDocumentInfo : public PDFObject { PDFDocumentInfo (PDFXref& xref) : PDFObject(xref) {} virtual void writeImpl(std::ostream& s) { /* TODO: Allow setting: /Title (...) /Author (...) ... */ s << "<<\n" "/Creator (ExactImage " VERSION ")\n" "/Producer (ExactImage " VERSION ")\n" ">>\n"; } }; struct PDFPages : public PDFObject { PDFPages (PDFXref& xref) : PDFObject(xref) {} virtual void writeImpl(std::ostream& s) { // TODO: count needs to be determined by recursively scanning // the whole, potentially nested, page hierarchy s << "<<\n" "/Type /Pages\n" "/Count " << pages.size() << "\n" // TODO "/Kids ["; bool first = true; for (page_iterator it = pages.begin(); it != pages.end(); ++it) { s << (first ? "" : " ") << (*it)->indirectRef(); first = false; } s << "]\n" ">>\n"; } std::vector pages; typedef std::vector::iterator page_iterator; }; struct PDFCatalog : public PDFObject { PDFCatalog (PDFXref& xref, PDFPages& _pages) : PDFObject(xref), pages(_pages) {} virtual void writeImpl(std::ostream& s) { s << "<<\n" "/Type /Catalog\n" "/Pages " << pages.indirectRef() << "\n" ">>\n"; } PDFPages& pages; }; struct PDFFont : public PDFObject { PDFFont(PDFXref& _xref, const std::string& _fontname = "Helvetica") : PDFObject(_xref), fontname(_fontname) { fontID = ++_xref.fontCount; } virtual std::string resourceName() const { std::stringstream s; s << "/F" << fontID; return s.str(); } virtual std::string resourceType() const { return "/Font"; } virtual void writeImpl(std::ostream& s) { // TODO: allow embedding and sub-setting, for now only built-in ones s << "<<\n" "/Type /Font\n" "/Subtype /Type1\n" "/BaseFont /" << fontname << "\n" // as FOP, for now, or: /PDFDocEncoding, /MacRomanEncoding etc. "/Encoding /WinAnsiEncoding\n" ">>\n"; } std::string fontname; uint32_t fontID; }; class Args { public: Args(const std::string& _args) { size_t it1 = 0; while (it1 < _args.size()) { size_t it2 = _args.find_first_of(",;|:", it1); args.insert (_args.substr(it1, it2 - it1)); if (it2 != std::string::npos) it1 = it2 + 1; else it1 = _args.size(); } } bool contains(const std::string& arg) { if (args.find(arg) != args.end()) return true; else return false; } void remove(const std::string& arg) { args.erase(arg); } bool containsAndRemove(const std::string& arg) { if (contains(arg)) { remove(arg); return true; } return false; } std::string str() { std::string ret; std::set::iterator it = args.begin(); if (it != args.end()) ret = *it++; for (; it != args.end(); ++it) { ret += ","; ret += *it; } return ret; } protected: std::set args; }; // so far always an image struct PDFXObject : public PDFStream { PDFXObject (PDFXref& _xref, Image& _image, const std::string& _compress = "", int _quality = 80) : PDFStream(_xref), image(_image), compress(_compress), quality(_quality) { imageID = ++_xref.imageCount; } virtual std::string resourceName() const { std::stringstream s; s << "/I" << imageID; return s.str(); } virtual std::string resourceType() const { return "/XObject"; } virtual void writeStreamTagsImpl(std::ostream& s) { // default based on image type if (image.bps < 8) encoding = "/FlateDecode"; else encoding = "/DCTDecode"; // TODO: move transform to Args class std::string c(compress); std::transform(c.begin(), c.end(), c.begin(), tolower); Args args(c); if (args.containsAndRemove("ascii85")) encoding = "/ASCII85Decode"; else if (args.containsAndRemove("hex")) encoding = "/ASCIIHexDecode"; #if WITHLIBJPEG == 1 else if (args.containsAndRemove("jpeg")) encoding = "/DCTDecode"; #endif #if WITHLIBJASPER == 1 else if (args.containsAndRemove("jpeg2000")) encoding = "/JPXDecode"; #endif if (args.containsAndRemove("flate")) encoding = "/FlateDecode"; compress = args.str(); s << "/Type /XObject\n" "/Subtype /Image\n" "/Width " << image.w << " /Height " << image.h << "\n" "/ColorSpace " << (image.spp == 1 ? "/DeviceGray" : "/DeviceRGB") << "\n" "/BitsPerComponent " << image.bps << "\n" "/Filter " << encoding << "\n"; } virtual void writeStreamImpl(std::ostream& s) { const int bytes = image.stride() * image.h; uint8_t* data = image.getRawData(); if (encoding == "/FlateDecode") EncodeZlib(s, (const char*)data, bytes); if (encoding == "/ASCII85Decode") EncodeASCII85(s, data, bytes); else if (encoding == "/ASCIIHexDecode") EncodeHex(s, data, bytes); #if WITHLIBJPEG == 1 else if (encoding == "/DCTDecode") { ImageCodec::Write(&s, image, "jpeg", "jpg", quality, compress); } #endif #if WITHJASPER == 1 else if (encoding == "/JPXDecode") { ImageCodec::Write(&s, image, "jp2", "jp2", quality, compress); } #endif // TODO: let the codecs remove what they consumed Args args(compress); args.containsAndRemove("recompress"); if (!args.str().empty()) std::cerr << "PDFCodec: Unrecognized encoding option '" << args.str() << "'" << std::endl; } uint32_t imageID; Image& image; std::string compress; std::string encoding; int quality; }; struct PDFContentStream : public PDFStream { PDFContentStream(PDFXref& _xref, PDFPage& _page) : PDFStream(_xref), parent(_page) { encoding = "/FlateDecode"; c.setf(std::ios::fixed, std::ios::floatfield); c.setf(std::ios::showpoint); c.precision(8); } virtual void writeStreamTagsImpl(std::ostream& s) { if (!encoding.empty()) s << "/Filter " << encoding << "\n"; } virtual void writeStreamImpl(std::ostream& s) { if (!encoding.empty()) { EncodeZlib(s, (const char*)c.str().c_str(), c.str().size()); } else { s << c.rdbuf(); } c.str().clear(); // just release memory after writing } // for the beginning we translate the coordinates manually // to form a more commonly used up-down co-ordinate system void translateY(double& y); // drawing void moveTo(double x, double y) { translateY(y); last_x = x; last_y = y; c << x << " " << y << " m\n"; } void addLineTo(double x, double y) { translateY(y); c << x << " " << y << " l\n"; } void close() { c << "h\n"; } void addCurveTo(double x1, double y1, double x2, double y2, double x3, double y3) { translateY(y1); translateY(y2); translateY(y3); c << x1 << " " << y1 << " " << x2 << " " << y2 << " " << x3 << " " << y3 << " c\n"; } void setFillColor(double r, double g, double b) { if ((r == g) && (g == b)) { // gray optimization for printers c << r << " G\n"; // stroke c << r << " g\n"; // fill } else { c << r << " " << g << " " << b << " RG\n"; // stroke c << r << " " << g << " " << b << " rg\n"; // fill } } void setLineWidth(double width) { c << width << " w\n"; } void setLineDash(double offset, const std::vector& dashes) { c << "["; for (unsigned i = 0; i < dashes.size(); ++i) c << " " << dashes[i]; c << " ] " << offset << " d\n"; } void setLineDash(double offset, const double* dashes, int n) { c << "["; for (; n; n--, dashes++) c << " " << *dashes; c << " ] " << offset << " d\n"; } void showPath(PDFCodec::filling_rule_t fill = PDFCodec::fill_none) { switch (fill) { case PDFCodec::fill_non_zero: c << "f\n"; break; case PDFCodec::fill_even_odd: c << "f*\n"; break; default: c << "S\n"; // stroke break; } } void beginText(); void endText(); void textTo(double x, double y); void showText(const PDFFont& f, const std::string& text, double height); void showImage(const PDFXObject& i, double x, double y, double w, double h); PDFPage& parent; std::string encoding; std::stringstream c; // content / commands double last_x, last_y; double last_text_x, last_text_y, last_text_height; std::string last_text_res; }; struct PDFPage : public PDFObject { PDFPage(PDFXref& xref, PDFPages& _parent, double _w, double _h) : PDFObject(xref), parent(_parent), w(_w), h(_h), content(xref, *this) { parent.pages.push_back(this); } void addResource(const PDFObject* res) { if (res->resourceType() == "/Font") font_resources.insert(res); else image_resources.insert(res); // TODO: assert other types } virtual void writeImpl(std::ostream& s) { s << "<<\n" "/Type /Page\n" "/Parent " << parent.indirectRef() << "\n" "/MediaBox [0 0 " << w << " " << h << "]\n" "/Contents " << content.indirectRef() << "\n" "/Resources <<\n" // TODO: dnymically determin, though it's an obsolete info only tag "/ProcSet[/PDF /Text /ImageB /ImageC]\n"; // for all utilzed indirect resources, /Font (F*) and /XObject (I*) if (!font_resources.empty()) { s << (*font_resources.begin())->resourceType() << " <<"; for (resource_iterator it = font_resources.begin(); it != font_resources.end(); ++it) s << " " << (*it)->resourceName() << " " << (*it)->indirectRef(); s << " >>\n"; } if (!image_resources.empty()) { s << (*image_resources.begin())->resourceType() << " <<"; for (resource_iterator it = image_resources.begin(); it != image_resources.end(); ++it) s << " " << (*it)->resourceName() << " " << (*it)->indirectRef(); s << " >>\n"; } s << ">>\n" ">>\n"; pendingObjWriteout.push_back (&content); // just release memory after writing font_resources.clear(); image_resources.clear(); } PDFPages& parent; double w, h; PDFContentStream content; std::set font_resources; std::set image_resources; typedef std::set::iterator resource_iterator; }; // trailer with start of xref and EOF marker struct PDFTrailer { PDFTrailer(PDFXref& _xref, PDFObject& _root, PDFDocumentInfo* _info = 0) : xref(_xref), root(_root), info(_info) {} void write(std::ostream& s) { s << "\ntrailer\n" "<<\n" "/Size " << xref.objects.size() + 1 << "\n" // total number of entries "/Root " << root.indirectRef() << "\n"; if (info) s << "/Info " << info->indirectRef() << "\n"; s << ">>\n" "\nstartxref\n" << xref.streamPos << "\n" "%%EOF" << std::endl; // final flush, just in case } PDFXref& xref; PDFObject& root; PDFDocumentInfo* info; }; void PDFContentStream::beginText() { last_text_x = last_text_y = last_text_height = 0; last_text_res.clear(); c << "BT\n"; } // TODO: automatic tracking and assertion / auto-correction void PDFContentStream::endText() { c << "ET\n"; } void PDFContentStream::textTo(double x, double y) { translateY(y); c << x - last_text_x << " " << y - last_text_y << " Td\n"; last_text_x = x; last_text_y = y; } void PDFContentStream::showText(const PDFFont& f, const std::string& text, double height) { parent.addResource(&f); std::string fRes = f.resourceName(); if (fRes != last_text_res || height != last_text_height) { c << f.resourceName() << " " << height << " Tf\n"; last_text_height = height; last_text_res = fRes; } c << "("; // parse string and use proper escape // TODO: Unicode mappings bool first_newline = true; // decode utf8, locally std::vector utf8 = DecodeUtf8(text.c_str(), text.size()); for (std::vector::const_iterator it = utf8.begin(); it != utf8.end(); ++it) { switch (*it) { // escapes case '\\': case '(': case ')': c << "\\" << (char)*it; break; // newline case '\n': c << ") Tj\n"; if (first_newline) { first_newline = false; c << height << " TL\n"; } c << "T* ("; break; // just copy by default: default: c << (char)*it; } } c << ") Tj\n"; } void PDFContentStream::translateY(double& y) { y = parent.h - y; } void PDFContentStream::showImage(const PDFXObject& i, double x, double y, double w, double h) { // add to resources parent.addResource(&i); c << "q\n" << "1 0 0 1 " << x << " " << y << " cm\n" // translate << w << " 0 0 " << h << " 0 0 cm\n" // scale << i.resourceName() << " Do\n" "Q\n"; } std::ostream& operator<< (std::ostream& s, PDFTrailer& obj) { obj.write(s); return s; } int PDFCodec::readImage (std::istream* stream, Image& image, const std::string& decompres) { return false; } void PDFXref::write(std::ostream& s) { s << "\n"; // save position in stream for trailer streamPos = s.tellp(); s << "xref\n" "0 " << objects.size() + 1 << "\n"; for (unsigned int i = 0; i < objects.size() + 1; ++i) { uint32_t offset = 0; uint16_t generation = 0xFFFF; char state = 'f'; if (i >0) { offset = objects[i-1]->getStreamPos(); generation = 0; state = 'n'; } s.fill('0'); s.width(10); s << std::right << offset << " "; s.width(5); s << generation << " " << state << " \n"; // only double marker here } } struct PDFContext { std::ostream* s; /* PDF stream construction */ PDFXref xref; PDFDocumentInfo info; PDFPages pages; PDFCatalog catalog; PDFTrailer trailer; std::list pageList; PDFPage* currentPage; std::map fontMap; typedef std::map::iterator fontMapIterator; std::list images; typedef std::list::iterator imageIterator; PDFContext(std::ostream* _s) : s(_s), info(xref), pages(xref), catalog(xref, pages), trailer(xref, catalog, &info), currentPage(0) { // TODO: dynamic version depending on features used // TODO: place in some object? *s << "%PDF-1.4\n%\xc9\xcc\n"; // early 8-bit indicator cookie *s << info; } ~PDFContext() { // write out last page if (currentPage) *s << *currentPage; /* PDF stream finalizing */ *s << pages; *s << catalog; *s << xref; *s << trailer; /* free dynamically allocated objects */ while (!pageList.empty()) { PDFPage* p = pageList.front(); delete (p); pageList.pop_front(); } for (fontMapIterator it = fontMap.begin(); it != fontMap.end(); ++it) delete it->second; for (imageIterator it = images.begin(); it != images.end(); ++it) delete *it; } void beginPage(double w, double h) { // write out last page, also frees some memory if (currentPage) *s << *currentPage; currentPage = new PDFPage(xref, pages, w, h); pageList.push_back(currentPage); } PDFFont* getFont(const std::string& f) { PDFFont* font; fontMapIterator it = fontMap.find(f); if (it != fontMap.end()) return it->second; font = new PDFFont(xref, f); *s << *font; return fontMap[f] = font; } }; bool PDFCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { PDFContext context(stream); PDFXObject* i = new PDFXObject(context.xref, image, compress, quality); *context.s << *i; context.images.push_back(i); const double iw = 72. * image.w / (image.resolutionX() ? image.resolutionX() : 72); const double ih = 72. * image.h / (image.resolutionY() ? image.resolutionX() : 72); context.beginPage(iw, ih); context.currentPage->content.showImage(*i, 0, 0, iw, ih); return true; } // external drawing API // TODO: assert on each context ref PDFCodec::PDFCodec(std::ostream* s) { context = new PDFContext(s); } PDFCodec::~PDFCodec() { if (context) delete context; } void PDFCodec::beginPage(double w, double h) { context->beginPage(w, h); } void PDFCodec::moveTo(double x, double y) { context->currentPage->content.moveTo(x, y); } void PDFCodec::addLineTo(double x, double y) { context->currentPage->content.addLineTo(x, y); } void PDFCodec::closePath() { context->currentPage->content.close(); } void PDFCodec::addCurveTo(double x1, double y1, double x2, double y2, double x3, double y3) { context->currentPage->content.addCurveTo(x1, y1, x2, y2, x3, y3); } void PDFCodec::setFillColor(double r, double g, double b) { context->currentPage->content.setFillColor(r, g, b); } void PDFCodec::setLineWidth(double width) { context->currentPage->content.setLineWidth(width); } void PDFCodec::setLineDash(double offset, const std::vector& dashes) { context->currentPage->content.setLineDash(offset, dashes); } void PDFCodec::setLineDash(double offset, const double* dashes, int n) { context->currentPage->content.setLineDash(offset, dashes, n); } void PDFCodec::showPath(filling_rule_t fill) { context->currentPage->content.showPath(fill); } void PDFCodec::beginText() { context->currentPage->content.beginText(); } void PDFCodec::endText() { context->currentPage->content.endText(); } void PDFCodec::textTo(double x, double y) { context->currentPage->content.textTo(x, y); } void PDFCodec::showText(const std::string& font, const std::string& text, double height) { // hash and map font to PDFFont object PDFFont* f = context->getFont(font); context->currentPage->content.showText(*f, text, height); } void PDFCodec::showImage(Image& image, double x, double y, double width, double height, int quality, const std::string& compress) { PDFXObject* i = new PDFXObject(context->xref, image, compress, quality); *context->s << *i; context->currentPage->content.showImage(*i, x, y, width, height); context->images.push_back(i); } PDFCodec pdf_loader; exact-image-0.9.1/codecs/openexr.hh0000644000076400007640000000207211343547354015634 0ustar renerene/* * Copyright (C) 2006 - 2008 René Rebe * * 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 "Codecs.hh" class OpenEXRCodec : public ImageCodec { public: OpenEXRCodec () { registerCodec ("exr", this); }; virtual std::string getID () { return "OpenEXR"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); }; exact-image-0.9.1/codecs/jinclude.h0000644000076400007640000000626210550751407015601 0ustar renerene/* * jinclude.h * * Copyright (C) 1991-1994, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file exists to provide a single place to fix any problems with * including the wrong system include files. (Common problems are taken * care of by the standard jconfig symbols, but on really weird systems * you may have to edit this file.) * * NOTE: this file is NOT intended to be included by applications using the * JPEG library. Most applications need only include jpeglib.h. */ /* Include auto-config file to find out which system include files we need. */ #include "jconfig.h" /* auto configuration options */ #define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ /* * We need the NULL macro and size_t typedef. * On an ANSI-conforming system it is sufficient to include . * Otherwise, we get them from or ; we may have to * pull in as well. * Note that the core JPEG library does not require ; * only the default error handler and data source/destination modules do. * But we must pull it in because of the references to FILE in jpeglib.h. * You can remove those references if you want to compile without . */ #ifdef HAVE_STDDEF_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef NEED_SYS_TYPES_H #include #endif #include /* * We need memory copying and zeroing functions, plus strncpy(). * ANSI and System V implementations declare these in . * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). * Some systems may declare memset and memcpy in . * * NOTE: we assume the size parameters to these functions are of type size_t. * Change the casts in these macros if not! */ #ifdef NEED_BSD_STRINGS #include #define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) #define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) #else /* not BSD, assume ANSI/SysV string lib */ #include #define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) #define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) #endif /* * In ANSI C, and indeed any rational implementation, size_t is also the * type returned by sizeof(). However, it seems there are some irrational * implementations out there, in which sizeof() returns an int even though * size_t is defined as long or unsigned long. To ensure consistent results * we always use this SIZEOF() macro in place of using sizeof() directly. */ #define SIZEOF(object) ((size_t) sizeof(object)) /* * The modules that use fread() and fwrite() always invoke them through * these macros. On some systems you may need to twiddle the argument casts. * CAUTION: argument order is different from underlying functions! */ #define JFREAD(file,buf,sizeofbuf) \ ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) #define JFWRITE(file,buf,sizeofbuf) \ ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) exact-image-0.9.1/codecs/agg_svg_path_tokenizer.cc0000644000076400007640000001036611027657673020677 0ustar renerene//---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // SVG path tokenizer. // //---------------------------------------------------------------------------- /* * Copyright (c) 2008 Rene Rebe * */ #include #include #include "agg_svg_exception.hh" #include "agg_svg_path_tokenizer.hh" namespace agg { namespace svg { //------------------------------------------------------------------------ const char path_tokenizer::s_commands[] = "+-MmZzLlHhVvCcSsQqTtAaFfPp"; const char path_tokenizer::s_numeric[] = ".Ee0123456789"; const char path_tokenizer::s_separators[] = " ,\t\n\r"; //------------------------------------------------------------------------ path_tokenizer::path_tokenizer() : m_path(0), m_last_number(0.0), m_last_command(0) { init_char_mask(m_commands_mask, s_commands); init_char_mask(m_numeric_mask, s_numeric); init_char_mask(m_separators_mask, s_separators); } //------------------------------------------------------------------------ void path_tokenizer::set_path_str(const char* str) { m_path = str; m_last_command = 0; m_last_number = 0.0; } //------------------------------------------------------------------------ void path_tokenizer::init_char_mask(char* mask, const char* char_set) { memset(mask, 0, 256/8); while(*char_set) { unsigned c = unsigned(*char_set++) & 0xFF; mask[c >> 3] |= 1 << (c & 7); } } //------------------------------------------------------------------------ bool path_tokenizer::next() { if(m_path == 0) return false; // Skip all white spaces and other garbage while(*m_path && !is_command(*m_path) && !is_numeric(*m_path)) { if(!is_separator(*m_path)) { char buf[100]; sprintf(buf, "path_tokenizer::next : Invalid Character %c", *m_path); throw exception(buf); } m_path++; } if(*m_path == 0) return false; if(is_command(*m_path)) { // Check if the command is a numeric sign character if(*m_path == '-' || *m_path == '+') { return parse_number(); } m_last_command = *m_path++; while(*m_path && is_separator(*m_path)) m_path++; if(*m_path == 0) return true; } return parse_number(); } //------------------------------------------------------------------------ double path_tokenizer::next(char cmd) { if(!next()) throw exception("parse_path: Unexpected end of path"); if(last_command() != cmd) { char buf[100]; sprintf(buf, "parse_path: Command %c: bad or missing parameters", cmd); throw exception(buf); } return last_number(); } //------------------------------------------------------------------------ bool path_tokenizer::parse_number() { char buf[256]; // Should be enough for any number char* buf_ptr = buf; // Copy all sign characters while(buf_ptr < buf+255 && (*m_path == '-' || *m_path == '+')) { *buf_ptr++ = *m_path++; } // Copy all numeric characters while(buf_ptr < buf+255 && (is_numeric(*m_path))) { *buf_ptr++ = *m_path++; } *buf_ptr = 0; m_last_number = atof(buf); return true; } } //namespace svg } //namespace agg exact-image-0.9.1/codecs/ps.hh0000644000076400007640000000237611343547354014605 0ustar renerene/* * Copyright (c) 2008 Valentin Ziegler * Copyright (c) 2008 Susanne Klaus * * 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 "Codecs.hh" class PSCodec : public ImageCodec { public: PSCodec () { registerCodec ("ps", this); }; virtual std::string getID () { return "PS"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); static void encodeImage (std::ostream* stream, Image& image, double scale, int quality, const std::string& compress); }; exact-image-0.9.1/codecs/agg_svg_path_renderer.hh0000644000076400007640000002615110776625145020503 0ustar renerene//---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // SVG path renderer. // //---------------------------------------------------------------------------- #ifndef AGG_SVG_PATH_RENDERER_INCLUDED #define AGG_SVG_PATH_RENDERER_INCLUDED #include "agg_path_storage.h" #include "agg_conv_transform.h" #include "agg_conv_stroke.h" #include "agg_conv_contour.h" #include "agg_conv_curve.h" #include "agg_color_rgba.h" #include "agg_renderer_scanline.h" #include "agg_bounding_rect.h" #include "agg_rasterizer_scanline_aa.h" #include "agg_svg_path_tokenizer.hh" namespace agg { namespace svg { template class conv_count { public: conv_count(VertexSource& vs) : m_source(&vs), m_count(0) {} void count(unsigned n) { m_count = n; } unsigned count() const { return m_count; } void rewind(unsigned path_id) { m_source->rewind(path_id); } unsigned vertex(double* x, double* y) { ++m_count; return m_source->vertex(x, y); } private: VertexSource* m_source; unsigned m_count; }; //============================================================================ // Basic path attributes struct path_attributes { unsigned index; rgba8 fill_color; rgba8 stroke_color; bool fill_flag; bool stroke_flag; bool even_odd_flag; line_join_e line_join; line_cap_e line_cap; double miter_limit; double stroke_width; trans_affine transform; // Empty constructor path_attributes() : index(0), fill_color(rgba(0,0,0)), stroke_color(rgba(0,0,0)), fill_flag(true), stroke_flag(false), even_odd_flag(false), line_join(miter_join), line_cap(butt_cap), miter_limit(4.0), stroke_width(1.0), transform() { } // Copy constructor path_attributes(const path_attributes& attr) : index(attr.index), fill_color(attr.fill_color), stroke_color(attr.stroke_color), fill_flag(attr.fill_flag), stroke_flag(attr.stroke_flag), even_odd_flag(attr.even_odd_flag), line_join(attr.line_join), line_cap(attr.line_cap), miter_limit(attr.miter_limit), stroke_width(attr.stroke_width), transform(attr.transform) { } // Copy constructor with new index value path_attributes(const path_attributes& attr, unsigned idx) : index(idx), fill_color(attr.fill_color), stroke_color(attr.stroke_color), fill_flag(attr.fill_flag), stroke_flag(attr.stroke_flag), even_odd_flag(attr.even_odd_flag), line_join(attr.line_join), line_cap(attr.line_cap), miter_limit(attr.miter_limit), stroke_width(attr.stroke_width), transform(attr.transform) { } }; //============================================================================ // Path container and renderer. class path_renderer { public: typedef pod_bvector attr_storage; typedef conv_curve curved; typedef conv_count curved_count; typedef conv_stroke curved_stroked; typedef conv_transform curved_stroked_trans; typedef conv_transform curved_trans; typedef conv_contour curved_trans_contour; path_renderer(); void remove_all(); // Use these functions as follows: // begin_path() when the XML tag comes ("start_element" handler) // parse_path() on "d=" tag attribute // end_path() when parsing of the entire tag is done. void begin_path(); void parse_path(path_tokenizer& tok); void end_path(); // The following functions are essentially a "reflection" of // the respective SVG path commands. void move_to(double x, double y, bool rel=false); // M, m void line_to(double x, double y, bool rel=false); // L, l void hline_to(double x, bool rel=false); // H, h void vline_to(double y, bool rel=false); // V, v void curve3(double x1, double y1, // Q, q double x, double y, bool rel=false); void curve3(double x, double y, bool rel=false); // T, t void curve4(double x1, double y1, // C, c double x2, double y2, double x, double y, bool rel=false); void curve4(double x2, double y2, // S, s double x, double y, bool rel=false); void arc(double rx, double ry, double angle, // A, a bool large_arc_flag, bool sweep_flag, double x, double y, bool rel=false); void close_subpath(); // Z, z // template // void add_path(VertexSource& vs, // unsigned path_id = 0, // bool solid_path = true) // { // m_storage.add_path(vs, path_id, solid_path); // } unsigned vertex_count() const { return m_curved_count.count(); } // Call these functions on tag (start_element, end_element respectively) void push_attr(); void pop_attr(); // Attribute setting functions. void fill(const rgba8& f); void stroke(const rgba8& s); void even_odd(bool flag); void stroke_width(double w); void fill_none(); void stroke_none(); void fill_opacity(double op); void stroke_opacity(double op); void line_join(line_join_e join); void line_cap(line_cap_e cap); void miter_limit(double ml); trans_affine& transform(); // Make all polygons CCW-oriented void arrange_orientations() { m_storage.arrange_orientations_all_paths(path_flags_ccw); } // Expand all polygons void expand(double value) { m_curved_trans_contour.width(value); } unsigned operator [](unsigned idx) { m_transform = m_attr_storage[idx].transform; return m_attr_storage[idx].index; } void bounding_rect(double* x1, double* y1, double* x2, double* y2) { agg::conv_transform trans(m_storage, m_transform); agg::bounding_rect(trans, *this, 0, m_attr_storage.size(), x1, y1, x2, y2); } // Rendering. One can specify two additional parameters: // trans_affine and opacity. They can be used to transform the whole // image and/or to make it translucent. template void render(Rasterizer& ras, Scanline& sl, Renderer& ren, const trans_affine& mtx, const rect_i& cb, double opacity=1.0) { unsigned i; ras.clip_box(cb.x1, cb.y1, cb.x2, cb.y2); m_curved_count.count(0); for(i = 0; i < m_attr_storage.size(); i++) { const path_attributes& attr = m_attr_storage[i]; m_transform = attr.transform; m_transform *= mtx; double scl = m_transform.scale(); //m_curved.approximation_method(curve_inc); m_curved.approximation_scale(scl); m_curved.angle_tolerance(0.0); rgba8 color; if(attr.fill_flag) { ras.reset(); ras.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero); if(fabs(m_curved_trans_contour.width()) < 0.0001) { ras.add_path(m_curved_trans, attr.index); } else { m_curved_trans_contour.miter_limit(attr.miter_limit); ras.add_path(m_curved_trans_contour, attr.index); } color = attr.fill_color; color.opacity(color.opacity() * opacity); ren.color(color); agg::render_scanlines(ras, sl, ren); } if(attr.stroke_flag) { m_curved_stroked.width(attr.stroke_width); //m_curved_stroked.line_join((attr.line_join == miter_join) ? miter_join_round : attr.line_join); m_curved_stroked.line_join(attr.line_join); m_curved_stroked.line_cap(attr.line_cap); m_curved_stroked.miter_limit(attr.miter_limit); m_curved_stroked.inner_join(inner_round); m_curved_stroked.approximation_scale(scl); // If the *visual* line width is considerable we // turn on processing of curve cusps. //--------------------- if(attr.stroke_width * scl > 1.0) { m_curved.angle_tolerance(0.2); } ras.reset(); ras.filling_rule(fill_non_zero); ras.add_path(m_curved_stroked_trans, attr.index); color = attr.stroke_color; color.opacity(color.opacity() * opacity); ren.color(color); agg::render_scanlines(ras, sl, ren); } } } private: path_attributes& cur_attr(); path_storage m_storage; attr_storage m_attr_storage; attr_storage m_attr_stack; trans_affine m_transform; curved m_curved; curved_count m_curved_count; curved_stroked m_curved_stroked; curved_stroked_trans m_curved_stroked_trans; curved_trans m_curved_trans; curved_trans_contour m_curved_trans_contour; }; } } #endif exact-image-0.9.1/codecs/transupp.c0000644000076400007640000015371711171663571015667 0ustar renerene/* * transupp.c * * Copyright (C) 1997-2001, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains image transformation routines and other utility code * used by the jpegtran sample application. These are NOT part of the core * JPEG library. But we keep these routines separate from jpegtran.c to * ease the task of maintaining jpegtran-like programs that have other user * interfaces. */ /* Although this file really shouldn't have access to the library internals, * it's helpful to let it call jround_up() and jcopy_block_row(). */ #define JPEG_INTERNALS #include "jinclude.h" #include "jpeglib.h" #include "transupp.h" /* My own external interface */ #include /* to declare isdigit() */ #if TRANSFORMS_SUPPORTED /* * Lossless image transformation routines. These routines work on DCT * coefficient arrays and thus do not require any lossy decompression * or recompression of the image. * Thanks to Guido Vollbeding for the initial design and code of this feature, * and to Ben Jackson for introducing the cropping feature. * * Horizontal flipping is done in-place, using a single top-to-bottom * pass through the virtual source array. It will thus be much the * fastest option for images larger than main memory. * * The other routines require a set of destination virtual arrays, so they * need twice as much memory as jpegtran normally does. The destination * arrays are always written in normal scan order (top to bottom) because * the virtual array manager expects this. The source arrays will be scanned * in the corresponding order, which means multiple passes through the source * arrays for most of the transforms. That could result in much thrashing * if the image is larger than main memory. * * If cropping or trimming is involved, the destination arrays may be smaller * than the source arrays. Note it is not possible to do horizontal flip * in-place when a nonzero Y crop offset is specified, since we'd have to move * data from one block row to another but the virtual array manager doesn't * guarantee we can touch more than one row at a time. So in that case, * we have to use a separate destination array. * * Some notes about the operating environment of the individual transform * routines: * 1. Both the source and destination virtual arrays are allocated from the * source JPEG object, and therefore should be manipulated by calling the * source's memory manager. * 2. The destination's component count should be used. It may be smaller * than the source's when forcing to grayscale. * 3. Likewise the destination's sampling factors should be used. When * forcing to grayscale the destination's sampling factors will be all 1, * and we may as well take that as the effective iMCU size. * 4. When "trim" is in effect, the destination's dimensions will be the * trimmed values but the source's will be untrimmed. * 5. When "crop" is in effect, the destination's dimensions will be the * cropped values but the source's will be uncropped. Each transform * routine is responsible for picking up source data starting at the * correct X and Y offset for the crop region. (The X and Y offsets * passed to the transform routines are measured in iMCU blocks of the * destination.) * 6. All the routines assume that the source and destination buffers are * padded out to a full iMCU boundary. This is true, although for the * source buffer it is an undocumented property of jdcoefct.c. */ LOCAL(void) do_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Crop. This is only used when no rotate/flip is requested with the crop. */ { JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks; int ci, offset_y; JBLOCKARRAY src_buffer, dst_buffer; jpeg_component_info *compptr; /* We simply have to copy the right amount of data (the destination's * image size) starting at the given X and Y offsets in the source. */ for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, dst_buffer[offset_y], compptr->width_in_blocks); } } } } LOCAL(void) do_flip_h_no_crop (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays) /* Horizontal flip; done in-place, so no separate dest array is required. * NB: this only works when y_crop_offset is zero. */ { JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks; int ci, k, offset_y; JBLOCKARRAY buffer; JCOEFPTR ptr1, ptr2; JCOEF temp1, temp2; jpeg_component_info *compptr; /* Horizontal mirroring of DCT blocks is accomplished by swapping * pairs of blocks in-place. Within a DCT block, we perform horizontal * mirroring by changing the signs of odd-numbered columns. * Partial iMCUs at the right edge are left untouched. */ MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; for (blk_y = 0; blk_y < compptr->height_in_blocks; blk_y += compptr->v_samp_factor) { buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { /* Do the mirroring */ for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) { ptr1 = buffer[offset_y][blk_x]; ptr2 = buffer[offset_y][comp_width - blk_x - 1]; /* this unrolled loop doesn't need to know which row it's on... */ for (k = 0; k < DCTSIZE2; k += 2) { temp1 = *ptr1; /* swap even column */ temp2 = *ptr2; *ptr1++ = temp2; *ptr2++ = temp1; temp1 = *ptr1; /* swap odd column with sign change */ temp2 = *ptr2; *ptr1++ = -temp2; *ptr2++ = -temp1; } } if (x_crop_blocks > 0) { /* Now left-justify the portion of the data to be kept. * We can't use a single jcopy_block_row() call because that routine * depends on memcpy(), whose behavior is unspecified for overlapping * source and destination areas. Sigh. */ for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) { jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks, buffer[offset_y] + blk_x, (JDIMENSION) 1); } } } } } } LOCAL(void) do_flip_h (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Horizontal flip in general cropping case */ { JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, k, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JBLOCKROW src_row_ptr, dst_row_ptr; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Here we must output into a separate array because we can't touch * different rows of a single virtual array simultaneously. Otherwise, * this is essentially the same as the routine above. */ MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { dst_row_ptr = dst_buffer[offset_y]; src_row_ptr = src_buffer[offset_y]; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Do the mirrorable blocks */ dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; /* this unrolled loop doesn't need to know which row it's on... */ for (k = 0; k < DCTSIZE2; k += 2) { *dst_ptr++ = *src_ptr++; /* copy even column */ *dst_ptr++ = - *src_ptr++; /* copy odd column with sign change */ } } else { /* Copy last partial block(s) verbatim */ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, dst_row_ptr + dst_blk_x, (JDIMENSION) 1); } } } } } } LOCAL(void) do_flip_v (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Vertical flip */ { JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JBLOCKROW src_row_ptr, dst_row_ptr; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* We output into a separate array because we can't touch different * rows of the source virtual array simultaneously. Otherwise, this * is a pretty straightforward analog of horizontal flip. * Within a DCT block, vertical mirroring is done by changing the signs * of odd-numbered rows. * Partial iMCUs at the bottom edge are copied verbatim. */ MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); if (y_crop_blocks + dst_blk_y < comp_height) { /* Row is within the mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_height - y_crop_blocks - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, (JDIMENSION) compptr->v_samp_factor, FALSE); } else { /* Bottom-edge blocks will be copied verbatim. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); } for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { if (y_crop_blocks + dst_blk_y < comp_height) { /* Row is within the mirrorable area. */ dst_row_ptr = dst_buffer[offset_y]; src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; src_row_ptr += x_crop_blocks; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[dst_blk_x]; for (i = 0; i < DCTSIZE; i += 2) { /* copy even row */ for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = *src_ptr++; /* copy odd row with sign change */ for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = - *src_ptr++; } } } else { /* Just copy row verbatim. */ jcopy_block_row(src_buffer[offset_y] + x_crop_blocks, dst_buffer[offset_y], compptr->width_in_blocks); } } } } } LOCAL(void) do_transpose (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Transpose source into destination */ { JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Transposing pixels within a block just requires transposing the * DCT coefficients. * Partial iMCUs at the edges require no special treatment; we simply * process all the available DCT blocks for every component. */ for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x + x_crop_blocks, (JDIMENSION) compptr->h_samp_factor, FALSE); for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; src_ptr = src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } LOCAL(void) do_rot_90 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 90 degree rotation is equivalent to * 1. Transposing the image; * 2. Horizontal mirroring. * These two steps are merged into a single processing routine. */ { JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Because of the horizontal mirror step, we can't process partial iMCUs * at the (output) right edge properly. They just get transposed and * not mirrored. */ MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_width - x_crop_blocks - dst_blk_x - (JDIMENSION) compptr->h_samp_factor, (JDIMENSION) compptr->h_samp_factor, FALSE); } else { /* Edge blocks are transposed but not mirrored. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x + x_crop_blocks, (JDIMENSION) compptr->h_samp_factor, FALSE); } for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; if (x_crop_blocks + dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; i++; for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } else { /* Edge blocks are transposed but not mirrored. */ src_ptr = src_buffer[offset_x] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } } LOCAL(void) do_rot_270 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 270 degree rotation is equivalent to * 1. Horizontal mirroring; * 2. Transposing the image. * These two steps are merged into a single processing routine. */ { JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; /* Because of the horizontal mirror step, we can't process partial iMCUs * at the (output) bottom edge properly. They just get transposed and * not mirrored. */ MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x + x_crop_blocks, (JDIMENSION) compptr->h_samp_factor, FALSE); for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; if (y_crop_blocks + dst_blk_y < comp_height) { /* Block is within the mirrorable area. */ src_ptr = src_buffer[offset_x] [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } } else { /* Edge blocks are transposed but not mirrored. */ src_ptr = src_buffer[offset_x] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } } LOCAL(void) do_rot_180 (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* 180 degree rotation is equivalent to * 1. Vertical mirroring; * 2. Horizontal mirroring. * These two steps are merged into a single processing routine. */ { JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JBLOCKROW src_row_ptr, dst_row_ptr; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; MCU_cols = srcinfo->image_width / (dstinfo->max_h_samp_factor * DCTSIZE); MCU_rows = srcinfo->image_height / (dstinfo->max_v_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); if (y_crop_blocks + dst_blk_y < comp_height) { /* Row is within the vertically mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_height - y_crop_blocks - dst_blk_y - (JDIMENSION) compptr->v_samp_factor, (JDIMENSION) compptr->v_samp_factor, FALSE); } else { /* Bottom-edge rows are only mirrored horizontally. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks, (JDIMENSION) compptr->v_samp_factor, FALSE); } for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { dst_row_ptr = dst_buffer[offset_y]; if (y_crop_blocks + dst_blk_y < comp_height) { /* Row is within the mirrorable area. */ src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1]; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { dst_ptr = dst_row_ptr[dst_blk_x]; if (x_crop_blocks + dst_blk_x < comp_width) { /* Process the blocks that can be mirrored both ways. */ src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; for (i = 0; i < DCTSIZE; i += 2) { /* For even row, negate every odd column. */ for (j = 0; j < DCTSIZE; j += 2) { *dst_ptr++ = *src_ptr++; *dst_ptr++ = - *src_ptr++; } /* For odd row, negate every even column. */ for (j = 0; j < DCTSIZE; j += 2) { *dst_ptr++ = - *src_ptr++; *dst_ptr++ = *src_ptr++; } } } else { /* Any remaining right-edge blocks are only mirrored vertically. */ src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x]; for (i = 0; i < DCTSIZE; i += 2) { for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = *src_ptr++; for (j = 0; j < DCTSIZE; j++) *dst_ptr++ = - *src_ptr++; } } } } else { /* Remaining rows are just mirrored horizontally. */ src_row_ptr = src_buffer[offset_y]; for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x++) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Process the blocks that can be mirrored. */ dst_ptr = dst_row_ptr[dst_blk_x]; src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1]; for (i = 0; i < DCTSIZE2; i += 2) { *dst_ptr++ = *src_ptr++; *dst_ptr++ = - *src_ptr++; } } else { /* Any remaining right-edge blocks are only copied. */ jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks, dst_row_ptr + dst_blk_x, (JDIMENSION) 1); } } } } } } } LOCAL(void) do_transverse (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JDIMENSION x_crop_offset, JDIMENSION y_crop_offset, jvirt_barray_ptr *src_coef_arrays, jvirt_barray_ptr *dst_coef_arrays) /* Transverse transpose is equivalent to * 1. 180 degree rotation; * 2. Transposition; * or * 1. Horizontal mirroring; * 2. Transposition; * 3. Horizontal mirroring. * These steps are merged into a single processing routine. */ { JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y; JDIMENSION x_crop_blocks, y_crop_blocks; int ci, i, j, offset_x, offset_y; JBLOCKARRAY src_buffer, dst_buffer; JCOEFPTR src_ptr, dst_ptr; jpeg_component_info *compptr; MCU_cols = srcinfo->image_height / (dstinfo->max_h_samp_factor * DCTSIZE); MCU_rows = srcinfo->image_width / (dstinfo->max_v_samp_factor * DCTSIZE); for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; comp_width = MCU_cols * compptr->h_samp_factor; comp_height = MCU_rows * compptr->v_samp_factor; x_crop_blocks = x_crop_offset * compptr->h_samp_factor; y_crop_blocks = y_crop_offset * compptr->v_samp_factor; for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks; dst_blk_y += compptr->v_samp_factor) { dst_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, dst_coef_arrays[ci], dst_blk_y, (JDIMENSION) compptr->v_samp_factor, TRUE); for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) { for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks; dst_blk_x += compptr->h_samp_factor) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], comp_width - x_crop_blocks - dst_blk_x - (JDIMENSION) compptr->h_samp_factor, (JDIMENSION) compptr->h_samp_factor, FALSE); } else { src_buffer = (*srcinfo->mem->access_virt_barray) ((j_common_ptr) srcinfo, src_coef_arrays[ci], dst_blk_x + x_crop_blocks, (JDIMENSION) compptr->h_samp_factor, FALSE); } for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) { dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x]; if (y_crop_blocks + dst_blk_y < comp_height) { if (x_crop_blocks + dst_blk_x < comp_width) { /* Block is within the mirrorable area. */ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } i++; for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } else { /* Right-edge blocks are mirrored in y only */ src_ptr = src_buffer[offset_x] [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) { dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; j++; dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } } } else { if (x_crop_blocks + dst_blk_x < comp_width) { /* Bottom-edge blocks are mirrored in x only */ src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; i++; for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = -src_ptr[i*DCTSIZE+j]; } } else { /* At lower right corner, just transpose, no mirroring */ src_ptr = src_buffer[offset_x] [dst_blk_y + offset_y + y_crop_blocks]; for (i = 0; i < DCTSIZE; i++) for (j = 0; j < DCTSIZE; j++) dst_ptr[j*DCTSIZE+i] = src_ptr[i*DCTSIZE+j]; } } } } } } } } /* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec. * Returns TRUE if valid integer found, FALSE if not. * *strptr is advanced over the digit string, and *result is set to its value. */ LOCAL(boolean) jt_read_integer (const char ** strptr, JDIMENSION * result) { const char * ptr = *strptr; JDIMENSION val = 0; for (; isdigit(*ptr); ptr++) { val = val * 10 + (JDIMENSION) (*ptr - '0'); } *result = val; if (ptr == *strptr) return FALSE; /* oops, no digits */ *strptr = ptr; return TRUE; } /* Parse a crop specification (written in X11 geometry style). * The routine returns TRUE if the spec string is valid, FALSE if not. * * The crop spec string should have the format * x{+-}{+-} * where width, height, xoffset, and yoffset are unsigned integers. * Each of the elements can be omitted to indicate a default value. * (A weakness of this style is that it is not possible to omit xoffset * while specifying yoffset, since they look alike.) * * This code is loosely based on XParseGeometry from the X11 distribution. */ GLOBAL(boolean) jtransform_parse_crop_spec (jpeg_transform_info *info, const char *spec) { info->crop = FALSE; info->crop_width_set = JCROP_UNSET; info->crop_height_set = JCROP_UNSET; info->crop_xoffset_set = JCROP_UNSET; info->crop_yoffset_set = JCROP_UNSET; if (isdigit(*spec)) { /* fetch width */ if (! jt_read_integer(&spec, &info->crop_width)) return FALSE; info->crop_width_set = JCROP_POS; } if (*spec == 'x' || *spec == 'X') { /* fetch height */ spec++; if (! jt_read_integer(&spec, &info->crop_height)) return FALSE; info->crop_height_set = JCROP_POS; } if (*spec == '+' || *spec == '-') { /* fetch xoffset */ info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; spec++; if (! jt_read_integer(&spec, &info->crop_xoffset)) return FALSE; } if (*spec == '+' || *spec == '-') { /* fetch yoffset */ info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS; spec++; if (! jt_read_integer(&spec, &info->crop_yoffset)) return FALSE; } /* We had better have gotten to the end of the string. */ if (*spec != '\0') return FALSE; info->crop = TRUE; return TRUE; } /* Trim off any partial iMCUs on the indicated destination edge */ LOCAL(void) trim_right_edge (jpeg_transform_info *info, JDIMENSION full_width) { JDIMENSION MCU_cols; MCU_cols = info->output_width / (info->max_h_samp_factor * DCTSIZE); if (MCU_cols > 0 && info->x_crop_offset + MCU_cols == full_width / (info->max_h_samp_factor * DCTSIZE)) info->output_width = MCU_cols * (info->max_h_samp_factor * DCTSIZE); } LOCAL(void) trim_bottom_edge (jpeg_transform_info *info, JDIMENSION full_height) { JDIMENSION MCU_rows; MCU_rows = info->output_height / (info->max_v_samp_factor * DCTSIZE); if (MCU_rows > 0 && info->y_crop_offset + MCU_rows == full_height / (info->max_v_samp_factor * DCTSIZE)) info->output_height = MCU_rows * (info->max_v_samp_factor * DCTSIZE); } /* Request any required workspace. * * This routine figures out the size that the output image will be * (which implies that all the transform parameters must be set before * it is called). * * We allocate the workspace virtual arrays from the source decompression * object, so that all the arrays (both the original data and the workspace) * will be taken into account while making memory management decisions. * Hence, this routine must be called after jpeg_read_header (which reads * the image dimensions) and before jpeg_read_coefficients (which realizes * the source's virtual arrays). */ GLOBAL(void) jtransform_request_workspace (j_decompress_ptr srcinfo, jpeg_transform_info *info) { jvirt_barray_ptr *coef_arrays = NULL; boolean need_workspace, transpose_it; jpeg_component_info *compptr; JDIMENSION xoffset, yoffset, width_in_iMCUs, height_in_iMCUs; JDIMENSION width_in_blocks, height_in_blocks; int ci, h_samp_factor, v_samp_factor; /* Determine number of components in output image */ if (info->force_grayscale && srcinfo->jpeg_color_space == JCS_YCbCr && srcinfo->num_components == 3) { /* We'll only process the first component */ info->num_components = 1; } else { /* Process all the components */ info->num_components = srcinfo->num_components; } /* If there is only one output component, force the iMCU size to be 1; * else use the source iMCU size. (This allows us to do the right thing * when reducing color to grayscale, and also provides a handy way of * cleaning up "funny" grayscale images whose sampling factors are not 1x1.) */ switch (info->transform) { case JXFORM_TRANSPOSE: case JXFORM_TRANSVERSE: case JXFORM_ROT_90: case JXFORM_ROT_270: info->output_width = srcinfo->image_height; info->output_height = srcinfo->image_width; if (info->num_components == 1) { info->max_h_samp_factor = 1; info->max_v_samp_factor = 1; } else { info->max_h_samp_factor = srcinfo->max_v_samp_factor; info->max_v_samp_factor = srcinfo->max_h_samp_factor; } break; default: info->output_width = srcinfo->image_width; info->output_height = srcinfo->image_height; if (info->num_components == 1) { info->max_h_samp_factor = 1; info->max_v_samp_factor = 1; } else { info->max_h_samp_factor = srcinfo->max_h_samp_factor; info->max_v_samp_factor = srcinfo->max_v_samp_factor; } break; } /* If cropping has been requested, compute the crop area's position and * dimensions, ensuring that its upper left corner falls at an iMCU boundary. */ if (info->crop) { /* Insert default values for unset crop parameters */ if (info->crop_xoffset_set == JCROP_UNSET) info->crop_xoffset = 0; /* default to +0 */ if (info->crop_yoffset_set == JCROP_UNSET) info->crop_yoffset = 0; /* default to +0 */ if (info->crop_xoffset >= info->output_width || info->crop_yoffset >= info->output_height) ERREXIT(srcinfo, "Invalid crop request"); /* was: JERR_BAD_CROP_SPEC */ if (info->crop_width_set == JCROP_UNSET) info->crop_width = info->output_width - info->crop_xoffset; if (info->crop_height_set == JCROP_UNSET) info->crop_height = info->output_height - info->crop_yoffset; /* Ensure parameters are valid */ if (info->crop_width <= 0 || info->crop_width > info->output_width || info->crop_height <= 0 || info->crop_height > info->output_height || info->crop_xoffset > info->output_width - info->crop_width || info->crop_yoffset > info->output_height - info->crop_height) ERREXIT(srcinfo, "Invalid crop request"); /* was: JERR_BAD_CROP_SPEC */ /* Convert negative crop offsets into regular offsets */ if (info->crop_xoffset_set == JCROP_NEG) xoffset = info->output_width - info->crop_width - info->crop_xoffset; else xoffset = info->crop_xoffset; if (info->crop_yoffset_set == JCROP_NEG) yoffset = info->output_height - info->crop_height - info->crop_yoffset; else yoffset = info->crop_yoffset; /* Now adjust so that upper left corner falls at an iMCU boundary */ info->output_width = info->crop_width + (xoffset % (info->max_h_samp_factor * DCTSIZE)); info->output_height = info->crop_height + (yoffset % (info->max_v_samp_factor * DCTSIZE)); /* Save x/y offsets measured in iMCUs */ info->x_crop_offset = xoffset / (info->max_h_samp_factor * DCTSIZE); info->y_crop_offset = yoffset / (info->max_v_samp_factor * DCTSIZE); } else { info->x_crop_offset = 0; info->y_crop_offset = 0; } /* Figure out whether we need workspace arrays, * and if so whether they are transposed relative to the source. */ need_workspace = FALSE; transpose_it = FALSE; switch (info->transform) { case JXFORM_NONE: if (info->x_crop_offset != 0 || info->y_crop_offset != 0) need_workspace = TRUE; /* No workspace needed if neither cropping nor transforming */ break; case JXFORM_FLIP_H: if (info->trim) trim_right_edge(info, srcinfo->image_width); if (info->y_crop_offset != 0) need_workspace = TRUE; /* do_flip_h_no_crop doesn't need a workspace array */ break; case JXFORM_FLIP_V: if (info->trim) trim_bottom_edge(info, srcinfo->image_height); /* Need workspace arrays having same dimensions as source image. */ need_workspace = TRUE; break; case JXFORM_TRANSPOSE: /* transpose does NOT have to trim anything */ /* Need workspace arrays having transposed dimensions. */ need_workspace = TRUE; transpose_it = TRUE; break; case JXFORM_TRANSVERSE: if (info->trim) { trim_right_edge(info, srcinfo->image_height); trim_bottom_edge(info, srcinfo->image_width); } /* Need workspace arrays having transposed dimensions. */ need_workspace = TRUE; transpose_it = TRUE; break; case JXFORM_ROT_90: if (info->trim) trim_right_edge(info, srcinfo->image_height); /* Need workspace arrays having transposed dimensions. */ need_workspace = TRUE; transpose_it = TRUE; break; case JXFORM_ROT_180: if (info->trim) { trim_right_edge(info, srcinfo->image_width); trim_bottom_edge(info, srcinfo->image_height); } /* Need workspace arrays having same dimensions as source image. */ need_workspace = TRUE; break; case JXFORM_ROT_270: if (info->trim) trim_bottom_edge(info, srcinfo->image_width); /* Need workspace arrays having transposed dimensions. */ need_workspace = TRUE; transpose_it = TRUE; break; } /* Allocate workspace if needed. * Note that we allocate arrays padded out to the next iMCU boundary, * so that transform routines need not worry about missing edge blocks. */ if (need_workspace) { coef_arrays = (jvirt_barray_ptr *) (*srcinfo->mem->alloc_small) ((j_common_ptr) srcinfo, JPOOL_IMAGE, SIZEOF(jvirt_barray_ptr) * info->num_components); width_in_iMCUs = (JDIMENSION) jdiv_round_up((long) info->output_width, (long) (info->max_h_samp_factor * DCTSIZE)); height_in_iMCUs = (JDIMENSION) jdiv_round_up((long) info->output_height, (long) (info->max_v_samp_factor * DCTSIZE)); for (ci = 0; ci < info->num_components; ci++) { compptr = srcinfo->comp_info + ci; if (info->num_components == 1) { /* we're going to force samp factors to 1x1 in this case */ h_samp_factor = v_samp_factor = 1; } else if (transpose_it) { h_samp_factor = compptr->v_samp_factor; v_samp_factor = compptr->h_samp_factor; } else { h_samp_factor = compptr->h_samp_factor; v_samp_factor = compptr->v_samp_factor; } width_in_blocks = width_in_iMCUs * h_samp_factor; height_in_blocks = height_in_iMCUs * v_samp_factor; coef_arrays[ci] = (*srcinfo->mem->request_virt_barray) ((j_common_ptr) srcinfo, JPOOL_IMAGE, FALSE, width_in_blocks, height_in_blocks, (JDIMENSION) v_samp_factor); } } info->workspace_coef_arrays = coef_arrays; } /* Transpose destination image parameters */ LOCAL(void) transpose_critical_parameters (j_compress_ptr dstinfo) { int tblno, i, j, ci, itemp; jpeg_component_info *compptr; JQUANT_TBL *qtblptr; UINT16 qtemp; /* Transpose sampling factors */ for (ci = 0; ci < dstinfo->num_components; ci++) { compptr = dstinfo->comp_info + ci; itemp = compptr->h_samp_factor; compptr->h_samp_factor = compptr->v_samp_factor; compptr->v_samp_factor = itemp; } /* Transpose quantization tables */ for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) { qtblptr = dstinfo->quant_tbl_ptrs[tblno]; if (qtblptr != NULL) { for (i = 0; i < DCTSIZE; i++) { for (j = 0; j < i; j++) { qtemp = qtblptr->quantval[i*DCTSIZE+j]; qtblptr->quantval[i*DCTSIZE+j] = qtblptr->quantval[j*DCTSIZE+i]; qtblptr->quantval[j*DCTSIZE+i] = qtemp; } } } } } /* Adjust Exif image parameters. * * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible. */ LOCAL(void) adjust_exif_parameters (JOCTET FAR * data, unsigned int length, JDIMENSION new_width, JDIMENSION new_height) { boolean is_motorola; /* Flag for byte order */ unsigned int number_of_tags, tagnum; unsigned int firstoffset, offset; JDIMENSION new_value; if (length < 12) return; /* Length of an IFD entry */ /* Discover byte order */ if (GETJOCTET(data[0]) == 0x49 && GETJOCTET(data[1]) == 0x49) is_motorola = FALSE; else if (GETJOCTET(data[0]) == 0x4D && GETJOCTET(data[1]) == 0x4D) is_motorola = TRUE; else return; /* Check Tag Mark */ if (is_motorola) { if (GETJOCTET(data[2]) != 0) return; if (GETJOCTET(data[3]) != 0x2A) return; } else { if (GETJOCTET(data[3]) != 0) return; if (GETJOCTET(data[2]) != 0x2A) return; } /* Get first IFD offset (offset to IFD0) */ if (is_motorola) { if (GETJOCTET(data[4]) != 0) return; if (GETJOCTET(data[5]) != 0) return; firstoffset = GETJOCTET(data[6]); firstoffset <<= 8; firstoffset += GETJOCTET(data[7]); } else { if (GETJOCTET(data[7]) != 0) return; if (GETJOCTET(data[6]) != 0) return; firstoffset = GETJOCTET(data[5]); firstoffset <<= 8; firstoffset += GETJOCTET(data[4]); } if (firstoffset > length - 2) return; /* check end of data segment */ /* Get the number of directory entries contained in this IFD */ if (is_motorola) { number_of_tags = GETJOCTET(data[firstoffset]); number_of_tags <<= 8; number_of_tags += GETJOCTET(data[firstoffset+1]); } else { number_of_tags = GETJOCTET(data[firstoffset+1]); number_of_tags <<= 8; number_of_tags += GETJOCTET(data[firstoffset]); } if (number_of_tags == 0) return; firstoffset += 2; /* Search for ExifSubIFD offset Tag in IFD0 */ for (;;) { if (firstoffset > length - 12) return; /* check end of data segment */ /* Get Tag number */ if (is_motorola) { tagnum = GETJOCTET(data[firstoffset]); tagnum <<= 8; tagnum += GETJOCTET(data[firstoffset+1]); } else { tagnum = GETJOCTET(data[firstoffset+1]); tagnum <<= 8; tagnum += GETJOCTET(data[firstoffset]); } if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */ if (--number_of_tags == 0) return; firstoffset += 12; } /* Get the ExifSubIFD offset */ if (is_motorola) { if (GETJOCTET(data[firstoffset+8]) != 0) return; if (GETJOCTET(data[firstoffset+9]) != 0) return; offset = GETJOCTET(data[firstoffset+10]); offset <<= 8; offset += GETJOCTET(data[firstoffset+11]); } else { if (GETJOCTET(data[firstoffset+11]) != 0) return; if (GETJOCTET(data[firstoffset+10]) != 0) return; offset = GETJOCTET(data[firstoffset+9]); offset <<= 8; offset += GETJOCTET(data[firstoffset+8]); } if (offset > length - 2) return; /* check end of data segment */ /* Get the number of directory entries contained in this SubIFD */ if (is_motorola) { number_of_tags = GETJOCTET(data[offset]); number_of_tags <<= 8; number_of_tags += GETJOCTET(data[offset+1]); } else { number_of_tags = GETJOCTET(data[offset+1]); number_of_tags <<= 8; number_of_tags += GETJOCTET(data[offset]); } if (number_of_tags < 2) return; offset += 2; /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */ do { if (offset > length - 12) return; /* check end of data segment */ /* Get Tag number */ if (is_motorola) { tagnum = GETJOCTET(data[offset]); tagnum <<= 8; tagnum += GETJOCTET(data[offset+1]); } else { tagnum = GETJOCTET(data[offset+1]); tagnum <<= 8; tagnum += GETJOCTET(data[offset]); } if (tagnum == 0xA002 || tagnum == 0xA003) { if (tagnum == 0xA002) new_value = new_width; /* ExifImageWidth Tag */ else new_value = new_height; /* ExifImageHeight Tag */ if (is_motorola) { data[offset+2] = 0; /* Format = unsigned long (4 octets) */ data[offset+3] = 4; data[offset+4] = 0; /* Number Of Components = 1 */ data[offset+5] = 0; data[offset+6] = 0; data[offset+7] = 1; data[offset+8] = 0; data[offset+9] = 0; data[offset+10] = (JOCTET)((new_value >> 8) & 0xFF); data[offset+11] = (JOCTET)(new_value & 0xFF); } else { data[offset+2] = 4; /* Format = unsigned long (4 octets) */ data[offset+3] = 0; data[offset+4] = 1; /* Number Of Components = 1 */ data[offset+5] = 0; data[offset+6] = 0; data[offset+7] = 0; data[offset+8] = (JOCTET)(new_value & 0xFF); data[offset+9] = (JOCTET)((new_value >> 8) & 0xFF); data[offset+10] = 0; data[offset+11] = 0; } } offset += 12; } while (--number_of_tags); } /* Adjust output image parameters as needed. * * This must be called after jpeg_copy_critical_parameters() * and before jpeg_write_coefficients(). * * The return value is the set of virtual coefficient arrays to be written * (either the ones allocated by jtransform_request_workspace, or the * original source data arrays). The caller will need to pass this value * to jpeg_write_coefficients(). */ GLOBAL(jvirt_barray_ptr *) jtransform_adjust_parameters (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info) { /* If force-to-grayscale is requested, adjust destination parameters */ if (info->force_grayscale) { /* First, ensure we have YCbCr or grayscale data, and that the source's * Y channel is full resolution. (No reasonable person would make Y * be less than full resolution, so actually coping with that case * isn't worth extra code space. But we check it to avoid crashing.) */ if (((dstinfo->jpeg_color_space == JCS_YCbCr && dstinfo->num_components == 3) || (dstinfo->jpeg_color_space == JCS_GRAYSCALE && dstinfo->num_components == 1)) && srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor && srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) { /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed * properly. Among other things, it sets the target h_samp_factor & * v_samp_factor to 1, which typically won't match the source. * We have to preserve the source's quantization table number, however. */ int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no; jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE); dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no; } else { /* Sorry, can't do it */ ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL); } } else if (info->num_components == 1) { /* For a single-component source, we force the destination sampling factors * to 1x1, with or without force_grayscale. This is useful because some * decoders choke on grayscale images with other sampling factors. */ dstinfo->comp_info[0].h_samp_factor = 1; dstinfo->comp_info[0].v_samp_factor = 1; } /* Correct the destination's image dimensions as necessary * for crop and rotate/flip operations. */ dstinfo->image_width = info->output_width; dstinfo->image_height = info->output_height; /* Transpose destination image parameters */ switch (info->transform) { case JXFORM_TRANSPOSE: case JXFORM_TRANSVERSE: case JXFORM_ROT_90: case JXFORM_ROT_270: transpose_critical_parameters(dstinfo); break; default: break; } /* Adjust Exif properties */ if (srcinfo->marker_list != NULL && srcinfo->marker_list->marker == JPEG_APP0+1 && srcinfo->marker_list->data_length >= 6 && GETJOCTET(srcinfo->marker_list->data[0]) == 0x45 && GETJOCTET(srcinfo->marker_list->data[1]) == 0x78 && GETJOCTET(srcinfo->marker_list->data[2]) == 0x69 && GETJOCTET(srcinfo->marker_list->data[3]) == 0x66 && GETJOCTET(srcinfo->marker_list->data[4]) == 0 && GETJOCTET(srcinfo->marker_list->data[5]) == 0) { /* Suppress output of JFIF marker */ dstinfo->write_JFIF_header = FALSE; /* Adjust Exif image parameters */ if (dstinfo->image_width != srcinfo->image_width || dstinfo->image_height != srcinfo->image_height) /* Align data segment to start of TIFF structure for parsing */ adjust_exif_parameters(srcinfo->marker_list->data + 6, srcinfo->marker_list->data_length - 6, dstinfo->image_width, dstinfo->image_height); } /* Return the appropriate output data set */ if (info->workspace_coef_arrays != NULL) return info->workspace_coef_arrays; return src_coef_arrays; } /* Execute the actual transformation, if any. * * This must be called *after* jpeg_write_coefficients, because it depends * on jpeg_write_coefficients to have computed subsidiary values such as * the per-component width and height fields in the destination object. * * Note that some transformations will modify the source data arrays! */ GLOBAL(void) jtransform_execute_transform (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info) { jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays; /* Note: conditions tested here should match those in switch statement * in jtransform_request_workspace() */ switch (info->transform) { case JXFORM_NONE: if (info->x_crop_offset != 0 || info->y_crop_offset != 0) do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_FLIP_H: if (info->y_crop_offset != 0) do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); else do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset, src_coef_arrays); break; case JXFORM_FLIP_V: do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_TRANSPOSE: do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_TRANSVERSE: do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_ROT_90: do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_ROT_180: do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; case JXFORM_ROT_270: do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset, src_coef_arrays, dst_coef_arrays); break; } } /* jtransform_perfect_transform * * Determine whether lossless transformation is perfectly * possible for a specified image and transformation. * * Inputs: * image_width, image_height: source image dimensions. * MCU_width, MCU_height: pixel dimensions of MCU. * transform: transformation identifier. * Parameter sources from initialized jpeg_struct * (after reading source header): * image_width = cinfo.image_width * image_height = cinfo.image_height * MCU_width = cinfo.max_h_samp_factor * DCTSIZE * MCU_height = cinfo.max_v_samp_factor * DCTSIZE * Result: * TRUE = perfect transformation possible * FALSE = perfect transformation not possible * (may use custom action then) */ GLOBAL(boolean) jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height, int MCU_width, int MCU_height, JXFORM_CODE transform) { boolean result = TRUE; /* initialize TRUE */ switch (transform) { case JXFORM_FLIP_H: case JXFORM_ROT_270: if (image_width % (JDIMENSION) MCU_width) result = FALSE; break; case JXFORM_FLIP_V: case JXFORM_ROT_90: if (image_height % (JDIMENSION) MCU_height) result = FALSE; break; case JXFORM_TRANSVERSE: case JXFORM_ROT_180: if (image_width % (JDIMENSION) MCU_width) result = FALSE; if (image_height % (JDIMENSION) MCU_height) result = FALSE; break; default: break; } return result; } #endif /* TRANSFORMS_SUPPORTED */ /* Setup decompression object to save desired markers in memory. * This must be called before jpeg_read_header() to have the desired effect. */ GLOBAL(void) jcopy_markers_setup (j_decompress_ptr srcinfo, JCOPY_OPTION option) { #ifdef SAVE_MARKERS_SUPPORTED int m; /* Save comments except under NONE option */ if (option != JCOPYOPT_NONE) { jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF); } /* Save all types of APPn markers iff ALL option */ if (option == JCOPYOPT_ALL) { for (m = 0; m < 16; m++) jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF); } #endif /* SAVE_MARKERS_SUPPORTED */ } /* Copy markers saved in the given source object to the destination object. * This should be called just after jpeg_start_compress() or * jpeg_write_coefficients(). * Note that those routines will have written the SOI, and also the * JFIF APP0 or Adobe APP14 markers if selected. */ GLOBAL(void) jcopy_markers_execute (j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JCOPY_OPTION option) { jpeg_saved_marker_ptr marker; /* In the current implementation, we don't actually need to examine the * option flag here; we just copy everything that got saved. * But to avoid confusion, we do not output JFIF and Adobe APP14 markers * if the encoder library already wrote one. */ for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) { if (dstinfo->write_JFIF_header && marker->marker == JPEG_APP0 && marker->data_length >= 5 && GETJOCTET(marker->data[0]) == 0x4A && GETJOCTET(marker->data[1]) == 0x46 && GETJOCTET(marker->data[2]) == 0x49 && GETJOCTET(marker->data[3]) == 0x46 && GETJOCTET(marker->data[4]) == 0) continue; /* reject duplicate JFIF */ if (dstinfo->write_Adobe_marker && marker->marker == JPEG_APP0+14 && marker->data_length >= 5 && GETJOCTET(marker->data[0]) == 0x41 && GETJOCTET(marker->data[1]) == 0x64 && GETJOCTET(marker->data[2]) == 0x6F && GETJOCTET(marker->data[3]) == 0x62 && GETJOCTET(marker->data[4]) == 0x65) continue; /* reject duplicate Adobe */ #ifdef NEED_FAR_POINTERS /* We could use jpeg_write_marker if the data weren't FAR... */ { unsigned int i; jpeg_write_m_header(dstinfo, marker->marker, marker->data_length); for (i = 0; i < marker->data_length; i++) jpeg_write_m_byte(dstinfo, marker->data[i]); } #else jpeg_write_marker(dstinfo, marker->marker, marker->data, marker->data_length); #endif } } exact-image-0.9.1/codecs/xpm.hh0000644000076400007640000000206111343547354014756 0ustar renerene/* * Copyright (C) 2006 - 2008 René Rebe * * 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 "Codecs.hh" class XPMCodec : public ImageCodec { public: XPMCodec () { registerCodec ("xpm", this); }; virtual std::string getID () { return "XPM"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); }; exact-image-0.9.1/codecs/bmp.cc0000644000076400007640000006077312453513306014725 0ustar renerene/* * C++ BMP library. * Copyright (C) 2006 - 2015 René Rebe, ExactCODE GmbH Germany * * 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. * * Lossy based on (in the past more so, but more and more parts got * rewritten): * * Project: libtiff tools * Purpose: Convert Windows BMP files in TIFF. * Author: Andrey Kiselev, dron@remotesensing.org * */ #include #include "bmp.hh" #include "Colorspace.hh" #include #include #include #include #include static int last_bit_set (int v) { unsigned int i; for (i = sizeof (int) * 8 - 1; i > 0; --i) { if (v & (1L << i)) return i; } return 0; } #ifndef O_BINARY # define O_BINARY 0 #endif using Exact::EndianessConverter; using Exact::LittleEndianTraits; enum BMPType { BMPT_WIN4, /* BMP used in Windows 3.0/NT 3.51/95 */ BMPT_WIN5, /* BMP used in Windows NT 4.0/98/Me/2000/XP */ BMPT_OS21, /* BMP used in OS/2 PM 1.x */ BMPT_OS22, /* BMP used in OS/2 PM 2.x */ }; /* * Bitmap file consists of a BMPFileHeader structure followed by a * BMPInfoHeader structure. An array of BMPColorEntry structures (also called * a colour table) follows the bitmap information header structure. The colour * table is followed by a second array of indexes into the colour table (the * actual bitmap data). Data may be comressed, for 4-bpp and 8-bpp used RLE * compression. * * +---------------------+ * | BMPFileHeader | * +---------------------+ * | BMPInfoHeader | * +---------------------+ * | BMPColorEntry array | * +---------------------+ * | Colour-index array | * +---------------------+ * * All numbers stored in Intel order with least significant byte first. */ enum BMPComprMethod { BMPC_RGB = 0, /* Uncompressed */ BMPC_RLE8 = 1, /* RLE for 8 bpp images */ BMPC_RLE4 = 2, /* RLE for 4 bpp images */ BMPC_BITFIELDS = 3, /* Bitmap is not compressed and the colour table * consists of three DWORD color masks that specify * the red, green, and blue components of each * pixel. This is valid when used with * 16- and 32-bpp bitmaps. */ BMPC_JPEG = 4, /* Indicates that the image is a JPEG image. */ BMPC_PNG = 5, /* Indicates that the image is a PNG image. */ BMPC_ALPHABITFIELDS = 6, BMPC_CMYK = 11, BMPC_CMYKRLE = 12, BMPC_CMYRTLE = 13, }; enum BMPLCSType /* Type of logical color space. */ { BMPLT_CALIBRATED_RGB = 0, /* This value indicates that endpoints and * gamma values are given in the appropriate * fields. */ BMPLT_DEVICE_RGB = 1, BMPLT_DEVICE_CMYK = 2, }; #ifdef _MSC_VER #pragma pack(push, 1) #endif struct BMPCIEXYZ { int32_t iCIEX; int32_t iCIEY; int32_t iCIEZ; }; struct BMPCIEXYZTriple /* This structure contains the x, y, and z */ { /* coordinates of the three colors that */ /* correspond */ BMPCIEXYZ iCIERed; /* to the red, green, and blue endpoints for */ BMPCIEXYZ iCIEGreen; /* a specified logical color space. */ BMPCIEXYZ iCIEBlue; }; struct BMPFileHeader { char bType[2]; /* Signature "BM" */ EndianessConverter iSize; /* Size in bytes of the bitmap file. Should * always be ignored while reading because * of error in Windows 3.0 SDK's description * of this field */ uint16_t iReserved1; /* Reserved, set as 0 */ uint16_t iReserved2; /* Reserved, set as 0 */ EndianessConverter iOffBits; /* Offset of the image from file start in bytes */ } #ifdef __GNUC__ __attribute__((packed)) #endif ; struct BMPInfoHeader { EndianessConverter iSize; /* Size of BMPInfoHeader structure in bytes. * Should be used to determine start of the * colour table */ EndianessConverter iWidth; /* Image width */ EndianessConverter iHeight; /* Image height. If positive, image has bottom * left origin, if negative --- top left. */ EndianessConverter iPlanes; /* Number of image planes (must be set to 1) */ EndianessConverter iBitCount; /* Number of bits per pixel (1, 4, 8, 16, 24 * or 32). If 0 then the number of bits per * pixel is specified or is implied by the * JPEG or PNG format. */ EndianessConverter iCompression; /* Compression method */ EndianessConverter iSizeImage; /* Size of uncomressed image in bytes. May * be 0 for BMPC_RGB bitmaps. If iCompression * is BI_JPEG or BI_PNG, iSizeImage indicates * the size of the JPEG or PNG image buffer. */ EndianessConverter iXPelsPerMeter; /* X resolution, pixels per meter (0 if not used) */ EndianessConverter iYPelsPerMeter; /* Y resolution, pixels per meter (0 if not used) */ EndianessConverter iClrUsed; /* Size of colour table. If 0, iBitCount should * be used to calculate this value * (1< iClrImportant; /* Number of important colours. If 0, all * colours are required */ /* * Fields above should be used for bitmaps, compatible with Windows NT 3.51 * and earlier. Windows 98/Me, Windows 2000/XP introduces additional fields: */ EndianessConverter iRedMask; /* Colour mask that specifies the red component * of each pixel, valid only if iCompression * is set to BI_BITFIELDS. */ EndianessConverter iGreenMask; /* The same for green component */ EndianessConverter iBlueMask; /* The same for blue component */ EndianessConverter iAlphaMask; /* Colour mask that specifies the alpha * component of each pixel. */ EndianessConverter iCSType; /* Colour space of the DIB. */ BMPCIEXYZTriple sEndpoints; /* This member is ignored unless the iCSType * member specifies BMPLT_CALIBRATED_RGB. */ EndianessConverter iGammaRed; /* Toned response curve for red. This member * is ignored unless color values are * calibrated RGB values and iCSType is set to * BMPLT_CALIBRATED_RGB. Specified * in 16^16 format. */ EndianessConverter iGammaGreen; /* Toned response curve for green. */ EndianessConverter iGammaBlue; /* Toned response curve for blue. */ } #ifdef __GNUC__ __attribute__((packed)) #endif ; /* * Info header size in bytes: */ static const unsigned int BIH_OS21SIZE = 12; /* for BMPT_OS21 */ static const unsigned int BIH_OS22SIZE = 64; /* for BMPT_OS22 */ static const unsigned int BIH_WIN4SIZE = 40; /* for BMPT_WIN4 */ static const unsigned int BIH_WIN5SIZE = 56; /* for BMPT_WIN5 */ static const unsigned int BIH_V4 = 108; static const unsigned int BIH_V5 = 124; /* * We will use plain byte array instead of this structure, but declaration * provided for reference */ struct BMPColorEntry { char bBlue; char bGreen; char bRed; char bReserved; /* Must be 0 */ }; #ifdef _MSC_VER #pragma pack(pop) #endif /* * Image data in BMP file stored in BGR (or ABGR) format. We rearrange * pixels to RGB (RGBA) format. */ static void rearrangePixels(uint8_t* buf, uint32_t width, uint32_t bit_count) { uint16_t tmp; uint16_t* buf16 = (uint16_t*)buf; switch (bit_count) { case 16: /* FIXME: need a sample file */ break; case 24: for (uint32_t i = 0; i < width; i++, buf += 3) { tmp = *buf; *buf = *(buf + 2); *(buf + 2) = tmp; } break; case 48: for (uint32_t i = 0; i < width; i++, buf16 += 3) { tmp = *buf16; *buf16 = *(buf16 + 2); *(buf16 + 2) = tmp; } break; case 32: { uint8_t* buf1 = buf; for (uint32_t i = 0; i < width; i++, buf += 4) { tmp = *buf; *buf1++ = *(buf + 2); *buf1++ = *(buf + 1); *buf1++ = tmp; } } break; default: break; } } int BMPCodec::readImage (std::istream* stream, Image& image, const std::string& decompres) { BMPFileHeader file_hdr; stream->read ((char*)&file_hdr.bType, 2); if (file_hdr.bType[0] != 'B' || file_hdr.bType[1] != 'M') { stream->seekg (0); return false; } /* -------------------------------------------------------------------- */ /* Read the BMPFileHeader. We need iOffBits value only */ /* -------------------------------------------------------------------- */ stream->seekg (10); stream->read ((char*)&file_hdr.iOffBits, 4); // fix the iSize, in early BMP file this is pure garbage stream->seekg (0, std::ios::end); file_hdr.iSize = stream->tellg (); // TODO: minus the header? int i = readImageWithoutFileHeader(stream, image, decompres, &file_hdr); return i; } int BMPCodec::readImageWithoutFileHeader (std::istream* stream, Image& image, const std::string& decompres, BMPFileHeader* _file_hdr) { BMPFileHeader* file_hdr = _file_hdr; BMPFileHeader file_header; // only used if no file_hdr is supplied BMPInfoHeader info_hdr = {}; enum BMPType bmp_type; int offset = file_hdr ? sizeof(*file_hdr) : 0; uint32_t clr_tbl_size = 0, n_clr_elems = 3; uint8_t* clr_tbl = 0; uint8_t* data = 0; /* -------------------------------------------------------------------- */ /* Read the BMPInfoHeader. */ /* -------------------------------------------------------------------- */ stream->seekg (offset); stream->read ((char*)&info_hdr.iSize, 4); if (!_file_hdr) { offset = 0; file_hdr = &file_header; stream->seekg (0, std::ios::end); file_hdr->iSize = stream->tellg (); file_hdr->iOffBits = info_hdr.iSize; // assumed to follow after info header stream->seekg (offset + 4); } if (info_hdr.iSize == BIH_WIN4SIZE) bmp_type = BMPT_WIN4; else if (info_hdr.iSize == BIH_WIN5SIZE) bmp_type = BMPT_WIN5; else if (info_hdr.iSize == BIH_OS21SIZE) bmp_type = BMPT_OS21; else if (info_hdr.iSize == BIH_OS22SIZE || info_hdr.iSize == 16) bmp_type = BMPT_OS22; else { bmp_type = BMPT_WIN5; std::cerr << "Unknown header size: " << info_hdr.iSize << std::endl; } if (bmp_type == BMPT_WIN4 || bmp_type == BMPT_WIN5 || bmp_type == BMPT_OS22) { stream->read((char*)&info_hdr.iWidth, 4); stream->read((char*)&info_hdr.iHeight, 4); stream->read((char*)&info_hdr.iPlanes, 2); stream->read((char*)&info_hdr.iBitCount, 2); stream->read((char*)&info_hdr.iCompression, 4); stream->read((char*)&info_hdr.iSizeImage, 4); stream->read((char*)&info_hdr.iXPelsPerMeter, 4); stream->read((char*)&info_hdr.iYPelsPerMeter, 4); stream->read((char*)&info_hdr.iClrUsed, 4); stream->read((char*)&info_hdr.iClrImportant, 4); stream->read((char*)&info_hdr.iRedMask, 4); stream->read((char*)&info_hdr.iGreenMask, 4); stream->read((char*)&info_hdr.iBlueMask, 4); stream->read((char*)&info_hdr.iAlphaMask, 4); n_clr_elems = 4; image.setResolution((2.54 * info_hdr.iXPelsPerMeter) / 100 + .5, (2.54 * info_hdr.iYPelsPerMeter) / 100 + .5); } if (bmp_type == BMPT_OS22) { /* * FIXME: different info in different documents * regarding this! */ n_clr_elems = 3; } if (bmp_type == BMPT_OS21) { int16_t iShort; stream->read ((char*)&iShort, 2); info_hdr.iWidth = iShort; stream->read ((char*)&iShort, 2); info_hdr.iHeight = iShort; stream->read ((char*)&iShort, 2); info_hdr.iPlanes = iShort; stream->read ((char*)&iShort, 2); info_hdr.iBitCount = iShort; info_hdr.iCompression = BMPC_RGB; n_clr_elems = 3; } switch (info_hdr.iBitCount) { case 1: // case 2: case 4: case 8: case 16: case 24: case 32: case 48: break; default: std::cerr << "BMPCodec:: Cannot read " << info_hdr.iBitCount << " bit files." << std::endl; return false; } image.w = info_hdr.iWidth; image.h = std::abs(info_hdr.iHeight); // negative when upside-down switch (info_hdr.iBitCount) { case 1: case 2: case 4: case 8: image.spp = 1; image.bps = info_hdr.iBitCount; /* Allocate memory for colour table and read it. */ if (info_hdr.iClrUsed) clr_tbl_size = ((uint32_t)(1 << image.bps) < info_hdr.iClrUsed) ? 1 << image.bps : info_hdr.iClrUsed; else clr_tbl_size = 1 << image.bps; //std::cerr << "n_clr_elems: " << n_clr_elems << ", clr_tbl_size: " << clr_tbl_size << std::endl; // if we had no file_hdr, update offset to compensate for color table if (!_file_hdr) { file_hdr->iOffBits = file_hdr->iOffBits + n_clr_elems * clr_tbl_size; } clr_tbl = (uint8_t *) malloc (n_clr_elems * clr_tbl_size); if (!clr_tbl) { std::cerr << "BMPCodec:: Can't allocate space for color table" << std::endl; return false; } stream->seekg (offset + info_hdr.iSize); stream->read ((char*)clr_tbl, n_clr_elems * clr_tbl_size); /*for(clr = 0; clr < clr_tbl_size; ++clr) { printf ("%d: r: %d g: %d b: %d\n", clr, clr_tbl[clr*n_clr_elems+2], clr_tbl[clr*n_clr_elems+1], clr_tbl[clr*n_clr_elems]); }*/ break; case 16: case 24: image.spp = 3; image.bps = info_hdr.iBitCount / image.spp; break; case 32: image.spp = 3; image.bps = 8; break; case 48: image.spp = 3; image.bps = 16; break; default: break; } uint32_t stride = image.stride (); /*printf ("w: %d, h: %d, spp: %d, bps: %d, colorspace: %d\n", *w, *h, *spp, *bps, info_hdr.iCompression); */ // detect old style bitmask images if (info_hdr.iCompression == BMPC_RGB && info_hdr.iBitCount == 16) { //std::cerr << "implicit non-RGB image\n"; info_hdr.iCompression = BMPC_BITFIELDS; info_hdr.iBlueMask = 0x1f; info_hdr.iGreenMask = 0x1f << 5; info_hdr.iRedMask = 0x1f << 10; } /* -------------------------------------------------------------------- */ /* Read uncompressed image data. */ /* -------------------------------------------------------------------- */ switch (info_hdr.iCompression) { case BMPC_BITFIELDS: // we unpack bitfields to plain RGB image.bps = 8; stride = image.stride (); case BMPC_RGB: { uint32_t file_stride = ((image.w * info_hdr.iBitCount + 7) / 8 + 3) / 4 * 4; /*std::cerr << "bitcount: " << info_hdr.iBitCount << ", stride: " << stride << ", file stride: " << file_stride << std::endl; std::cerr << std::hex << "red mask: " << info_hdr.iRedMask << ", green mask: " << info_hdr.iGreenMask << ", blue mask: " << info_hdr.iBlueMask << std::dec << std::endl; */ image.resize(image.w, image.h); data = image.getRawData(); uint8_t* row_data = (uint8_t*) malloc (file_stride); if (!row_data) { std::cerr << "Can't allocate space for image buffer\n"; goto bad1; } for (uint32_t row = 0; row < (uint32_t)image.h; ++row) { std::istream::pos_type offset = file_hdr->iOffBits + row * file_stride; stream->seekg (offset); if (stream->tellg () != offset) { std::cerr << "scanline " << row << " Seek error: " << stream->tellg() << " vs " << offset << std::endl; } stream->read((char*)row_data, file_stride); if (!stream->good()) { std::cerr << "bmp read error: scanline " << row << "\n"; } else { // convert to RGB uint8_t* rgb_ptr = data + stride * (info_hdr.iHeight < 0 ? row : image.h - row - 1); if (info_hdr.iCompression == BMPC_BITFIELDS) { uint8_t* bf_ptr = row_data; const int r_shift = last_bit_set (info_hdr.iRedMask) - 7; const int g_shift = last_bit_set (info_hdr.iGreenMask) - 7; const int b_shift = last_bit_set (info_hdr.iBlueMask) - 7; const int a_shift = last_bit_set (info_hdr.iAlphaMask) - 7; for (int i = 0; i < image.w; ++i, rgb_ptr += 3) { int val = 0; for (int bits = 0; bits < info_hdr.iBitCount; bits += 8) val |= (*bf_ptr++) << bits; if (r_shift > 0) rgb_ptr[0] = (val & info_hdr.iRedMask) >> r_shift; else rgb_ptr[0] = (val & info_hdr.iRedMask) << -r_shift; if (g_shift > 0) rgb_ptr[1] = (val & info_hdr.iGreenMask) >> g_shift; else rgb_ptr[1] = (val & info_hdr.iGreenMask) << -g_shift; if (b_shift > 0) rgb_ptr[2] = (val & info_hdr.iBlueMask) >> b_shift; else rgb_ptr[2] = (val & info_hdr.iBlueMask) << -b_shift; /*if (a_shift > 0) rgb_ptr[3] = (val & info_hdr.iAlphaMask) >> a_shift; else rgb_ptr[3] = (val & info_hdr.iAlphaMask) << -a_shift;*/ } } else { rearrangePixels (row_data, image.w, info_hdr.iBitCount); memcpy (rgb_ptr, row_data, stride); } } } free(row_data); } break; /* -------------------------------------------------------------------- */ /* Read compressed image data. */ /* -------------------------------------------------------------------- */ case BMPC_RLE4: case BMPC_RLE8: { uint32_t i, j, k, runlength, x; uint32_t compr_size, uncompr_size; uint8_t *comprbuf; uint8_t *uncomprbuf; //std::cerr << "RLE" << (info_hdr.iCompression == BMPC_RLE4 ? "4" : "8") // << " compressed\n"; compr_size = file_hdr->iSize - file_hdr->iOffBits; uncompr_size = image.w * image.h; comprbuf = (uint8_t *) malloc( compr_size ); if (!comprbuf) { std::cerr << "Can't allocate space for compressed scanline buffer\n"; goto bad1; } uncomprbuf = (uint8_t *) malloc( uncompr_size ); if (!uncomprbuf) { std::cerr << "Can't allocate space for uncompressed scanline buffer\n"; goto bad1; } stream->seekg (*file_hdr->iOffBits); stream->read ((char*)comprbuf, compr_size); i = j = x = 0; while( j < uncompr_size && i < compr_size ) { if ( comprbuf[i] ) { runlength = comprbuf[i++]; for ( k = 0; runlength > 0 && j < uncompr_size && i < compr_size && x < (uint32_t)image.w; ++k, ++x) { if (info_hdr.iBitCount == 8) uncomprbuf[j++] = comprbuf[i]; else { if ( k & 0x01 ) uncomprbuf[j++] = comprbuf[i] & 0x0F; else uncomprbuf[j++] = (comprbuf[i] & 0xF0) >> 4; } runlength--; } i++; } else { i++; if ( comprbuf[i] == 0 ) { /* Next scanline */ i++; x = 0; } else if ( comprbuf[i] == 1 ) /* End of image */ break; else if ( comprbuf[i] == 2 ) { /* Move to... */ i++; if ( i < compr_size - 1 ) { j += comprbuf[i] + comprbuf[i+1] * image.w; i += 2; } else break; } else { /* Absolute mode */ runlength = comprbuf[i++]; for ( k = 0; k < runlength && j < uncompr_size && i < compr_size; k++, x++) { if (info_hdr.iBitCount == 8) uncomprbuf[j++] = comprbuf[i++]; else { if ( k & 0x01 ) uncomprbuf[j++] = comprbuf[i++] & 0x0F; else uncomprbuf[j++] = (comprbuf[i] & 0xF0) >> 4; } } /* word boundary alignment */ if (info_hdr.iBitCount == 4) k /= 2; if ( k & 0x01 ) i++; } } } free(comprbuf); data = (uint8_t *) malloc( uncompr_size ); if (!data) { std::cerr << "Can't allocate space for final uncompressed scanline buffer\n"; goto bad1; } // TODO: suboptimal, later improve the above to yield the corrent orientation natively for (uint32_t row = 0; row < (uint32_t)image.h; ++row) { memcpy (data + row * image.w, uncomprbuf + (image.h - 1 - row) * image.w, image.w); rearrangePixels(data + row * image.w, image.w, info_hdr.iBitCount); } free(uncomprbuf); image.bps = 8; } image.setRawData(data); break; } /* switch */ // convert to RGB color-space - we do not handle palette images internally // no color table anyway or RGB* ? if (clr_tbl && image.spp < 3) { uint16_t* rmap = new uint16_t [clr_tbl_size]; uint16_t* gmap = new uint16_t [clr_tbl_size]; uint16_t* bmap = new uint16_t [clr_tbl_size]; for (unsigned int i = 0; i < clr_tbl_size; ++i) { // BMP maps have BGR order ... rmap[i] = 0x101 * clr_tbl[i * n_clr_elems + 2]; gmap[i] = 0x101 * clr_tbl[i * n_clr_elems + 1]; bmap[i] = 0x101 * clr_tbl[i * n_clr_elems + 0]; } colorspace_de_palette (image, clr_tbl_size, rmap, gmap, bmap); delete[] (rmap); delete[] (gmap); delete[] (bmap); free(clr_tbl); clr_tbl = NULL; } return true; bad1: if (clr_tbl) free(clr_tbl); clr_tbl = NULL; return false; } bool BMPCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { const int hdr_size = image.spp == 4 ? BIH_WIN5SIZE : BIH_WIN4SIZE; const unsigned stride = image.stride(); const int n_clr_elems = 4; // we write "modern" formats, not the vintage OS/2 flavour if (image.bps > 16 || image.bps == 2 || image.spp > 4) { std::cerr << "BMPCodec: " << image.bps << " bits and " << image.spp << " samples not supported." << std::endl; return false; } BMPFileHeader file_hdr; BMPInfoHeader info_hdr; memset (&file_hdr, 0, sizeof (file_hdr)); memset (&info_hdr, 0, sizeof (info_hdr)); // BMPFileHeader file_hdr.bType[0] = 'B'; file_hdr.bType[1] = 'M'; // BMPInfoHeader info_hdr.iSize = hdr_size; info_hdr.iWidth = image.w; info_hdr.iHeight = image.h; info_hdr.iPlanes = 1; info_hdr.iBitCount = image.spp * image.bps; info_hdr.iCompression = BMPC_RGB; info_hdr.iSizeImage = image.stride()*image.h; // TODO: compressed size info_hdr.iXPelsPerMeter = (int32_t) (100. * image.resolutionX() / 2.54 + .5); info_hdr.iYPelsPerMeter = (int32_t) (100. * image.resolutionY() / 2.54 + .5); info_hdr.iClrUsed = image.spp == 1 ? 1 << image.bps : 0; info_hdr.iClrImportant = 0; info_hdr.iRedMask = 0; info_hdr.iGreenMask = 0; info_hdr.iBlueMask = 0; info_hdr.iAlphaMask = 0; // BMP image payload needs to be 4 byte aligned :-( int file_stride = ((image.w * info_hdr.iBitCount + 7) / 8 + 3) / 4 * 4; file_hdr.iOffBits = sizeof(file_hdr) + hdr_size + info_hdr.iClrUsed * n_clr_elems; file_hdr.iSize = file_hdr.iOffBits + file_stride * image.h; // write header meta info stream->write ((char*)&file_hdr, sizeof(file_hdr)); stream->write ((char*)&info_hdr, hdr_size); // write color table if (info_hdr.iClrUsed) { int n = info_hdr.iClrUsed; #ifdef _MSC_VER std::vector _clrtbl(n_clr_elems*n); uint8_t* clrtbl = &_clrtbl[0]; #else uint8_t clrtbl [n_clr_elems*n]; #endif for (int i = 0; i < n; ++i) { clrtbl[n_clr_elems*i+0] = clrtbl[n_clr_elems*i+1] = clrtbl[n_clr_elems*i+2] = i * 0xff / (n - 1); for (int j = 3; j < n_clr_elems; ++j) clrtbl[n_clr_elems*i+j] = 0; } stream->write ((char*)clrtbl, n_clr_elems*n); } // write image data switch (info_hdr.iCompression) { case BMPC_RGB: { #ifdef _MSC_VER std::vector _payload(file_stride); uint8_t* payload = &_payload[0]; #else uint8_t payload [file_stride]; #endif for (int row = image.h-1; row >=0; --row) { memcpy (payload, image.getRawData() + stride*row, stride); rearrangePixels (payload, image.w, info_hdr.iBitCount); if (!stream->write ((char*)payload, file_stride)) { std::cerr << "scanline " << row << " write error" << std::endl; return false; } } } break; default: std::cerr << "unsupported compression method writing bmp" << std::endl; return false; } /* switch */ return true; } BMPCodec bmp_loader; exact-image-0.9.1/codecs/agg_svg_path_renderer.cc0000644000076400007640000002764411027657125020472 0ustar renerene//---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // SVG path renderer. // //---------------------------------------------------------------------------- /* * Copyright (c) 2008 Rene Rebe * Added support for parsing arc's. */ #include "agg_svg_path_renderer.hh" namespace agg { namespace svg { //------------------------------------------------------------------------ path_renderer::path_renderer() : m_curved(m_storage), m_curved_count(m_curved), m_curved_stroked(m_curved_count), m_curved_stroked_trans(m_curved_stroked, m_transform), m_curved_trans(m_curved_count, m_transform), m_curved_trans_contour(m_curved_trans) { m_curved_trans_contour.auto_detect_orientation(false); } //------------------------------------------------------------------------ void path_renderer::remove_all() { m_storage.remove_all(); m_attr_storage.remove_all(); m_attr_stack.remove_all(); m_transform.reset(); } //------------------------------------------------------------------------ void path_renderer::begin_path() { push_attr(); unsigned idx = m_storage.start_new_path(); m_attr_storage.add(path_attributes(cur_attr(), idx)); } //------------------------------------------------------------------------ void path_renderer::end_path() { if(m_attr_storage.size() == 0) { throw exception("end_path : The path was not begun"); } path_attributes attr = cur_attr(); unsigned idx = m_attr_storage[m_attr_storage.size() - 1].index; attr.index = idx; m_attr_storage[m_attr_storage.size() - 1] = attr; pop_attr(); } //------------------------------------------------------------------------ void path_renderer::move_to(double x, double y, bool rel) // M, m { if(rel) m_storage.rel_to_abs(&x, &y); m_storage.move_to(x, y); } //------------------------------------------------------------------------ void path_renderer::line_to(double x, double y, bool rel) // L, l { if(rel) m_storage.rel_to_abs(&x, &y); m_storage.line_to(x, y); } //------------------------------------------------------------------------ void path_renderer::hline_to(double x, bool rel) // H, h { double x2 = 0.0; double y2 = 0.0; if(m_storage.total_vertices()) { m_storage.vertex(m_storage.total_vertices() - 1, &x2, &y2); if(rel) x += x2; m_storage.line_to(x, y2); } } //------------------------------------------------------------------------ void path_renderer::vline_to(double y, bool rel) // V, v { double x2 = 0.0; double y2 = 0.0; if(m_storage.total_vertices()) { m_storage.vertex(m_storage.total_vertices() - 1, &x2, &y2); if(rel) y += y2; m_storage.line_to(x2, y); } } //------------------------------------------------------------------------ void path_renderer::curve3(double x1, double y1, // Q, q double x, double y, bool rel) { if(rel) { m_storage.rel_to_abs(&x1, &y1); m_storage.rel_to_abs(&x, &y); } m_storage.curve3(x1, y1, x, y); } //------------------------------------------------------------------------ void path_renderer::curve3(double x, double y, bool rel) // T, t { if(rel) { m_storage.curve3_rel(x, y); } else { m_storage.curve3(x, y); } } //------------------------------------------------------------------------ void path_renderer::curve4(double x1, double y1, // C, c double x2, double y2, double x, double y, bool rel) { if(rel) { m_storage.rel_to_abs(&x1, &y1); m_storage.rel_to_abs(&x2, &y2); m_storage.rel_to_abs(&x, &y); } m_storage.curve4(x1, y1, x2, y2, x, y); } //------------------------------------------------------------------------ void path_renderer::curve4(double x2, double y2, // S, s double x, double y, bool rel) { if(rel) { m_storage.curve4_rel(x2, y2, x, y); } else { m_storage.curve4(x2, y2, x, y); } } //------------------------------------------------------------------------ void path_renderer::arc(double rx, double ry, double angle, bool large_arc_flag, bool sweep_flag, double x, double y, bool rel) { angle = deg2rad (angle); if(rel) { m_storage.arc_rel(rx, ry, angle, large_arc_flag, sweep_flag, x, y); } else { m_storage.arc_to(rx, ry, angle, large_arc_flag, sweep_flag, x, y); } } //------------------------------------------------------------------------ void path_renderer::close_subpath() { m_storage.end_poly(path_flags_close); } //------------------------------------------------------------------------ path_attributes& path_renderer::cur_attr() { if(m_attr_stack.size() == 0) { throw exception("cur_attr : Attribute stack is empty"); } return m_attr_stack[m_attr_stack.size() - 1]; } //------------------------------------------------------------------------ void path_renderer::push_attr() { m_attr_stack.add(m_attr_stack.size() ? m_attr_stack[m_attr_stack.size() - 1] : path_attributes()); } //------------------------------------------------------------------------ void path_renderer::pop_attr() { if(m_attr_stack.size() == 0) { throw exception("pop_attr : Attribute stack is empty"); } m_attr_stack.remove_last(); } //------------------------------------------------------------------------ void path_renderer::fill(const rgba8& f) { path_attributes& attr = cur_attr(); attr.fill_color = f; attr.fill_flag = true; } //------------------------------------------------------------------------ void path_renderer::stroke(const rgba8& s) { path_attributes& attr = cur_attr(); attr.stroke_color = s; attr.stroke_flag = true; } //------------------------------------------------------------------------ void path_renderer::even_odd(bool flag) { cur_attr().even_odd_flag = flag; } //------------------------------------------------------------------------ void path_renderer::stroke_width(double w) { cur_attr().stroke_width = w; } //------------------------------------------------------------------------ void path_renderer::fill_none() { cur_attr().fill_flag = false; } //------------------------------------------------------------------------ void path_renderer::stroke_none() { cur_attr().stroke_flag = false; } //------------------------------------------------------------------------ void path_renderer::fill_opacity(double op) { cur_attr().fill_color.opacity(op); } //------------------------------------------------------------------------ void path_renderer::stroke_opacity(double op) { cur_attr().stroke_color.opacity(op); } //------------------------------------------------------------------------ void path_renderer::line_join(line_join_e join) { cur_attr().line_join = join; } //------------------------------------------------------------------------ void path_renderer::line_cap(line_cap_e cap) { cur_attr().line_cap = cap; } //------------------------------------------------------------------------ void path_renderer::miter_limit(double ml) { cur_attr().miter_limit = ml; } //------------------------------------------------------------------------ trans_affine& path_renderer::transform() { return cur_attr().transform; } //------------------------------------------------------------------------ void path_renderer::parse_path(path_tokenizer& tok) { while(tok.next()) { double arg[10]; char cmd = tok.last_command(); unsigned i; switch(cmd) { case 'M': case 'm': arg[0] = tok.last_number(); arg[1] = tok.next(cmd); move_to(arg[0], arg[1], cmd == 'm'); break; case 'L': case 'l': arg[0] = tok.last_number(); arg[1] = tok.next(cmd); line_to(arg[0], arg[1], cmd == 'l'); break; case 'V': case 'v': vline_to(tok.last_number(), cmd == 'v'); break; case 'H': case 'h': hline_to(tok.last_number(), cmd == 'h'); break; case 'Q': case 'q': arg[0] = tok.last_number(); for(i = 1; i < 4; i++) { arg[i] = tok.next(cmd); } curve3(arg[0], arg[1], arg[2], arg[3], cmd == 'q'); break; case 'T': case 't': arg[0] = tok.last_number(); arg[1] = tok.next(cmd); curve3(arg[0], arg[1], cmd == 't'); break; case 'C': case 'c': arg[0] = tok.last_number(); for(i = 1; i < 6; i++) { arg[i] = tok.next(cmd); } curve4(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], cmd == 'c'); break; case 'S': case 's': arg[0] = tok.last_number(); for(i = 1; i < 4; i++) { arg[i] = tok.next(cmd); } curve4(arg[0], arg[1], arg[2], arg[3], cmd == 's'); break; case 'A': case 'a': arg[0] = tok.last_number(); for(i = 1; i < 7; ++i) { arg[i] = tok.next(cmd); } arc(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], cmd == 'a'); break; case 'Z': case 'z': close_subpath(); break; default: { char buf[100]; sprintf(buf, "parse_path: Invalid Command %c", cmd); throw exception(buf); } } } } } } exact-image-0.9.1/codecs/pdf.hh0000644000076400007640000000502711737001650014717 0ustar renerene/* * Copyright (c) 2008 Susanne Klaus * Copyright (c) 2008 Rene Rebe * * 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 #include "Codecs.hh" struct PDFContext; // fwd class PDFCodec : public ImageCodec { public: PDFCodec () : context(0) { registerCodec ("pdf", this); }; ~PDFCodec (); // freestanding PDFCodec (std::ostream* s); virtual std::string getID () { return "PDF"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); // direct PDF stream creation, including vector objects and // multiple pages enum filling_rule_t { fill_non_zero = (1<<0), fill_even_odd = (1<<1), fill_none = 0xff }; void beginPage(double, double); void moveTo(double x, double y); void addLineTo(double x, double y); void closePath(); void addCurveTo(double x1, double y1, double x2, double y2, double x3, double y3); void setFillColor(double r, double g, double b); void setLineWidth(double width); void setLineDash(double offset, const std::vector& dashes); void setLineDash(double offset, const double* dashes, int n); void showPath(filling_rule_t fill = fill_none); /* Default font names, as per PDF Reference: Times-Roman, Times-Bold, Times-Italic, Times-BoldItalic, Helvetica, Helvetica-Bold, Helvetica-Oblique, Helvetica-BoldOblique, Courier, Courier-Bold, Courier-Oblique, Courier-BoldOblique, Symbol, ZapfDingbats */ void beginText(); void textTo(double x, double y); void showText(const std::string& font, const std::string& text, double height); void showImage(Image& image, double x, double y, double width, double height, int quality = 80, const std::string& compress = ""); void endText(); private: PDFContext* context; }; exact-image-0.9.1/codecs/raw.hh0000644000076400007640000000212011343547354014737 0ustar renerene/* * Copyright (C) 2006 - 2008 René Rebe * * 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. * * All rights reserved. Commercial licensing options are * available from the copyright holder ExactCODE GmbH Germany. */ #include "Codecs.hh" class RAWCodec : public ImageCodec { public: RAWCodec () { registerCodec ("raw", this, true /* explicit only */); }; virtual std::string getID () { return "RAW data"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); }; exact-image-0.9.1/codecs/agg_svg_parser.hh0000644000076400007640000000573211027657215017150 0ustar renerene//---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // SVG parser. // //---------------------------------------------------------------------------- /* * Copyright (c) 2008 Rene Rebe * Adapted for std::istream, and int precision warning.y */ #ifndef AGG_SVG_PARSER_INCLUDED #define AGG_SVG_PARSER_INCLUDED #include #include "agg_svg_path_tokenizer.hh" #include "agg_svg_path_renderer.hh" namespace agg { namespace svg { class parser { enum buf_size_e { buf_size = BUFSIZ }; public: ~parser(); parser(path_renderer& path); void parse(std::istream& stream); const char* title() const { return m_title; } private: // XML event handlers static void start_element(void* data, const char* el, const char** attr); static void end_element(void* data, const char* el); static void content(void* data, const char* s, int len); void parse_attr(const char** attr); void parse_path(const char** attr); void parse_poly(const char** attr, bool close_flag); void parse_circle(const char** attr); void parse_ellipse(const char** attr); void parse_rect(const char** attr); void parse_line(const char** attr); void parse_style(const char* str); void parse_transform(const char* str); unsigned parse_matrix(const char* str); unsigned parse_translate(const char* str); unsigned parse_rotate(const char* str); unsigned parse_scale(const char* str); unsigned parse_skew_x(const char* str); unsigned parse_skew_y(const char* str); bool parse_attr(const char* name, const char* value); bool parse_name_value(const char* nv_start, const char* nv_end); void copy_name(const char* start, const char* end); void copy_value(const char* start, const char* end); private: path_renderer& m_path; path_tokenizer m_tokenizer; char* m_buf; char* m_title; unsigned m_title_len; bool m_title_flag; bool m_path_flag; char* m_attr_name; char* m_attr_value; unsigned m_attr_name_len; unsigned m_attr_value_len; }; } } #endif exact-image-0.9.1/codecs/pcx.hh0000644000076400007640000000204412422531462014735 0ustar renerene/* * Copyright (C) 2008 - 2014 René Rebe * * 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 "Codecs.hh" class PCXCodec : public ImageCodec { public: PCXCodec () { registerCodec ("pcx", this); }; virtual std::string getID () { return "PCX"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompress); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); }; exact-image-0.9.1/codecs/Makefile0000644000076400007640000000203511603164515015263 0ustar renereneinclude build/top.make ifeq "$(WITHLIBJPEG)" "1" LDFLAGS += -ljpeg else NOT_SRCS += jpeg.cc transupp.c endif ifeq "$(WITHLIBTIFF)" "1" LDFLAGS += -ltiff # -ltiffxx else NOT_SRCS += tiff.cc endif ifeq "$(WITHLIBPNG)" "1" LDFLAGS += -lpng else NOT_SRCS += png.cc endif ifeq "$(WITHLIBUNGIF)" "1" LDFLAGS += -lungif else NOT_SRCS += gif.cc endif ifeq "$(WITHJASPER)" "1" LDFLAGS += -ljasper else NOT_SRCS += jpeg2000.cc endif ifeq "$(WITHOPENEXR)" "1" CPPFLAGS += $(OPENEXRINCS) LDFLAGS += $(OPENEXRLIBS) else NOT_SRCS += openexr.cc endif ifeq "$(WITHLCMS)" "1" LDFLAGS += $(LCMSLIBS) endif ifeq "$(WITHEXPAT)" "1" LDFLAGS += $(EXPATLIBS) else NOT_SRCS += agg_svg_parser.cc agg_svg_path_renderer.cc \ agg_svg_path_tokenizer.cc svg.cc endif ifeq "$(PCX)" "0" NOT_SRCS += pcx.cc endif ifeq "$(TGA)" "0" NOT_SRCS += tga.cc endif BINARY = lib BINARY_EXT = $(X_LIBEXT) DEPS = CPPFLAGS += -I codecs/ LDFLAGS += -lz # for the PDF compression, TODO: check for availability and disable the support code otherwise include build/bottom.make exact-image-0.9.1/codecs/agg_svg_parser.cc0000644000076400007640000007101111027657215017127 0ustar renerene//---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // SVG parser. // //---------------------------------------------------------------------------- /* * Copyright (c) 2008 Rene Rebe * Adapted for std::istream, and int precision warning, * added ellipse and circle. */ #include #include #include "agg_svg_parser.hh" #include "expat.h" namespace agg { namespace svg { struct named_color { char name[22]; int8u r, g, b, a; }; named_color colors[] = { { "aliceblue",240,248,255, 255 }, { "antiquewhite",250,235,215, 255 }, { "aqua",0,255,255, 255 }, { "aquamarine",127,255,212, 255 }, { "azure",240,255,255, 255 }, { "beige",245,245,220, 255 }, { "bisque",255,228,196, 255 }, { "black",0,0,0, 255 }, { "blanchedalmond",255,235,205, 255 }, { "blue",0,0,255, 255 }, { "blueviolet",138,43,226, 255 }, { "brown",165,42,42, 255 }, { "burlywood",222,184,135, 255 }, { "cadetblue",95,158,160, 255 }, { "chartreuse",127,255,0, 255 }, { "chocolate",210,105,30, 255 }, { "coral",255,127,80, 255 }, { "cornflowerblue",100,149,237, 255 }, { "cornsilk",255,248,220, 255 }, { "crimson",220,20,60, 255 }, { "cyan",0,255,255, 255 }, { "darkblue",0,0,139, 255 }, { "darkcyan",0,139,139, 255 }, { "darkgoldenrod",184,134,11, 255 }, { "darkgray",169,169,169, 255 }, { "darkgreen",0,100,0, 255 }, { "darkgrey",169,169,169, 255 }, { "darkkhaki",189,183,107, 255 }, { "darkmagenta",139,0,139, 255 }, { "darkolivegreen",85,107,47, 255 }, { "darkorange",255,140,0, 255 }, { "darkorchid",153,50,204, 255 }, { "darkred",139,0,0, 255 }, { "darksalmon",233,150,122, 255 }, { "darkseagreen",143,188,143, 255 }, { "darkslateblue",72,61,139, 255 }, { "darkslategray",47,79,79, 255 }, { "darkslategrey",47,79,79, 255 }, { "darkturquoise",0,206,209, 255 }, { "darkviolet",148,0,211, 255 }, { "deeppink",255,20,147, 255 }, { "deepskyblue",0,191,255, 255 }, { "dimgray",105,105,105, 255 }, { "dimgrey",105,105,105, 255 }, { "dodgerblue",30,144,255, 255 }, { "firebrick",178,34,34, 255 }, { "floralwhite",255,250,240, 255 }, { "forestgreen",34,139,34, 255 }, { "fuchsia",255,0,255, 255 }, { "gainsboro",220,220,220, 255 }, { "ghostwhite",248,248,255, 255 }, { "gold",255,215,0, 255 }, { "goldenrod",218,165,32, 255 }, { "gray",128,128,128, 255 }, { "green",0,128,0, 255 }, { "greenyellow",173,255,47, 255 }, { "grey",128,128,128, 255 }, { "honeydew",240,255,240, 255 }, { "hotpink",255,105,180, 255 }, { "indianred",205,92,92, 255 }, { "indigo",75,0,130, 255 }, { "ivory",255,255,240, 255 }, { "khaki",240,230,140, 255 }, { "lavender",230,230,250, 255 }, { "lavenderblush",255,240,245, 255 }, { "lawngreen",124,252,0, 255 }, { "lemonchiffon",255,250,205, 255 }, { "lightblue",173,216,230, 255 }, { "lightcoral",240,128,128, 255 }, { "lightcyan",224,255,255, 255 }, { "lightgoldenrodyellow",250,250,210, 255 }, { "lightgray",211,211,211, 255 }, { "lightgreen",144,238,144, 255 }, { "lightgrey",211,211,211, 255 }, { "lightpink",255,182,193, 255 }, { "lightsalmon",255,160,122, 255 }, { "lightseagreen",32,178,170, 255 }, { "lightskyblue",135,206,250, 255 }, { "lightslategray",119,136,153, 255 }, { "lightslategrey",119,136,153, 255 }, { "lightsteelblue",176,196,222, 255 }, { "lightyellow",255,255,224, 255 }, { "lime",0,255,0, 255 }, { "limegreen",50,205,50, 255 }, { "linen",250,240,230, 255 }, { "magenta",255,0,255, 255 }, { "maroon",128,0,0, 255 }, { "mediumaquamarine",102,205,170, 255 }, { "mediumblue",0,0,205, 255 }, { "mediumorchid",186,85,211, 255 }, { "mediumpurple",147,112,219, 255 }, { "mediumseagreen",60,179,113, 255 }, { "mediumslateblue",123,104,238, 255 }, { "mediumspringgreen",0,250,154, 255 }, { "mediumturquoise",72,209,204, 255 }, { "mediumvioletred",199,21,133, 255 }, { "midnightblue",25,25,112, 255 }, { "mintcream",245,255,250, 255 }, { "mistyrose",255,228,225, 255 }, { "moccasin",255,228,181, 255 }, { "navajowhite",255,222,173, 255 }, { "navy",0,0,128, 255 }, { "oldlace",253,245,230, 255 }, { "olive",128,128,0, 255 }, { "olivedrab",107,142,35, 255 }, { "orange",255,165,0, 255 }, { "orangered",255,69,0, 255 }, { "orchid",218,112,214, 255 }, { "palegoldenrod",238,232,170, 255 }, { "palegreen",152,251,152, 255 }, { "paleturquoise",175,238,238, 255 }, { "palevioletred",219,112,147, 255 }, { "papayawhip",255,239,213, 255 }, { "peachpuff",255,218,185, 255 }, { "peru",205,133,63, 255 }, { "pink",255,192,203, 255 }, { "plum",221,160,221, 255 }, { "powderblue",176,224,230, 255 }, { "purple",128,0,128, 255 }, { "red",255,0,0, 255 }, { "rosybrown",188,143,143, 255 }, { "royalblue",65,105,225, 255 }, { "saddlebrown",139,69,19, 255 }, { "salmon",250,128,114, 255 }, { "sandybrown",244,164,96, 255 }, { "seagreen",46,139,87, 255 }, { "seashell",255,245,238, 255 }, { "sienna",160,82,45, 255 }, { "silver",192,192,192, 255 }, { "skyblue",135,206,235, 255 }, { "slateblue",106,90,205, 255 }, { "slategray",112,128,144, 255 }, { "slategrey",112,128,144, 255 }, { "snow",255,250,250, 255 }, { "springgreen",0,255,127, 255 }, { "steelblue",70,130,180, 255 }, { "tan",210,180,140, 255 }, { "teal",0,128,128, 255 }, { "thistle",216,191,216, 255 }, { "tomato",255,99,71, 255 }, { "turquoise",64,224,208, 255 }, { "violet",238,130,238, 255 }, { "wheat",245,222,179, 255 }, { "white",255,255,255, 255 }, { "whitesmoke",245,245,245, 255 }, { "yellow",255,255,0, 255 }, { "yellowgreen",154,205,50, 255 }, { "zzzzzzzzzzz",0,0,0, 0 } }; //------------------------------------------------------------------------ parser::~parser() { delete [] m_attr_value; delete [] m_attr_name; delete [] m_buf; delete [] m_title; } //------------------------------------------------------------------------ parser::parser(path_renderer& path) : m_path(path), m_tokenizer(), m_buf(new char[buf_size]), m_title(new char[256]), m_title_len(0), m_title_flag(false), m_path_flag(false), m_attr_name(new char[128]), m_attr_value(new char[1024]), m_attr_name_len(127), m_attr_value_len(1023) { m_title[0] = 0; } //------------------------------------------------------------------------ void parser::parse(std::istream& stream) { char msg[1024]; XML_Parser p = XML_ParserCreate(NULL); if(p == 0) { throw exception("Couldn't allocate memory for parser"); } XML_SetUserData(p, this); XML_SetElementHandler(p, start_element, end_element); XML_SetCharacterDataHandler(p, content); bool done = false; do { size_t len = stream.readsome (m_buf, buf_size); // trigger eof stream.peek(); done = stream.eof(); if(!XML_Parse(p, m_buf, len, done)) { sprintf(msg, "%s at line %ld\n", XML_ErrorString(XML_GetErrorCode(p)), (long)XML_GetCurrentLineNumber(p)); throw exception(msg); } } while(!done); XML_ParserFree(p); char* ts = m_title; while(*ts) { if(*ts < ' ') *ts = ' '; ++ts; } } //------------------------------------------------------------------------ void parser::start_element(void* data, const char* el, const char** attr) { parser& self = *(parser*)data; if(strcmp(el, "title") == 0) { self.m_title_flag = true; } else if(strcmp(el, "g") == 0) { self.m_path.push_attr(); self.parse_attr(attr); } else if(strcmp(el, "path") == 0) { if(self.m_path_flag) { throw exception("start_element: Nested path"); } self.m_path.begin_path(); self.parse_path(attr); self.m_path.end_path(); self.m_path_flag = true; } else if(strcmp(el, "rect") == 0) { self.parse_rect(attr); } else if(strcmp(el, "line") == 0) { self.parse_line(attr); } else if(strcmp(el, "polyline") == 0) { self.parse_poly(attr, false); } else if(strcmp(el, "polygon") == 0) { self.parse_poly(attr, true); } else if(strcmp(el, "circle") == 0) { self.parse_circle(attr); } else if(strcmp(el, "ellipse") == 0) { self.parse_ellipse(attr); } // TODO: text, tspan, ... //else //if(strcmp(el, "") == 0) //{ //} } //------------------------------------------------------------------------ void parser::end_element(void* data, const char* el) { parser& self = *(parser*)data; if(strcmp(el, "title") == 0) { self.m_title_flag = false; } else if(strcmp(el, "g") == 0) { self.m_path.pop_attr(); } else if(strcmp(el, "path") == 0) { self.m_path_flag = false; } //else //if(strcmp(el, "") == 0) //{ //} // . . . } //------------------------------------------------------------------------ void parser::content(void* data, const char* s, int len) { parser& self = *(parser*)data; // m_title_flag signals that the tag is being parsed now. // The following code concatenates the pieces of content of the <title> tag. if(self.m_title_flag) { if(len + self.m_title_len > 255) len = 255 - self.m_title_len; if(len > 0) { memcpy(self.m_title + self.m_title_len, s, len); self.m_title_len += len; self.m_title[self.m_title_len] = 0; } } } //------------------------------------------------------------------------ void parser::parse_attr(const char** attr) { int i; for(i = 0; attr[i]; i += 2) { if(strcmp(attr[i], "style") == 0) { parse_style(attr[i + 1]); } else { parse_attr(attr[i], attr[i + 1]); } } } //------------------------------------------------------------- void parser::parse_path(const char** attr) { int i; for(i = 0; attr[i]; i += 2) { // The <path> tag can consist of the path itself ("d=") // as well as of other parameters like "style=", "transform=", etc. // In the last case we simply rely on the function of parsing // attributes (see 'else' branch). if(strcmp(attr[i], "d") == 0) { m_tokenizer.set_path_str(attr[i + 1]); m_path.parse_path(m_tokenizer); } else { // Create a temporary single pair "name-value" in order // to avoid multiple calls for the same attribute. const char* tmp[4]; tmp[0] = attr[i]; tmp[1] = attr[i + 1]; tmp[2] = 0; tmp[3] = 0; parse_attr(tmp); } } } //------------------------------------------------------------- int cmp_color(const void* p1, const void* p2) { return strcmp(((named_color*)p1)->name, ((named_color*)p2)->name); } //------------------------------------------------------------- rgba8 parse_color(const char* str) { while(*str == ' ') ++str; unsigned c = 0; if(*str == '#') { sscanf(str + 1, "%x", &c); return rgb8_packed(c); } else { named_color c; unsigned len = strlen(str); if(len > sizeof(c.name) - 1) { throw exception("parse_color: Invalid color name '%s'", str); } strcpy(c.name, str); const void* p = bsearch(&c, colors, sizeof(colors) / sizeof(colors[0]), sizeof(colors[0]), cmp_color); if(p == 0) { throw exception("parse_color: Invalid color name '%s'", str); } const named_color* pc = (const named_color*)p; return rgba8(pc->r, pc->g, pc->b, pc->a); } } double parse_double(const char* str) { while(*str == ' ') ++str; return atof(str); } //------------------------------------------------------------- bool parser::parse_attr(const char* name, const char* value) { if(strcmp(name, "style") == 0) { parse_style(value); } else if(strcmp(name, "fill") == 0) { if(strcmp(value, "none") == 0) { m_path.fill_none(); } else { m_path.fill(parse_color(value)); } } else if(strcmp(name, "fill-opacity") == 0) { m_path.fill_opacity(parse_double(value)); } else if(strcmp(name, "stroke") == 0) { if(strcmp(value, "none") == 0) { m_path.stroke_none(); } else { m_path.stroke(parse_color(value)); } } else if(strcmp(name, "stroke-width") == 0) { m_path.stroke_width(parse_double(value)); } else if(strcmp(name, "stroke-linecap") == 0) { if(strcmp(value, "butt") == 0) m_path.line_cap(butt_cap); else if(strcmp(value, "round") == 0) m_path.line_cap(round_cap); else if(strcmp(value, "square") == 0) m_path.line_cap(square_cap); } else if(strcmp(name, "stroke-linejoin") == 0) { if(strcmp(value, "miter") == 0) m_path.line_join(miter_join); else if(strcmp(value, "round") == 0) m_path.line_join(round_join); else if(strcmp(value, "bevel") == 0) m_path.line_join(bevel_join); } else if(strcmp(name, "stroke-miterlimit") == 0) { m_path.miter_limit(parse_double(value)); } else if(strcmp(name, "stroke-opacity") == 0) { m_path.stroke_opacity(parse_double(value)); } else if(strcmp(name, "transform") == 0) { parse_transform(value); } //else //if(strcmp(el, "<OTHER_ATTRIBUTES>") == 0) //{ //} // . . . else { return false; } return true; } //------------------------------------------------------------- void parser::copy_name(const char* start, const char* end) { unsigned len = unsigned(end - start); if(m_attr_name_len == 0 || len > m_attr_name_len) { delete [] m_attr_name; m_attr_name = new char[len + 1]; m_attr_name_len = len; } if(len) memcpy(m_attr_name, start, len); m_attr_name[len] = 0; } //------------------------------------------------------------- void parser::copy_value(const char* start, const char* end) { unsigned len = unsigned(end - start); if(m_attr_value_len == 0 || len > m_attr_value_len) { delete [] m_attr_value; m_attr_value = new char[len + 1]; m_attr_value_len = len; } if(len) memcpy(m_attr_value, start, len); m_attr_value[len] = 0; } //------------------------------------------------------------- bool parser::parse_name_value(const char* nv_start, const char* nv_end) { const char* str = nv_start; while(str < nv_end && *str != ':') ++str; const char* val = str; // Right Trim while(str > nv_start && (*str == ':' || isspace(*str))) --str; ++str; copy_name(nv_start, str); while(val < nv_end && (*val == ':' || isspace(*val))) ++val; copy_value(val, nv_end); return parse_attr(m_attr_name, m_attr_value); } //------------------------------------------------------------- void parser::parse_style(const char* str) { while(*str) { // Left Trim while(*str && isspace(*str)) ++str; const char* nv_start = str; while(*str && *str != ';') ++str; const char* nv_end = str; // Right Trim while(nv_end > nv_start && (*nv_end == ';' || isspace(*nv_end))) --nv_end; ++nv_end; parse_name_value(nv_start, nv_end); if(*str) ++str; } } //------------------------------------------------------------- void parser::parse_rect(const char** attr) { int i; double x = 0.0; double y = 0.0; double w = 0.0; double h = 0.0; m_path.begin_path(); for(i = 0; attr[i]; i += 2) { if(!parse_attr(attr[i], attr[i + 1])) { if(strcmp(attr[i], "x") == 0) x = parse_double(attr[i + 1]); if(strcmp(attr[i], "y") == 0) y = parse_double(attr[i + 1]); if(strcmp(attr[i], "width") == 0) w = parse_double(attr[i + 1]); if(strcmp(attr[i], "height") == 0) h = parse_double(attr[i + 1]); // rx - to be implemented // ry - to be implemented } } if(w != 0.0 && h != 0.0) { if(w < 0.0) throw exception("parse_rect: Invalid width: %f", w); if(h < 0.0) throw exception("parse_rect: Invalid height: %f", h); m_path.move_to(x, y); m_path.line_to(x + w, y); m_path.line_to(x + w, y + h); m_path.line_to(x, y + h); m_path.close_subpath(); } m_path.end_path(); } //------------------------------------------------------------- void parser::parse_line(const char** attr) { int i; double x1 = 0.0; double y1 = 0.0; double x2 = 0.0; double y2 = 0.0; m_path.begin_path(); for(i = 0; attr[i]; i += 2) { if(!parse_attr(attr[i], attr[i + 1])) { if(strcmp(attr[i], "x1") == 0) x1 = parse_double(attr[i + 1]); if(strcmp(attr[i], "y1") == 0) y1 = parse_double(attr[i + 1]); if(strcmp(attr[i], "x2") == 0) x2 = parse_double(attr[i + 1]); if(strcmp(attr[i], "y2") == 0) y2 = parse_double(attr[i + 1]); } } m_path.move_to(x1, y1); m_path.line_to(x2, y2); m_path.end_path(); } //------------------------------------------------------------- void parser::parse_poly(const char** attr, bool close_flag) { int i; double x = 0.0; double y = 0.0; m_path.begin_path(); for(i = 0; attr[i]; i += 2) { if(!parse_attr(attr[i], attr[i + 1])) { if(strcmp(attr[i], "points") == 0) { m_tokenizer.set_path_str(attr[i + 1]); if(!m_tokenizer.next()) { throw exception("parse_poly: Too few coordinates"); } x = m_tokenizer.last_number(); if(!m_tokenizer.next()) { throw exception("parse_poly: Too few coordinates"); } y = m_tokenizer.last_number(); m_path.move_to(x, y); while(m_tokenizer.next()) { x = m_tokenizer.last_number(); if(!m_tokenizer.next()) { throw exception("parse_poly: Odd number of coordinates"); } y = m_tokenizer.last_number(); m_path.line_to(x, y); } } } } if(close_flag) { m_path.close_subpath(); } m_path.end_path(); } //------------------------------------------------------------- void parser::parse_circle(const char** attr) { int i; double cx = 0.0; double cy = 0.0; double r = 0.0; m_path.begin_path(); for(i = 0; attr[i]; i += 2) { if(!parse_attr(attr[i], attr[i + 1])) { if(strcmp(attr[i], "cx") == 0) cx = parse_double(attr[i + 1]); if(strcmp(attr[i], "cy") == 0) cy = parse_double(attr[i + 1]); if(strcmp(attr[i], "r") == 0) r = parse_double(attr[i + 1]); } } m_path.move_to(cx-r, cy); m_path.arc(r, r, 360, true, true, 0, .0001, true); m_path.end_path(); } void parser::parse_ellipse(const char** attr) { int i; double cx = 0.0; double cy = 0.0; double rx = 0.0; double ry = 0.0; m_path.begin_path(); for(i = 0; attr[i]; i += 2) { if(!parse_attr(attr[i], attr[i + 1])) { if(strcmp(attr[i], "cx") == 0) cx = parse_double(attr[i + 1]); if(strcmp(attr[i], "cy") == 0) cy = parse_double(attr[i + 1]); if(strcmp(attr[i], "rx") == 0) rx = parse_double(attr[i + 1]); if(strcmp(attr[i], "ry") == 0) ry = parse_double(attr[i + 1]); } } m_path.move_to(cx-rx, cy); m_path.arc(rx, ry, 360, true, true, 0, .0001, true); m_path.end_path(); } //------------------------------------------------------------- void parser::parse_transform(const char* str) { while(*str) { if(islower(*str)) { if(strncmp(str, "matrix", 6) == 0) str += parse_matrix(str); else if(strncmp(str, "translate", 9) == 0) str += parse_translate(str); else if(strncmp(str, "rotate", 6) == 0) str += parse_rotate(str); else if(strncmp(str, "scale", 5) == 0) str += parse_scale(str); else if(strncmp(str, "skewX", 5) == 0) str += parse_skew_x(str); else if(strncmp(str, "skewY", 5) == 0) str += parse_skew_y(str); else { ++str; } } else { ++str; } } } //------------------------------------------------------------- static bool is_numeric(char c) { return strchr("0123456789+-.eE", c) != 0; } //------------------------------------------------------------- static unsigned parse_transform_args(const char* str, double* args, unsigned max_na, unsigned* na) { *na = 0; const char* ptr = str; while(*ptr && *ptr != '(') ++ptr; if(*ptr == 0) { throw exception("parse_transform_args: Invalid syntax"); } const char* end = ptr; while(*end && *end != ')') ++end; if(*end == 0) { throw exception("parse_transform_args: Invalid syntax"); } while(ptr < end) { if(is_numeric(*ptr)) { if(*na >= max_na) { throw exception("parse_transform_args: Too many arguments"); } args[(*na)++] = atof(ptr); while(ptr < end && is_numeric(*ptr)) ++ptr; } else { ++ptr; } } return unsigned(end - str); } //------------------------------------------------------------- unsigned parser::parse_matrix(const char* str) { double args[6]; unsigned na = 0; unsigned len = parse_transform_args(str, args, 6, &na); if(na != 6) { throw exception("parse_matrix: Invalid number of arguments"); } m_path.transform().premultiply(trans_affine(args[0], args[1], args[2], args[3], args[4], args[5])); return len; } //------------------------------------------------------------- unsigned parser::parse_translate(const char* str) { double args[2]; unsigned na = 0; unsigned len = parse_transform_args(str, args, 2, &na); if(na == 1) args[1] = 0.0; m_path.transform().premultiply(trans_affine_translation(args[0], args[1])); return len; } //------------------------------------------------------------- unsigned parser::parse_rotate(const char* str) { double args[3]; unsigned na = 0; unsigned len = parse_transform_args(str, args, 3, &na); if(na == 1) { m_path.transform().premultiply(trans_affine_rotation(deg2rad(args[0]))); } else if(na == 3) { trans_affine t = trans_affine_translation(-args[1], -args[2]); t *= trans_affine_rotation(deg2rad(args[0])); t *= trans_affine_translation(args[1], args[2]); m_path.transform().premultiply(t); } else { throw exception("parse_rotate: Invalid number of arguments"); } return len; } //------------------------------------------------------------- unsigned parser::parse_scale(const char* str) { double args[2]; unsigned na = 0; unsigned len = parse_transform_args(str, args, 2, &na); if(na == 1) args[1] = args[0]; m_path.transform().premultiply(trans_affine_scaling(args[0], args[1])); return len; } //------------------------------------------------------------- unsigned parser::parse_skew_x(const char* str) { double arg; unsigned na = 0; unsigned len = parse_transform_args(str, &arg, 1, &na); m_path.transform().premultiply(trans_affine_skewing(deg2rad(arg), 0.0)); return len; } //------------------------------------------------------------- unsigned parser::parse_skew_y(const char* str) { double arg; unsigned na = 0; unsigned len = parse_transform_args(str, &arg, 1, &na); m_path.transform().premultiply(trans_affine_skewing(0.0, deg2rad(arg))); return len; } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/Codecs.hh������������������������������������������������������������������0000644�0000764�0000764�00000010702�11737001550�015341� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2010 René Rebe * * 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. */ /* The Image decoder and coder collection. * * The class itself has static methods to perform the de- and * encoding. These methods search thru a loader list to match the * file magick (on decoding) or the specified codec / file extension * on encoding. * * The codec might attach a freestanding instance of itself onto the * image on decode to allow on-the-fly decoding and reuse of coded * data while re-encoding an image where nothing or just meta data was * touched while the pixel data remains unmodified. * * Also some specialized methods are available to optimize some * operations that sometimes can work on encoded data. */ #ifndef IMAGELOADER_HH #define IMAGELOADER_HH #include <stdio.h> #include <list> #include <algorithm> #include <iosfwd> #include "Image.hh" // just forward class Image; class ImageCodec { public: ImageCodec (); ImageCodec (Image* __image); virtual ~ImageCodec (); virtual std::string getID () = 0; // helpers for parsing the codec spec and filename extension static std::string getCodec (std::string& filename); static std::string getExtension (const std::string& filename); // NEW API, allowing the use of any STL i/o stream derived source. The index i // is the page, image, index number within the file (TIFF, GIF, ICO, etc.) static int Read (std::istream* stream, Image& image, std::string codec = "", const std::string& decompress = "", int index = 0); static bool Write (std::ostream* stream, Image& image, std::string codec, std::string ext = "", int quality = 75, const std::string& compress = ""); static ImageCodec* MultiWrite (std::ostream* stream, std::string codec, std::string ext = ""); // OLD API, only left for compatibility. // Not const string& because the filename is parsed and the copy is changed intern. // // Removed soon! static int Read (std::string file, Image& image, const std::string& decompress = "", int index = 0); static bool Write (std::string file, Image& image, int quality = 75, const std::string& compress = ""); // Per codec methods, only one set needs to be implemented, the one with // index invoke the one without by default (compatibility, ease of implemntation // fallback), the ones without return error (as in "not implemented"). virtual int readImage (std::istream* stream, Image& image, const std::string& decompress); virtual int readImage (std::istream* stream, Image& image, const std::string& decompress, int index); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) = 0; virtual ImageCodec* instanciateForWrite (std::ostream* stream); // slightly named differently to match the public factory name virtual bool Write (Image& image, int quality = 75, const std::string& compress = "", int index = 0); // not pure-virtual so not every codec needs a NOP virtual /*bool*/ void decodeNow (Image* image); // optional optimizing and/or lossless implementations (JPEG, et al.) virtual bool flipX (Image& image); virtual bool flipY (Image& image); virtual bool rotate (Image& image, double angle); virtual bool crop (Image& image, unsigned int x, unsigned int y, unsigned int w, unsigned int h); virtual bool toGray (Image& image); virtual bool scale (Image& image, double xscale, double yscale); protected: struct loader_ref { const char* ext; ImageCodec* loader; bool primary_entry; bool via_codec_only; }; static std::list<loader_ref>* loader; static void registerCodec (const char* _ext, ImageCodec* _loader, bool _via_codec_only = false, bool push_back = false); static void unregisterCodec (ImageCodec* _loader); // freestanding instance, attached to an image const Image* _image; }; #endif ��������������������������������������������������������������exact-image-0.9.1/codecs/tga.hh���������������������������������������������������������������������0000644�0000764�0000764�00000002353�11737001550�014717� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 René Rebe * * 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 "Codecs.hh" class TGACodec : public ImageCodec { public: TGACodec () { registerCodec ("tga", this, false, true); registerCodec ("tpic", this, false, true); registerCodec ("vda", this, false, true); registerCodec ("icb", this, false, true); registerCodec ("vst", this, false, true); }; virtual std::string getID () { return "TARGA"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompress); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/svg.hh���������������������������������������������������������������������0000644�0000764�0000764�00000002057�11352361372�014750� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008-2010 René Rebe * * 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 "Codecs.hh" class SVGCodec : public ImageCodec { public: SVGCodec () { registerCodec ("svg", this); }; virtual std::string getID () { return "SVG"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/raw.cc���������������������������������������������������������������������0000644�0000764�0000764�00000004232�11514075025�014722� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2011 René Rebe * * 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. * * All rights reserved. Commercial licensing options are * available from the copyright holder ExactCODE GmbH Germany. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include "raw.hh" int RAWCodec::readImage(std::istream* stream, Image& image, const std::string& decompres) { if (image.w <= 0 || image.bps == 0 || image.spp == 0) { std::cerr << "RAWCodec: image parameters not sufficently defined!" << std::endl; return false; } int h = image.h; if (h > 0) // if we know the height up-front image.resize(image.w, image.h); int y = 0; for (y = 0; h <= 0 || y < h; ++y) { if (h <= 0) // height not known up-front, resize line by line image.resize (image.w, y + 1); stream->read((char*)image.getRawData() + image.stride() * y, image.stride()); if (!stream->good()) break; } if (h > 0) { if (y != h) { std::cerr << "RAWCodec: Error reading line: " << y << std::endl; return false; } return true; } else { if (y == 0) { std::cerr << "RAWCodec: Error reading a line of image with undefined height at all (stride: " << image.stride() << ")" << std::endl; return false; } image.resize (image.w, y - 1); // final size of scanlines fully read return true; } } bool RAWCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { if (!image.getRawData()) return false; return stream->write ((char*)image.getRawData(), image.stride()*image.h) /* == (size_t) image.stride()*image.h*/; } RAWCodec raw_loader; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/eps.hh���������������������������������������������������������������������0000644�0000764�0000764�00000002203�11343547354�014737� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (c) 2008 Valentin Ziegler <valentin@exactcode.de> * Copyright (c) 2008 Susanne Klaus <susanne@exactcode.de> * * 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 "Codecs.hh" class EPSCodec : public ImageCodec { public: EPSCodec () { registerCodec ("eps", this); }; virtual std::string getID () { return "EPS"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); }; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/dcraw.h��������������������������������������������������������������������0000644�0000764�0000764�00001121147�12231502347�015100� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* dcraw.c -- Dave Coffin's raw photo decoder Copyright 1997-2013 by Dave Coffin, dcoffin a cybercom o net This is a command-line ANSI C program to convert raw photos from any digital camera on any computer running any operating system. No license is required to download and use dcraw.c. However, to lawfully redistribute dcraw, you must either (a) offer, at no extra charge, full source code* for all executable files containing RESTRICTED functions, (b) distribute this code under the GPL Version 2 or later, (c) remove all RESTRICTED functions, re-implement them, or copy them from an earlier, unrestricted Revision of dcraw.c, or (d) purchase a license from the author. The functions that process Foveon images have been RESTRICTED since Revision 1.237. All other code remains free for all uses. *If you have not modified dcraw.c in any way, a link to my homepage qualifies as "full source code". $Revision: 1.456 $ $Date: 2013/06/16 18:01:08 $ */ #define DCRAW_VERSION "9.19" #define NODEPS #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #define _USE_MATH_DEFINES #include <ctype.h> #include <errno.h> #include <fcntl.h> #include <float.h> #include <limits.h> #include <math.h> #include <setjmp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <sys/types.h> #if defined(DJGPP) || defined(__MINGW32__) #define fseeko fseek #define ftello ftell #else //#define fgetc getc_unlocked #endif #ifdef __CYGWIN__ #include <io.h> #endif #ifdef WIN32 #include <sys/utime.h> #include <winsock2.h> #pragma comment(lib, "ws2_32.lib") #define snprintf _snprintf #define strcasecmp stricmp #define strncasecmp strnicmp typedef __int64 INT64; typedef unsigned __int64 UINT64; #else #include <unistd.h> #include <utime.h> #include <netinet/in.h> #endif typedef long long INT64; typedef unsigned long long UINT64; #ifdef NODEPS #define NO_JASPER #define NO_JPEG #define NO_LCMS #endif #ifndef NO_JASPER #include <jasper/jasper.h> /* Decode Red camera movies */ #endif #ifndef NO_JPEG #include <jpeglib.h> /* Decode compressed Kodak DC120 photos */ #endif /* and Adobe Lossy DNGs */ #ifndef NO_LCMS #include <lcms.h> /* Support color profiles */ #endif #ifdef LOCALEDIR #include <libintl.h> #define _(String) gettext(String) #else #define _(String) (String) #endif #ifdef LJPEG_DECODE #error Please compile dcraw.c by itself. #error Do not link it with ljpeg_decode. #endif #ifndef LONG_BIT #define LONG_BIT (8 * sizeof (long)) #endif #if !defined(uchar) #define uchar unsigned char #endif #if !defined(ushort) #define ushort unsigned short #endif namespace dcraw { /* All global variables are defined here, and all functions that access them are prefixed with "CLASS". Note that a thread-safe C++ class cannot have non-const static local variables. */ FILE *ifp, *ofp; short order; const char *ifname; char *meta_data, xtrans[6][6]; char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64]; float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len; time_t timestamp; off_t strip_offset, data_offset; off_t thumb_offset, meta_offset, profile_offset; unsigned shot_order, kodak_cbpp, exif_cfa, unique_id; unsigned thumb_length, meta_length, profile_length; unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0; unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress; unsigned black, cblack[4], maximum, mix_green, raw_color, zero_is_bad; unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error; unsigned tile_width, tile_length, gpsdata[32], load_flags; unsigned flip, tiff_flip, filters, colors; ushort raw_height, raw_width, height, width, top_margin, left_margin; ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height; ushort *raw_image, (*image)[4]; ushort white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4]; double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 }; float bright=1, user_mul[4]={0,0,0,0}, threshold=0; int mask[8][4]; int half_size=0, four_color_rgb=0, document_mode=0, highlight=0; int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=-1; int output_color=1, output_bps=8, output_tiff=0, med_passes=0; int no_auto_bright=0; unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX }; float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4]; const double xyz_rgb[3][3] = { /* XYZ from RGB */ { 0.412453, 0.357580, 0.180423 }, { 0.212671, 0.715160, 0.072169 }, { 0.019334, 0.119193, 0.950227 } }; const float d65_white[3] = { 0.950456, 1, 1.088754 }; int histogram[4][0x2000]; void (*write_thumb)(), (*write_fun)(); void (*load_raw)(), (*thumb_load_raw)(); jmp_buf failure; struct decode { struct decode *branch[2]; int leaf; } first_decode[2048], *second_decode, *free_decode; struct tiff_ifd { int width, height, bps, comp, phint, offset, flip, samples, bytes; int tile_width, tile_length; } tiff_ifd[10]; struct ph1 { int format, key_off, black, black_off, split_col, tag_21a; float tag_210; } ph1; #define CLASS #define FORC(cnt) for (c=0; c < cnt; c++) #define FORC3 FORC(3) #define FORC4 FORC(4) #define FORCC FORC(colors) #define SQR(x) ((x)*(x)) #define ABS(x) (((int)(x) ^ ((int)(x) >> 31)) - ((int)(x) >> 31)) #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define LIM(x,min,max) MAX(min,MIN(x,max)) #define ULIM(x,y,z) ((y) < (z) ? LIM(x,y,z) : LIM(x,z,y)) #define CLIP(x) LIM(x,0,65535) #define SWAP(a,b) { a=a+b; b=a-b; a=a-b; } /* In order to inline this calculation, I make the risky assumption that all filter patterns can be described by a repeating pattern of eight rows and two columns Do not use the FC or BAYER macros with the Leaf CatchLight, because its pattern is 16x16, not 2x8. Return values are either 0/1/2/3 = G/M/C/Y or 0/1/2/3 = R/G1/B/G2 PowerShot 600 PowerShot A50 PowerShot Pro70 Pro90 & G1 0xe1e4e1e4: 0x1b4e4b1e: 0x1e4b4e1b: 0xb4b4b4b4: 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 G M G M G M 0 C Y C Y C Y 0 Y C Y C Y C 0 G M G M G M 1 C Y C Y C Y 1 M G M G M G 1 M G M G M G 1 Y C Y C Y C 2 M G M G M G 2 Y C Y C Y C 2 C Y C Y C Y 3 C Y C Y C Y 3 G M G M G M 3 G M G M G M 4 C Y C Y C Y 4 Y C Y C Y C PowerShot A5 5 G M G M G M 5 G M G M G M 0x1e4e1e4e: 6 Y C Y C Y C 6 C Y C Y C Y 7 M G M G M G 7 M G M G M G 0 1 2 3 4 5 0 C Y C Y C Y 1 G M G M G M 2 C Y C Y C Y 3 M G M G M G All RGB cameras use one of these Bayer grids: 0x16161616: 0x61616161: 0x49494949: 0x94949494: 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 1 2 3 4 5 0 B G B G B G 0 G R G R G R 0 G B G B G B 0 R G R G R G 1 G R G R G R 1 B G B G B G 1 R G R G R G 1 G B G B G B 2 B G B G B G 2 G R G R G R 2 G B G B G B 2 R G R G R G 3 G R G R G R 3 B G B G B G 3 R G R G R G 3 G B G B G B */ #define RAW(row,col) \ raw_image[(row)*raw_width+(col)] #define FC(row,col) \ (filters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) #define BAYER(row,col) \ image[((row) >> shrink)*iwidth + ((col) >> shrink)][FC(row,col)] #define BAYER2(row,col) \ image[((row) >> shrink)*iwidth + ((col) >> shrink)][fcol(row,col)] int CLASS fcol (int row, int col) { static const char filter[16][16] = { { 2,1,1,3,2,3,2,0,3,2,3,0,1,2,1,0 }, { 0,3,0,2,0,1,3,1,0,1,1,2,0,3,3,2 }, { 2,3,3,2,3,1,1,3,3,1,2,1,2,0,0,3 }, { 0,1,0,1,0,2,0,2,2,0,3,0,1,3,2,1 }, { 3,1,1,2,0,1,0,2,1,3,1,3,0,1,3,0 }, { 2,0,0,3,3,2,3,1,2,0,2,0,3,2,2,1 }, { 2,3,3,1,2,1,2,1,2,1,1,2,3,0,0,1 }, { 1,0,0,2,3,0,0,3,0,3,0,3,2,1,2,3 }, { 2,3,3,1,1,2,1,0,3,2,3,0,2,3,1,3 }, { 1,0,2,0,3,0,3,2,0,1,1,2,0,1,0,2 }, { 0,1,1,3,3,2,2,1,1,3,3,0,2,1,3,2 }, { 2,3,2,0,0,1,3,0,2,0,1,2,3,0,1,0 }, { 1,3,1,2,3,2,3,2,0,2,0,1,1,0,3,0 }, { 0,2,0,3,1,0,0,1,1,3,3,2,3,2,2,1 }, { 2,1,3,2,3,1,2,1,0,3,0,2,0,2,0,2 }, { 0,3,1,0,0,2,0,3,2,1,3,1,1,3,1,3 } }; if (filters == 1) return filter[(row+top_margin)&15][(col+left_margin)&15]; if (filters == 9) return xtrans[(row+top_margin+6)%6][(col+left_margin+6)%6]; return FC(row,col); } #ifndef __GLIBC__ char *my_memmem (char *haystack, size_t haystacklen, char *needle, size_t needlelen) { char *c; for (c = haystack; c <= haystack + haystacklen - needlelen; c++) if (!memcmp (c, needle, needlelen)) return c; return 0; } #define memmem my_memmem char *my_strcasestr (char *haystack, const char *needle) { char *c; for (c = haystack; *c; c++) if (!strncasecmp(c, needle, strlen(needle))) return c; return 0; } #define strcasestr my_strcasestr #endif void CLASS merror (void *ptr, const char *where) { if (ptr) return; fprintf (stderr,_("%s: Out of memory in %s\n"), ifname, where); longjmp (failure, 1); } void CLASS derror() { if (!data_error) { fprintf (stderr, "%s: ", ifname); if (feof(ifp)) fprintf (stderr,_("Unexpected end of file\n")); else fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp)); } data_error++; } ushort CLASS sget2 (uchar *s) { if (order == 0x4949) /* "II" means little-endian */ return s[0] | s[1] << 8; else /* "MM" means big-endian */ return s[0] << 8 | s[1]; } ushort CLASS get2() { uchar str[2] = { 0xff,0xff }; fread (str, 1, 2, ifp); return sget2(str); } unsigned CLASS sget4 (uchar *s) { if (order == 0x4949) return s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24; else return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3]; } #define sget4(s) sget4((uchar *)s) unsigned CLASS get4() { uchar str[4] = { 0xff,0xff,0xff,0xff }; fread (str, 1, 4, ifp); return sget4(str); } unsigned CLASS getint (int type) { return type == 3 ? get2() : get4(); } float CLASS int_to_float (int i) { union { int i; float f; } u; u.i = i; return u.f; } double CLASS getreal (int type) { union { char c[8]; double d; } u; int i, rev; switch (type) { case 3: return (unsigned short) get2(); case 4: return (unsigned int) get4(); case 5: u.d = (unsigned int) get4(); return u.d / (unsigned int) get4(); case 8: return (signed short) get2(); case 9: return (signed int) get4(); case 10: u.d = (signed int) get4(); return u.d / (signed int) get4(); case 11: return int_to_float (get4()); case 12: rev = 7 * ((order == 0x4949) == (ntohs(0x1234) == 0x1234)); for (i=0; i < 8; i++) u.c[i ^ rev] = fgetc(ifp); return u.d; default: return fgetc(ifp); } } void CLASS read_shorts (ushort *pixel, int count) { if (fread (pixel, 2, count, ifp) < count) derror(); if ((order == 0x4949) == (ntohs(0x1234) == 0x1234)) swab (pixel, pixel, count*2); } void CLASS canon_600_fixed_wb (int temp) { static const short mul[4][5] = { { 667, 358,397,565,452 }, { 731, 390,367,499,517 }, { 1119, 396,348,448,537 }, { 1399, 485,431,508,688 } }; int lo, hi, i; float frac=0; for (lo=4; --lo; ) if (*mul[lo] <= temp) break; for (hi=0; hi < 3; hi++) if (*mul[hi] >= temp) break; if (lo != hi) frac = (float) (temp - *mul[lo]) / (*mul[hi] - *mul[lo]); for (i=1; i < 5; i++) pre_mul[i-1] = 1 / (frac * mul[hi][i] + (1-frac) * mul[lo][i]); } /* Return values: 0 = white 1 = near white 2 = not white */ int CLASS canon_600_color (int ratio[2], int mar) { int clipped=0, target, miss; if (flash_used) { if (ratio[1] < -104) { ratio[1] = -104; clipped = 1; } if (ratio[1] > 12) { ratio[1] = 12; clipped = 1; } } else { if (ratio[1] < -264 || ratio[1] > 461) return 2; if (ratio[1] < -50) { ratio[1] = -50; clipped = 1; } if (ratio[1] > 307) { ratio[1] = 307; clipped = 1; } } target = flash_used || ratio[1] < 197 ? -38 - (398 * ratio[1] >> 10) : -123 + (48 * ratio[1] >> 10); if (target - mar <= ratio[0] && target + 20 >= ratio[0] && !clipped) return 0; miss = target - ratio[0]; if (abs(miss) >= mar*4) return 2; if (miss < -20) miss = -20; if (miss > mar) miss = mar; ratio[0] = target - miss; return 1; } void CLASS canon_600_auto_wb() { int mar, row, col, i, j, st, count[] = { 0,0 }; int test[8], total[2][8], ratio[2][2], stat[2]; memset (&total, 0, sizeof total); i = canon_ev + 0.5; if (i < 10) mar = 150; else if (i > 12) mar = 20; else mar = 280 - 20 * i; if (flash_used) mar = 80; for (row=14; row < height-14; row+=4) for (col=10; col < width; col+=2) { for (i=0; i < 8; i++) test[(i & 4) + FC(row+(i >> 1),col+(i & 1))] = BAYER(row+(i >> 1),col+(i & 1)); for (i=0; i < 8; i++) if (test[i] < 150 || test[i] > 1500) goto next; for (i=0; i < 4; i++) if (abs(test[i] - test[i+4]) > 50) goto next; for (i=0; i < 2; i++) { for (j=0; j < 4; j+=2) ratio[i][j >> 1] = ((test[i*4+j+1]-test[i*4+j]) << 10) / test[i*4+j]; stat[i] = canon_600_color (ratio[i], mar); } if ((st = stat[0] | stat[1]) > 1) goto next; for (i=0; i < 2; i++) if (stat[i]) for (j=0; j < 2; j++) test[i*4+j*2+1] = test[i*4+j*2] * (0x400 + ratio[i][j]) >> 10; for (i=0; i < 8; i++) total[st][i] += test[i]; count[st]++; next: ; } if (count[0] | count[1]) { st = count[0]*200 < count[1]; for (i=0; i < 4; i++) pre_mul[i] = 1.0 / (total[st][i] + total[st][i+4]); } } void CLASS canon_600_coeff() { static const short table[6][12] = { { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, { -1203,1715,-1136,1648, 1388,-876,267,245, -1641,2153,3921,-3409 }, { -615,1127,-1563,2075, 1437,-925,509,3, -756,1268,2519,-2007 }, { -190,702,-1886,2398, 2153,-1641,763,-251, -452,964,3040,-2528 }, { -190,702,-1878,2390, 1861,-1349,905,-393, -432,944,2617,-2105 }, { -807,1319,-1785,2297, 1388,-876,769,-257, -230,742,2067,-1555 } }; int t=0, i, c; float mc, yc; mc = pre_mul[1] / pre_mul[2]; yc = pre_mul[3] / pre_mul[2]; if (mc > 1 && mc <= 1.28 && yc < 0.8789) t=1; if (mc > 1.28 && mc <= 2) { if (yc < 0.8789) t=3; else if (yc <= 2) t=4; } if (flash_used) t=5; for (raw_color = i=0; i < 3; i++) FORCC rgb_cam[i][c] = table[t][i*4 + c] / 1024.0; } void CLASS canon_600_load_raw() { uchar data[1120], *dp; ushort *pix; int irow, row; for (irow=row=0; irow < height; irow++) { if (fread (data, 1, 1120, ifp) < 1120) derror(); pix = raw_image + row*raw_width; for (dp=data; dp < data+1120; dp+=10, pix+=8) { pix[0] = (dp[0] << 2) + (dp[1] >> 6 ); pix[1] = (dp[2] << 2) + (dp[1] >> 4 & 3); pix[2] = (dp[3] << 2) + (dp[1] >> 2 & 3); pix[3] = (dp[4] << 2) + (dp[1] & 3); pix[4] = (dp[5] << 2) + (dp[9] & 3); pix[5] = (dp[6] << 2) + (dp[9] >> 2 & 3); pix[6] = (dp[7] << 2) + (dp[9] >> 4 & 3); pix[7] = (dp[8] << 2) + (dp[9] >> 6 ); } if ((row+=2) > height) row = 1; } } void CLASS canon_600_correct() { int row, col, val; static const short mul[4][2] = { { 1141,1145 }, { 1128,1109 }, { 1178,1149 }, { 1128,1109 } }; for (row=0; row < height; row++) for (col=0; col < width; col++) { if ((val = BAYER(row,col) - black) < 0) val = 0; val = val * mul[row & 3][col & 1] >> 9; BAYER(row,col) = val; } canon_600_fixed_wb(1311); canon_600_auto_wb(); canon_600_coeff(); maximum = (0x3ff - black) * 1109 >> 9; black = 0; } int CLASS canon_s2is() { unsigned row; for (row=0; row < 100; row++) { fseek (ifp, row*3340 + 3284, SEEK_SET); if (getc(ifp) > 15) return 1; } return 0; } unsigned CLASS getbithuff (int nbits, ushort *huff) { static unsigned bitbuf=0; static int vbits=0, reset=0; unsigned c; if (nbits > 25) return 0; if (nbits < 0) return bitbuf = vbits = reset = 0; if (nbits == 0 || vbits < 0) return 0; while (!reset && vbits < nbits && (c = fgetc(ifp)) != EOF && !(reset = zero_after_ff && c == 0xff && fgetc(ifp))) { bitbuf = (bitbuf << 8) + (uchar) c; vbits += 8; } c = bitbuf << (32-vbits) >> (32-nbits); if (huff) { vbits -= huff[c] >> 8; c = (uchar) huff[c]; } else vbits -= nbits; if (vbits < 0) derror(); return c; } #define getbits(n) getbithuff(n,0) #define gethuff(h) getbithuff(*h,h+1) /* Construct a decode tree according the specification in *source. The first 16 bytes specify how many codes should be 1-bit, 2-bit 3-bit, etc. Bytes after that are the leaf values. For example, if the source is { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, then the code is 00 0x04 010 0x03 011 0x05 100 0x06 101 0x02 1100 0x07 1101 0x01 11100 0x08 11101 0x09 11110 0x00 111110 0x0a 1111110 0x0b 1111111 0xff */ ushort * CLASS make_decoder_ref (const uchar **source) { int max, len, h, i, j; const uchar *count; ushort *huff; count = (*source += 16) - 17; for (max=16; max && !count[max]; max--); huff = (ushort *) calloc (1 + (1 << max), sizeof *huff); merror (huff, "make_decoder()"); huff[0] = max; for (h=len=1; len <= max; len++) for (i=0; i < count[len]; i++, ++*source) for (j=0; j < 1 << (max-len); j++) if (h <= 1 << max) huff[h++] = len << 8 | **source; return huff; } ushort * CLASS make_decoder (const uchar *source) { return make_decoder_ref (&source); } void CLASS crw_init_tables (unsigned table, ushort *huff[2]) { static const uchar first_tree[3][29] = { { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, 0x04,0x03,0x05,0x06,0x02,0x07,0x01,0x08,0x09,0x00,0x0a,0x0b,0xff }, { 0,2,2,3,1,1,1,1,2,0,0,0,0,0,0,0, 0x03,0x02,0x04,0x01,0x05,0x00,0x06,0x07,0x09,0x08,0x0a,0x0b,0xff }, { 0,0,6,3,1,1,2,0,0,0,0,0,0,0,0,0, 0x06,0x05,0x07,0x04,0x08,0x03,0x09,0x02,0x00,0x0a,0x01,0x0b,0xff }, }; static const uchar second_tree[3][180] = { { 0,2,2,2,1,4,2,1,2,5,1,1,0,0,0,139, 0x03,0x04,0x02,0x05,0x01,0x06,0x07,0x08, 0x12,0x13,0x11,0x14,0x09,0x15,0x22,0x00,0x21,0x16,0x0a,0xf0, 0x23,0x17,0x24,0x31,0x32,0x18,0x19,0x33,0x25,0x41,0x34,0x42, 0x35,0x51,0x36,0x37,0x38,0x29,0x79,0x26,0x1a,0x39,0x56,0x57, 0x28,0x27,0x52,0x55,0x58,0x43,0x76,0x59,0x77,0x54,0x61,0xf9, 0x71,0x78,0x75,0x96,0x97,0x49,0xb7,0x53,0xd7,0x74,0xb6,0x98, 0x47,0x48,0x95,0x69,0x99,0x91,0xfa,0xb8,0x68,0xb5,0xb9,0xd6, 0xf7,0xd8,0x67,0x46,0x45,0x94,0x89,0xf8,0x81,0xd5,0xf6,0xb4, 0x88,0xb1,0x2a,0x44,0x72,0xd9,0x87,0x66,0xd4,0xf5,0x3a,0xa7, 0x73,0xa9,0xa8,0x86,0x62,0xc7,0x65,0xc8,0xc9,0xa1,0xf4,0xd1, 0xe9,0x5a,0x92,0x85,0xa6,0xe7,0x93,0xe8,0xc1,0xc6,0x7a,0x64, 0xe1,0x4a,0x6a,0xe6,0xb3,0xf1,0xd3,0xa5,0x8a,0xb2,0x9a,0xba, 0x84,0xa4,0x63,0xe5,0xc5,0xf3,0xd2,0xc4,0x82,0xaa,0xda,0xe4, 0xf2,0xca,0x83,0xa3,0xa2,0xc3,0xea,0xc2,0xe2,0xe3,0xff,0xff }, { 0,2,2,1,4,1,4,1,3,3,1,0,0,0,0,140, 0x02,0x03,0x01,0x04,0x05,0x12,0x11,0x06, 0x13,0x07,0x08,0x14,0x22,0x09,0x21,0x00,0x23,0x15,0x31,0x32, 0x0a,0x16,0xf0,0x24,0x33,0x41,0x42,0x19,0x17,0x25,0x18,0x51, 0x34,0x43,0x52,0x29,0x35,0x61,0x39,0x71,0x62,0x36,0x53,0x26, 0x38,0x1a,0x37,0x81,0x27,0x91,0x79,0x55,0x45,0x28,0x72,0x59, 0xa1,0xb1,0x44,0x69,0x54,0x58,0xd1,0xfa,0x57,0xe1,0xf1,0xb9, 0x49,0x47,0x63,0x6a,0xf9,0x56,0x46,0xa8,0x2a,0x4a,0x78,0x99, 0x3a,0x75,0x74,0x86,0x65,0xc1,0x76,0xb6,0x96,0xd6,0x89,0x85, 0xc9,0xf5,0x95,0xb4,0xc7,0xf7,0x8a,0x97,0xb8,0x73,0xb7,0xd8, 0xd9,0x87,0xa7,0x7a,0x48,0x82,0x84,0xea,0xf4,0xa6,0xc5,0x5a, 0x94,0xa4,0xc6,0x92,0xc3,0x68,0xb5,0xc8,0xe4,0xe5,0xe6,0xe9, 0xa2,0xa3,0xe3,0xc2,0x66,0x67,0x93,0xaa,0xd4,0xd5,0xe7,0xf8, 0x88,0x9a,0xd7,0x77,0xc4,0x64,0xe2,0x98,0xa5,0xca,0xda,0xe8, 0xf3,0xf6,0xa9,0xb2,0xb3,0xf2,0xd2,0x83,0xba,0xd3,0xff,0xff }, { 0,0,6,2,1,3,3,2,5,1,2,2,8,10,0,117, 0x04,0x05,0x03,0x06,0x02,0x07,0x01,0x08, 0x09,0x12,0x13,0x14,0x11,0x15,0x0a,0x16,0x17,0xf0,0x00,0x22, 0x21,0x18,0x23,0x19,0x24,0x32,0x31,0x25,0x33,0x38,0x37,0x34, 0x35,0x36,0x39,0x79,0x57,0x58,0x59,0x28,0x56,0x78,0x27,0x41, 0x29,0x77,0x26,0x42,0x76,0x99,0x1a,0x55,0x98,0x97,0xf9,0x48, 0x54,0x96,0x89,0x47,0xb7,0x49,0xfa,0x75,0x68,0xb6,0x67,0x69, 0xb9,0xb8,0xd8,0x52,0xd7,0x88,0xb5,0x74,0x51,0x46,0xd9,0xf8, 0x3a,0xd6,0x87,0x45,0x7a,0x95,0xd5,0xf6,0x86,0xb4,0xa9,0x94, 0x53,0x2a,0xa8,0x43,0xf5,0xf7,0xd4,0x66,0xa7,0x5a,0x44,0x8a, 0xc9,0xe8,0xc8,0xe7,0x9a,0x6a,0x73,0x4a,0x61,0xc7,0xf4,0xc6, 0x65,0xe9,0x72,0xe6,0x71,0x91,0x93,0xa6,0xda,0x92,0x85,0x62, 0xf3,0xc5,0xb2,0xa4,0x84,0xba,0x64,0xa5,0xb3,0xd2,0x81,0xe5, 0xd3,0xaa,0xc4,0xca,0xf2,0xb1,0xe4,0xd1,0x83,0x63,0xea,0xc3, 0xe2,0x82,0xf1,0xa3,0xc2,0xa1,0xc1,0xe3,0xa2,0xe1,0xff,0xff } }; if (table > 2) table = 2; huff[0] = make_decoder ( first_tree[table]); huff[1] = make_decoder (second_tree[table]); } /* Return 0 if the image starts with compressed data, 1 if it starts with uncompressed low-order bits. In Canon compressed data, 0xff is always followed by 0x00. */ int CLASS canon_has_lowbits() { uchar test[0x4000]; int ret=1, i; fseek (ifp, 0, SEEK_SET); fread (test, 1, sizeof test, ifp); for (i=540; i < sizeof test - 1; i++) if (test[i] == 0xff) { if (test[i+1]) return 1; ret=0; } return ret; } void CLASS canon_load_raw() { ushort *pixel, *prow, *huff[2]; int nblocks, lowbits, i, c, row, r, save, val; int block, diffbuf[64], leaf, len, diff, carry=0, pnum=0, base[2]; crw_init_tables (tiff_compress, huff); lowbits = canon_has_lowbits(); if (!lowbits) maximum = 0x3ff; fseek (ifp, 540 + lowbits*raw_height*raw_width/4, SEEK_SET); zero_after_ff = 1; getbits(-1); for (row=0; row < raw_height; row+=8) { pixel = raw_image + row*raw_width; nblocks = MIN (8, raw_height-row) * raw_width >> 6; for (block=0; block < nblocks; block++) { memset (diffbuf, 0, sizeof diffbuf); for (i=0; i < 64; i++ ) { leaf = gethuff(huff[i > 0]); if (leaf == 0 && i) break; if (leaf == 0xff) continue; i += leaf >> 4; len = leaf & 15; if (len == 0) continue; diff = getbits(len); if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; if (i < 64) diffbuf[i] = diff; } diffbuf[0] += carry; carry = diffbuf[0]; for (i=0; i < 64; i++ ) { if (pnum++ % raw_width == 0) base[0] = base[1] = 512; if ((pixel[(block << 6) + i] = base[i & 1] += diffbuf[i]) >> 10) derror(); } } if (lowbits) { save = ftell(ifp); fseek (ifp, 26 + row*raw_width/4, SEEK_SET); for (prow=pixel, i=0; i < raw_width*2; i++) { c = fgetc(ifp); for (r=0; r < 8; r+=2, prow++) { val = (*prow << 2) + ((c >> r) & 3); if (raw_width == 2672 && val < 512) val += 2; *prow = val; } } fseek (ifp, save, SEEK_SET); } } FORC(2) free (huff[c]); } /* Not a full implementation of Lossless JPEG, just enough to decode Canon, Kodak and Adobe DNG images. */ struct jhead { int bits, high, wide, clrs, sraw, psv, restart, vpred[6]; ushort *huff[6], *free[4], *row; }; int CLASS ljpeg_start (struct jhead *jh, int info_only) { int c, tag, len; uchar data[0x10000]; const uchar *dp; memset (jh, 0, sizeof *jh); jh->restart = INT_MAX; fread (data, 2, 1, ifp); if (data[1] != 0xd8) return 0; do { fread (data, 2, 2, ifp); tag = data[0] << 8 | data[1]; len = (data[2] << 8 | data[3]) - 2; if (tag <= 0xff00) return 0; fread (data, 1, len, ifp); switch (tag) { case 0xffc3: jh->sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; case 0xffc0: jh->bits = data[0]; jh->high = data[1] << 8 | data[2]; jh->wide = data[3] << 8 | data[4]; jh->clrs = data[5] + jh->sraw; if (len == 9 && !dng_version) getc(ifp); break; case 0xffc4: if (info_only) break; for (dp = data; dp < data+len && (c = *dp++) < 4; ) jh->free[c] = jh->huff[c] = make_decoder_ref (&dp); break; case 0xffda: jh->psv = data[1+data[0]*2]; jh->bits -= data[3+data[0]*2] & 15; break; case 0xffdd: jh->restart = data[0] << 8 | data[1]; } } while (tag != 0xffda); if (info_only) return 1; if (jh->clrs > 6 || !jh->huff[0]) return 0; FORC(5) if (!jh->huff[c+1]) jh->huff[c+1] = jh->huff[c]; if (jh->sraw) { FORC(4) jh->huff[2+c] = jh->huff[1]; FORC(jh->sraw) jh->huff[1+c] = jh->huff[0]; } jh->row = (ushort *) calloc (jh->wide*jh->clrs, 4); merror (jh->row, "ljpeg_start()"); return zero_after_ff = 1; } void CLASS ljpeg_end (struct jhead *jh) { int c; FORC4 if (jh->free[c]) free (jh->free[c]); free (jh->row); } int CLASS ljpeg_diff (ushort *huff) { int len, diff; if(!huff) longjmp (failure, 2); len = gethuff(huff); if (len == 16 && (!dng_version || dng_version >= 0x1010000)) return -32768; diff = getbits(len); if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; return diff; } ushort * CLASS ljpeg_row (int jrow, struct jhead *jh) { int col, c, diff, pred, spred=0; ushort mark=0, *row[3]; if (jrow * jh->wide % jh->restart == 0) { FORC(6) jh->vpred[c] = 1 << (jh->bits-1); if (jrow) { fseek (ifp, -2, SEEK_CUR); do mark = (mark << 8) + (c = fgetc(ifp)); while (c != EOF && mark >> 4 != 0xffd); } getbits(-1); } FORC3 row[c] = jh->row + jh->wide*jh->clrs*((jrow+c) & 1); for (col=0; col < jh->wide; col++) FORC(jh->clrs) { diff = ljpeg_diff (jh->huff[c]); if (jh->sraw && c <= jh->sraw && (col | c)) pred = spred; else if (col) pred = row[0][-jh->clrs]; else pred = (jh->vpred[c] += diff) - diff; if (jrow && col) switch (jh->psv) { case 1: break; case 2: pred = row[1][0]; break; case 3: pred = row[1][-jh->clrs]; break; case 4: pred = pred + row[1][0] - row[1][-jh->clrs]; break; case 5: pred = pred + ((row[1][0] - row[1][-jh->clrs]) >> 1); break; case 6: pred = row[1][0] + ((pred - row[1][-jh->clrs]) >> 1); break; case 7: pred = (pred + row[1][0]) >> 1; break; default: pred = 0; } if ((**row = pred + diff) >> jh->bits) derror(); if (c <= jh->sraw) spred = **row; row[0]++; row[1]++; } return row[2]; } void CLASS lossless_jpeg_load_raw() { int jwide, jrow, jcol, val, jidx, i, j, row=0, col=0; struct jhead jh; ushort *rp; if(jh.wide<1 || jh.high<1 || jh.clrs<1 || jh.bits <1) longjmp (failure, 2); if (!ljpeg_start (&jh, 0)) return; jwide = jh.wide * jh.clrs; for (jrow=0; jrow < jh.high; jrow++) { rp = ljpeg_row (jrow, &jh); if (load_flags & 1) row = jrow & 1 ? height-1-jrow/2 : jrow/2; for (jcol=0; jcol < jwide; jcol++) { val = curve[*rp++]; if (cr2_slice[0]) { jidx = jrow*jwide + jcol; i = jidx / (cr2_slice[1]*jh.high); if ((j = i >= cr2_slice[0])) i = cr2_slice[0]; jidx -= i * (cr2_slice[1]*jh.high); row = jidx / cr2_slice[1+j]; col = jidx % cr2_slice[1+j] + i*cr2_slice[1]; } if (raw_width == 3984 && (col -= 2) < 0) col += (row--,raw_width); if(row>raw_height) longjmp (failure, 3); if ((unsigned) row < raw_height) RAW(row,col) = val; if (++col >= raw_width) col = (row++,0); } } ljpeg_end (&jh); } void CLASS canon_sraw_load_raw() { struct jhead jh; short *rp=0, (*ip)[4]; int jwide, slice, scol, ecol, row, col, jrow=0, jcol=0, pix[3], c; int v[3]={0,0,0}, ver, hue; char *cp; if (!ljpeg_start (&jh, 0) || jh.clrs < 4) return; jwide = (jh.wide >>= 1) * jh.clrs; for (ecol=slice=0; slice <= cr2_slice[0]; slice++) { scol = ecol; ecol += cr2_slice[1] * 2 / jh.clrs; if (!cr2_slice[0] || ecol > raw_width-1) ecol = raw_width & -2; for (row=0; row < height; row += (jh.clrs >> 1) - 1) { ip = (short (*)[4]) image + row*width; for (col=scol; col < ecol; col+=2, jcol+=jh.clrs) { if ((jcol %= jwide) == 0) rp = (short *) ljpeg_row (jrow++, &jh); if (col >= width) continue; FORC (jh.clrs-2) ip[col + (c >> 1)*width + (c & 1)][0] = rp[jcol+c]; ip[col][1] = rp[jcol+jh.clrs-2] - 16384; ip[col][2] = rp[jcol+jh.clrs-1] - 16384; } } } for (cp=model2; *cp && !isdigit(*cp); cp++); sscanf (cp, "%d.%d.%d", v, v+1, v+2); ver = (v[0]*1000 + v[1])*1000 + v[2]; hue = (jh.sraw+1) << 2; if (unique_id >= 0x80000281 || (unique_id == 0x80000218 && ver > 1000006)) hue = jh.sraw << 1; ip = (short (*)[4]) image; rp = ip[0]; for (row=0; row < height; row++, ip+=width) { if (row & (jh.sraw >> 1)) for (col=0; col < width; col+=2) for (c=1; c < 3; c++) if (row == height-1) ip[col][c] = ip[col-width][c]; else ip[col][c] = (ip[col-width][c] + ip[col+width][c] + 1) >> 1; for (col=1; col < width; col+=2) for (c=1; c < 3; c++) if (col == width-1) ip[col][c] = ip[col-1][c]; else ip[col][c] = (ip[col-1][c] + ip[col+1][c] + 1) >> 1; } for ( ; rp < ip[0]; rp+=4) { if (unique_id == 0x80000218 || unique_id == 0x80000250 || unique_id == 0x80000261 || unique_id == 0x80000281 || unique_id == 0x80000287) { rp[1] = (rp[1] << 2) + hue; rp[2] = (rp[2] << 2) + hue; pix[0] = rp[0] + (( 50*rp[1] + 22929*rp[2]) >> 14); pix[1] = rp[0] + ((-5640*rp[1] - 11751*rp[2]) >> 14); pix[2] = rp[0] + ((29040*rp[1] - 101*rp[2]) >> 14); } else { if (unique_id < 0x80000218) rp[0] -= 512; pix[0] = rp[0] + rp[2]; pix[2] = rp[0] + rp[1]; pix[1] = rp[0] + ((-778*rp[1] - (rp[2] << 11)) >> 12); } FORC3 rp[c] = CLIP(pix[c] * sraw_mul[c] >> 10); } ljpeg_end (&jh); maximum = 0x3fff; } void CLASS adobe_copy_pixel (unsigned row, unsigned col, ushort **rp) { int c; if (is_raw == 2 && shot_select) (*rp)++; if (raw_image) { if (row < raw_height && col < raw_width) RAW(row,col) = curve[**rp]; *rp += is_raw; } else { if (row < height && col < width) FORC(tiff_samples) image[row*width+col][c] = curve[(*rp)[c]]; *rp += tiff_samples; } if (is_raw == 2 && shot_select) (*rp)--; } void CLASS lossless_dng_load_raw() { unsigned save, trow=0, tcol=0, jwide, jrow, jcol, row, col; struct jhead jh; ushort *rp; while (trow < raw_height) { save = ftell(ifp); if (tile_length < INT_MAX) fseek (ifp, get4(), SEEK_SET); if (!ljpeg_start (&jh, 0)) break; jwide = jh.wide; if (filters) jwide *= jh.clrs; jwide /= is_raw; for (row=col=jrow=0; jrow < jh.high; jrow++) { rp = ljpeg_row (jrow, &jh); for (jcol=0; jcol < jwide; jcol++) { adobe_copy_pixel (trow+row, tcol+col, &rp); if (++col >= tile_width || col >= raw_width) row += 1 + (col = 0); } } fseek (ifp, save+4, SEEK_SET); if ((tcol += tile_width) >= raw_width) trow += tile_length + (tcol = 0); ljpeg_end (&jh); } } void CLASS packed_dng_load_raw() { ushort *pixel, *rp; int row, col; pixel = (ushort *) calloc (raw_width, tiff_samples*sizeof *pixel); merror (pixel, "packed_dng_load_raw()"); for (row=0; row < raw_height; row++) { if (tiff_bps == 16) read_shorts (pixel, raw_width * tiff_samples); else { getbits(-1); for (col=0; col < raw_width * tiff_samples; col++) pixel[col] = getbits(tiff_bps); } for (rp=pixel, col=0; col < raw_width; col++) adobe_copy_pixel (row, col, &rp); } free (pixel); } void CLASS pentax_load_raw() { ushort bit[2][15], huff[4097]; int dep, row, col, diff, c, i; ushort vpred[2][2] = {{0,0},{0,0}}, hpred[2]; fseek (ifp, meta_offset, SEEK_SET); dep = (get2() + 12) & 15; fseek (ifp, 12, SEEK_CUR); FORC(dep) bit[0][c] = get2(); FORC(dep) bit[1][c] = fgetc(ifp); FORC(dep) for (i=bit[0][c]; i <= ((bit[0][c]+(4096 >> bit[1][c])-1) & 4095); ) huff[++i] = bit[1][c] << 8 | c; huff[0] = 12; fseek (ifp, data_offset, SEEK_SET); getbits(-1); for (row=0; row < raw_height; row++) for (col=0; col < raw_width; col++) { diff = ljpeg_diff (huff); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; RAW(row,col) = hpred[col & 1]; if (hpred[col & 1] >> tiff_bps) derror(); } } void CLASS nikon_load_raw() { static const uchar nikon_tree[][32] = { { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy */ 5,4,3,6,2,7,1,0,8,9,11,10,12 }, { 0,1,5,1,1,1,1,1,1,2,0,0,0,0,0,0, /* 12-bit lossy after split */ 0x39,0x5a,0x38,0x27,0x16,5,4,3,2,1,0,11,12,12 }, { 0,1,4,2,3,1,2,0,0,0,0,0,0,0,0,0, /* 12-bit lossless */ 5,4,6,3,7,2,8,1,9,0,10,11,12 }, { 0,1,4,3,1,1,1,1,1,2,0,0,0,0,0,0, /* 14-bit lossy */ 5,6,4,7,8,3,9,2,1,0,10,11,12,13,14 }, { 0,1,5,1,1,1,1,1,1,1,2,0,0,0,0,0, /* 14-bit lossy after split */ 8,0x5c,0x4b,0x3a,0x29,7,6,5,4,3,2,1,0,13,14 }, { 0,1,4,2,2,3,1,2,0,0,0,0,0,0,0,0, /* 14-bit lossless */ 7,6,8,5,9,4,10,3,11,12,2,0,1,13,14 } }; ushort *huff, ver0, ver1, vpred[2][2], hpred[2], csize; int i, min, max, step=0, tree=0, split=0, row, col, len, shl, diff; fseek (ifp, meta_offset, SEEK_SET); ver0 = fgetc(ifp); ver1 = fgetc(ifp); if (ver0 == 0x49 || ver1 == 0x58) fseek (ifp, 2110, SEEK_CUR); if (ver0 == 0x46) tree = 2; if (tiff_bps == 14) tree += 3; read_shorts (vpred[0], 4); max = 1 << tiff_bps & 0x7fff; if ((csize = get2()) > 1) step = max / (csize-1); if (ver0 == 0x44 && ver1 == 0x20 && step > 0) { for (i=0; i < csize; i++) curve[i*step] = get2(); for (i=0; i < max; i++) curve[i] = ( curve[i-i%step]*(step-i%step) + curve[i-i%step+step]*(i%step) ) / step; fseek (ifp, meta_offset+562, SEEK_SET); split = get2(); } else if (ver0 != 0x46 && csize <= 0x4001) read_shorts (curve, max=csize); while (curve[max-2] == curve[max-1]) max--; huff = make_decoder (nikon_tree[tree]); fseek (ifp, data_offset, SEEK_SET); getbits(-1); for (min=row=0; row < height; row++) { if (split && row == split) { free (huff); huff = make_decoder (nikon_tree[tree+1]); max += (min = 16) << 1; } for (col=0; col < raw_width; col++) { i = gethuff(huff); len = i & 15; shl = i >> 4; diff = ((getbits(len-shl) << 1) + 1) << shl >> 1; if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - !shl; if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; if ((ushort)(hpred[col & 1] + min) >= max) derror(); RAW(row,col) = curve[LIM((short)hpred[col & 1],0,0x3fff)]; } } free (huff); } /* Returns 1 for a Coolpix 995, 0 for anything else. */ int CLASS nikon_e995() { int i, histo[256]; const uchar often[] = { 0x00, 0x55, 0xaa, 0xff }; memset (histo, 0, sizeof histo); fseek (ifp, -2000, SEEK_END); for (i=0; i < 2000; i++) histo[fgetc(ifp)]++; for (i=0; i < 4; i++) if (histo[often[i]] < 200) return 0; return 1; } /* Returns 1 for a Coolpix 2100, 0 for anything else. */ int CLASS nikon_e2100() { uchar t[12]; int i; fseek (ifp, 0, SEEK_SET); for (i=0; i < 1024; i++) { fread (t, 1, 12, ifp); if (((t[2] & t[4] & t[7] & t[9]) >> 4 & t[1] & t[6] & t[8] & t[11] & 3) != 3) return 0; } return 1; } void CLASS nikon_3700() { int bits, i; uchar dp[24]; static const struct { int bits; char make[12], model[15]; } table[] = { { 0x00, "Pentax", "Optio 33WR" }, { 0x03, "Nikon", "E3200" }, { 0x32, "Nikon", "E3700" }, { 0x33, "Olympus", "C740UZ" } }; fseek (ifp, 3072, SEEK_SET); fread (dp, 1, 24, ifp); bits = (dp[8] & 3) << 4 | (dp[20] & 3); for (i=0; i < sizeof table / sizeof *table; i++) if (bits == table[i].bits) { strcpy (make, table[i].make ); strcpy (model, table[i].model); } } /* Separates a Minolta DiMAGE Z2 from a Nikon E4300. */ int CLASS minolta_z2() { int i, nz; char tail[424]; fseek (ifp, -sizeof tail, SEEK_END); fread (tail, 1, sizeof tail, ifp); for (nz=i=0; i < sizeof tail; i++) if (tail[i]) nz++; return nz > 20; } void CLASS jpeg_thumb(); void CLASS ppm_thumb() { char *thumb; thumb_length = thumb_width*thumb_height*3; thumb = (char *) malloc (thumb_length); merror (thumb, "ppm_thumb()"); fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); fread (thumb, 1, thumb_length, ifp); fwrite (thumb, 1, thumb_length, ofp); free (thumb); } void CLASS ppm16_thumb() { int i; char *thumb; thumb_length = thumb_width*thumb_height*3; thumb = (char *) calloc (thumb_length, 2); merror (thumb, "ppm16_thumb()"); read_shorts ((ushort *) thumb, thumb_length); for (i=0; i < thumb_length; i++) thumb[i] = ((ushort *) thumb)[i] >> 8; fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); fwrite (thumb, 1, thumb_length, ofp); free (thumb); } void CLASS layer_thumb() { int i, c; char *thumb, map[][4] = { "012","102" }; colors = thumb_misc >> 5 & 7; thumb_length = thumb_width*thumb_height; thumb = (char *) calloc (colors, thumb_length); merror (thumb, "layer_thumb()"); fprintf (ofp, "P%d\n%d %d\n255\n", 5 + (colors >> 1), thumb_width, thumb_height); fread (thumb, thumb_length, colors, ifp); for (i=0; i < thumb_length; i++) FORCC putc (thumb[i+thumb_length*(map[thumb_misc >> 8][c]-'0')], ofp); free (thumb); } void CLASS rollei_thumb() { unsigned i; ushort *thumb; thumb_length = thumb_width * thumb_height; thumb = (ushort *) calloc (thumb_length, 2); merror (thumb, "rollei_thumb()"); fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); read_shorts (thumb, thumb_length); for (i=0; i < thumb_length; i++) { putc (thumb[i] << 3, ofp); putc (thumb[i] >> 5 << 2, ofp); putc (thumb[i] >> 11 << 3, ofp); } free (thumb); } void CLASS rollei_load_raw() { uchar pixel[10]; unsigned iten=0, isix, i, buffer=0, todo[16]; isix = raw_width * raw_height * 5 / 8; while (fread (pixel, 1, 10, ifp) == 10) { for (i=0; i < 10; i+=2) { todo[i] = iten++; todo[i+1] = pixel[i] << 8 | pixel[i+1]; buffer = pixel[i] >> 2 | buffer << 6; } for ( ; i < 16; i+=2) { todo[i] = isix++; todo[i+1] = buffer >> (14-i)*5; } for (i=0; i < 16; i+=2) raw_image[todo[i]] = (todo[i+1] & 0x3ff); } maximum = 0x3ff; } int CLASS raw (unsigned row, unsigned col) { return (row < raw_height && col < raw_width) ? RAW(row,col) : 0; } void CLASS phase_one_flat_field (int is_float, int nc) { ushort head[8]; unsigned wide, y, x, c, rend, cend, row, col; float *mrow, num, mult[4]; read_shorts (head, 8); wide = head[2] / head[4]; mrow = (float *) calloc (nc*wide, sizeof *mrow); merror (mrow, "phase_one_flat_field()"); for (y=0; y < head[3] / head[5]; y++) { for (x=0; x < wide; x++) for (c=0; c < nc; c+=2) { num = is_float ? getreal(11) : get2()/32768.0; if (y==0) mrow[c*wide+x] = num; else mrow[(c+1)*wide+x] = (num - mrow[c*wide+x]) / head[5]; } if (y==0) continue; rend = head[1] + y*head[5]; for (row = rend-head[5]; row < raw_height && row < rend; row++) { for (x=1; x < wide; x++) { for (c=0; c < nc; c+=2) { mult[c] = mrow[c*wide+x-1]; mult[c+1] = (mrow[c*wide+x] - mult[c]) / head[4]; } cend = head[0] + x*head[4]; for (col = cend-head[4]; col < raw_width && col < cend; col++) { c = nc > 2 ? FC(row-top_margin,col-left_margin) : 0; if (!(c & 1)) { c = RAW(row,col) * mult[c]; RAW(row,col) = LIM(c,0,65535); } for (c=0; c < nc; c+=2) mult[c] += mult[c+1]; } } for (x=0; x < wide; x++) for (c=0; c < nc; c+=2) mrow[c*wide+x] += mrow[(c+1)*wide+x]; } } free (mrow); } void CLASS phase_one_correct() { unsigned entries, tag, data, save, col, row, type; int len, i, j, k, cip, val[4], dev[4], sum, max; int head[9], diff, mindiff=INT_MAX, off_412=0; static const signed char dir[12][2] = { {-1,-1}, {-1,1}, {1,-1}, {1,1}, {-2,0}, {0,-2}, {0,2}, {2,0}, {-2,-2}, {-2,2}, {2,-2}, {2,2} }; float poly[8], num, cfrac, frac, mult[2], *yval[2]; ushort *xval[2]; if (half_size || !meta_length) return; if (verbose) fprintf (stderr,_("Phase One correction...\n")); fseek (ifp, meta_offset, SEEK_SET); order = get2(); fseek (ifp, 6, SEEK_CUR); fseek (ifp, meta_offset+get4(), SEEK_SET); entries = get4(); get4(); while (entries--) { tag = get4(); len = get4(); data = get4(); save = ftell(ifp); fseek (ifp, meta_offset+data, SEEK_SET); if (tag == 0x419) { /* Polynomial curve */ for (get4(), i=0; i < 8; i++) poly[i] = getreal(11); poly[3] += (ph1.tag_210 - poly[7]) * poly[6] + 1; for (i=0; i < 0x10000; i++) { num = (poly[5]*i + poly[3])*i + poly[1]; curve[i] = LIM(num,0,65535); } goto apply; /* apply to right half */ } else if (tag == 0x41a) { /* Polynomial curve */ for (i=0; i < 4; i++) poly[i] = getreal(11); for (i=0; i < 0x10000; i++) { for (num=0, j=4; j--; ) num = num * i + poly[j]; curve[i] = LIM(num+i,0,65535); } apply: /* apply to whole image */ for (row=0; row < raw_height; row++) for (col = (tag & 1)*ph1.split_col; col < raw_width; col++) RAW(row,col) = curve[RAW(row,col)]; } else if (tag == 0x400) { /* Sensor defects */ while ((len -= 8) >= 0) { col = get2(); row = get2(); type = get2(); get2(); if (col >= raw_width) continue; if (type == 131) /* Bad column */ for (row=0; row < raw_height; row++) if (FC(row-top_margin,col-left_margin) == 1) { for (sum=i=0; i < 4; i++) sum += val[i] = raw (row+dir[i][0], col+dir[i][1]); for (max=i=0; i < 4; i++) { dev[i] = abs((val[i] << 2) - sum); if (dev[max] < dev[i]) max = i; } RAW(row,col) = (sum - val[max])/3.0 + 0.5; } else { for (sum=0, i=8; i < 12; i++) sum += raw (row+dir[i][0], col+dir[i][1]); RAW(row,col) = 0.5 + sum * 0.0732233 + (raw(row,col-2) + raw(row,col+2)) * 0.3535534; } else if (type == 129) { /* Bad pixel */ if (row >= raw_height) continue; j = (FC(row-top_margin,col-left_margin) != 1) * 4; for (sum=0, i=j; i < j+8; i++) sum += raw (row+dir[i][0], col+dir[i][1]); RAW(row,col) = (sum + 4) >> 3; } } } else if (tag == 0x401) { /* All-color flat fields */ phase_one_flat_field (1, 2); } else if (tag == 0x416 || tag == 0x410) { phase_one_flat_field (0, 2); } else if (tag == 0x40b) { /* Red+blue flat field */ phase_one_flat_field (0, 4); } else if (tag == 0x412) { fseek (ifp, 36, SEEK_CUR); diff = abs (get2() - ph1.tag_21a); if (mindiff > diff) { mindiff = diff; off_412 = ftell(ifp) - 38; } } fseek (ifp, save, SEEK_SET); } if (off_412) { fseek (ifp, off_412, SEEK_SET); for (i=0; i < 9; i++) head[i] = get4() & 0x7fff; yval[0] = (float *) calloc (head[1]*head[3] + head[2]*head[4], 6); merror (yval[0], "phase_one_correct()"); yval[1] = (float *) (yval[0] + head[1]*head[3]); xval[0] = (ushort *) (yval[1] + head[2]*head[4]); xval[1] = (ushort *) (xval[0] + head[1]*head[3]); get2(); for (i=0; i < 2; i++) for (j=0; j < head[i+1]*head[i+3]; j++) yval[i][j] = getreal(11); for (i=0; i < 2; i++) for (j=0; j < head[i+1]*head[i+3]; j++) xval[i][j] = get2(); for (row=0; row < raw_height; row++) for (col=0; col < raw_width; col++) { cfrac = (float) col * head[3] / raw_width; cfrac -= cip = cfrac; num = RAW(row,col) * 0.5; for (i=cip; i < cip+2; i++) { for (k=j=0; j < head[1]; j++) if (num < xval[0][k = head[1]*i+j]) break; frac = (j == 0 || j == head[1]) ? 0 : (xval[0][k] - num) / (xval[0][k] - xval[0][k-1]); mult[i-cip] = yval[0][k-1] * frac + yval[0][k] * (1-frac); } i = ((mult[0] * (1-cfrac) + mult[1] * cfrac) * row + num) * 2; RAW(row,col) = LIM(i,0,65535); } free (yval[0]); } } void CLASS phase_one_load_raw() { int a, b, i; ushort akey, bkey, mask; fseek (ifp, ph1.key_off, SEEK_SET); akey = get2(); bkey = get2(); mask = ph1.format == 1 ? 0x5555:0x1354; fseek (ifp, data_offset, SEEK_SET); read_shorts (raw_image, raw_width*raw_height); if (ph1.format) for (i=0; i < raw_width*raw_height; i+=2) { a = raw_image[i+0] ^ akey; b = raw_image[i+1] ^ bkey; raw_image[i+0] = (a & mask) | (b & ~mask); raw_image[i+1] = (b & mask) | (a & ~mask); } } unsigned CLASS ph1_bithuff (int nbits, ushort *huff) { static UINT64 bitbuf=0; static int vbits=0; unsigned c; if (nbits == -1) return bitbuf = vbits = 0; if (nbits == 0) return 0; if (vbits < nbits) { bitbuf = bitbuf << 32 | get4(); vbits += 32; } c = bitbuf << (64-vbits) >> (64-nbits); if (huff) { vbits -= huff[c] >> 8; return (uchar) huff[c]; } vbits -= nbits; return c; } #define ph1_bits(n) ph1_bithuff(n,0) #define ph1_huff(h) ph1_bithuff(*h,h+1) void CLASS phase_one_load_raw_c() { static const int length[] = { 8,7,6,9,11,10,5,12,14,13 }; int *offset, len[2], pred[2], row, col, i, j; ushort *pixel; short (*black)[2]; pixel = (ushort *) calloc (raw_width + raw_height*4, 2); merror (pixel, "phase_one_load_raw_c()"); offset = (int *) (pixel + raw_width); fseek (ifp, strip_offset, SEEK_SET); for (row=0; row < raw_height; row++) offset[row] = get4(); black = (short (*)[2]) offset + raw_height; fseek (ifp, ph1.black_off, SEEK_SET); if (ph1.black_off) read_shorts ((ushort *) black[0], raw_height*2); for (i=0; i < 256; i++) curve[i] = i*i / 3.969 + 0.5; for (row=0; row < raw_height; row++) { fseek (ifp, data_offset + offset[row], SEEK_SET); ph1_bits(-1); pred[0] = pred[1] = 0; for (col=0; col < raw_width; col++) { if (col >= (raw_width & -8)) len[0] = len[1] = 14; else if ((col & 7) == 0) for (i=0; i < 2; i++) { for (j=0; j < 5 && !ph1_bits(1); j++); if (j--) len[i] = length[j*2 + ph1_bits(1)]; } if ((i = len[col & 1]) == 14) pixel[col] = pred[col & 1] = ph1_bits(16); else pixel[col] = pred[col & 1] += ph1_bits(i) + 1 - (1 << (i - 1)); if (pred[col & 1] >> 16) derror(); if (ph1.format == 5 && pixel[col] < 256) pixel[col] = curve[pixel[col]]; } for (col=0; col < raw_width; col++) { i = (pixel[col] << 2) - ph1.black + black[row][col >= ph1.split_col]; if (i > 0) RAW(row,col) = i; } } free (pixel); maximum = 0xfffc - ph1.black; } void CLASS hasselblad_load_raw() { struct jhead jh; int row, col, pred[2], len[2], diff, c; if (!ljpeg_start (&jh, 0)) return; order = 0x4949; ph1_bits(-1); for (row=0; row < raw_height; row++) { pred[0] = pred[1] = 0x8000 + load_flags; for (col=0; col < raw_width; col+=2) { FORC(2) len[c] = ph1_huff(jh.huff[0]); FORC(2) { diff = ph1_bits(len[c]); if ((diff & (1 << (len[c]-1))) == 0) diff -= (1 << len[c]) - 1; if (diff == 65535) diff = -32768; RAW(row,col+c) = pred[c] += diff; } } } ljpeg_end (&jh); maximum = 0xffff; } void CLASS leaf_hdr_load_raw() { ushort *pixel=0; unsigned tile=0, r, c, row, col; if (!filters) { pixel = (ushort *) calloc (raw_width, sizeof *pixel); merror (pixel, "leaf_hdr_load_raw()"); } FORC(tiff_samples) for (r=0; r < raw_height; r++) { if (r % tile_length == 0) { fseek (ifp, data_offset + 4*tile++, SEEK_SET); fseek (ifp, get4(), SEEK_SET); } if (filters && c != shot_select) continue; if (filters) pixel = raw_image + r*raw_width; read_shorts (pixel, raw_width); if (!filters && (row = r - top_margin) < height) for (col=0; col < width; col++) image[row*width+col][c] = pixel[col+left_margin]; } if (!filters) { maximum = 0xffff; raw_color = 1; free (pixel); } } void CLASS unpacked_load_raw() { int row, col, bits=0; while (1 << ++bits < maximum); read_shorts (raw_image, raw_width*raw_height); for (row=0; row < raw_height; row++) for (col=0; col < raw_width; col++) if ((RAW(row,col) >>= load_flags) >> bits && (unsigned) (row-top_margin) < height && (unsigned) (col-left_margin) < width) derror(); } void CLASS sinar_4shot_load_raw() { ushort *pixel; unsigned shot, row, col, r, c; if ((shot = shot_select) || half_size) { if (shot) shot--; if (shot > 3) shot = 3; fseek (ifp, data_offset + shot*4, SEEK_SET); fseek (ifp, get4(), SEEK_SET); unpacked_load_raw(); return; } free (raw_image); raw_image = 0; free (image); image = (ushort (*)[4]) calloc ((iheight=height), (iwidth=width)*sizeof *image); merror (image, "sinar_4shot_load_raw()"); pixel = (ushort *) calloc (raw_width, sizeof *pixel); merror (pixel, "sinar_4shot_load_raw()"); for (shot=0; shot < 4; shot++) { fseek (ifp, data_offset + shot*4, SEEK_SET); fseek (ifp, get4(), SEEK_SET); for (row=0; row < raw_height; row++) { read_shorts (pixel, raw_width); if ((r = row-top_margin - (shot >> 1 & 1)) >= height) continue; for (col=0; col < raw_width; col++) { if ((c = col-left_margin - (shot & 1)) >= width) continue; image[r*width+c][FC(row,col)] = pixel[col]; } } } free (pixel); shrink = filters = 0; } void CLASS imacon_full_load_raw() { int row, col; if (!image) return; for (row=0; row < height; row++) for (col=0; col < width; col++) read_shorts (image[row*width+col], 3); } void CLASS packed_load_raw() { int vbits=0, bwide, rbits, bite, half, irow, row, col, val, i; UINT64 bitbuf=0; bwide = raw_width * tiff_bps / 8; bwide += bwide & load_flags >> 7; rbits = bwide * 8 - raw_width * tiff_bps; if (load_flags & 1) bwide = bwide * 16 / 15; bite = 8 + (load_flags & 24); half = (raw_height+1) >> 1; for (irow=0; irow < raw_height; irow++) { row = irow; if (load_flags & 2 && (row = irow % half * 2 + irow / half) == 1 && load_flags & 4) { if (vbits=0, tiff_compress) fseek (ifp, data_offset - (-half*bwide & -2048), SEEK_SET); else { fseek (ifp, 0, SEEK_END); fseek (ifp, ftell(ifp) >> 3 << 2, SEEK_SET); } } for (col=0; col < raw_width; col++) { for (vbits -= tiff_bps; vbits < 0; vbits += bite) { bitbuf <<= bite; for (i=0; i < bite; i+=8) bitbuf |= (unsigned) (fgetc(ifp) << i); } val = bitbuf << (64-tiff_bps-vbits) >> (64-tiff_bps); RAW(row,col ^ (load_flags >> 6 & 1)) = val; if (load_flags & 1 && (col % 10) == 9 && fgetc(ifp) && col < width+left_margin) derror(); } vbits -= rbits; } } void CLASS nokia_load_raw() { uchar *data, *dp; int rev, dwide, row, col, c; rev = 3 * (order == 0x4949); dwide = (raw_width * 5 + 1) / 4; data = (uchar *) malloc (dwide*2); merror (data, "nokia_load_raw()"); for (row=0; row < raw_height; row++) { if (fread (data+dwide, 1, dwide, ifp) < dwide) derror(); FORC(dwide) data[c] = data[dwide+(c ^ rev)]; for (dp=data, col=0; col < raw_width; dp+=5, col+=4) FORC4 RAW(row,col+c) = (dp[c] << 2) | (dp[4] >> (c << 1) & 3); } free (data); maximum = 0x3ff; } void CLASS canon_rmf_load_raw() { int row, col, bits, orow, ocol, c; for (row=0; row < raw_height; row++) for (col=0; col < raw_width-2; col+=3) { bits = get4(); FORC3 { orow = row; if ((ocol = col+c-4) < 0) { ocol += raw_width; if ((orow -= 2) < 0) orow += raw_height; } RAW(orow,ocol) = bits >> (10*c+2) & 0x3ff; } } maximum = 0x3ff; } unsigned CLASS pana_bits (int nbits) { static uchar buf[0x4000]; static int vbits; int byte; if (!nbits) return vbits=0; if (!vbits) { fread (buf+load_flags, 1, 0x4000-load_flags, ifp); fread (buf, 1, load_flags, ifp); } vbits = (vbits - nbits) & 0x1ffff; byte = vbits >> 3 ^ 0x3ff0; return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~(-1 << nbits); } void CLASS panasonic_load_raw() { int row, col, i, j, sh=0, pred[2], nonz[2]; pana_bits(0); for (row=0; row < height; row++) for (col=0; col < raw_width; col++) { if ((i = col % 14) == 0) pred[0] = pred[1] = nonz[0] = nonz[1] = 0; if (i % 3 == 2) sh = 4 >> (3 - pana_bits(2)); if (nonz[i & 1]) { if ((j = pana_bits(8))) { if ((pred[i & 1] -= 0x80 << sh) < 0 || sh == 4) pred[i & 1] &= ~(-1 << sh); pred[i & 1] += j << sh; } } else if ((nonz[i & 1] = pana_bits(8)) || i > 11) pred[i & 1] = nonz[i & 1] << 4 | pana_bits(4); if ((RAW(row,col) = pred[col & 1]) > 4098 && col < width) derror(); } } void CLASS olympus_load_raw() { ushort huff[4096]; int row, col, nbits, sign, low, high, i, c, w, n, nw; int acarry[2][3], *carry, pred, diff; huff[n=0] = 0xc0c; for (i=12; i--; ) FORC(2048 >> i) huff[++n] = (i+1) << 8 | i; fseek (ifp, 7, SEEK_CUR); getbits(-1); for (row=0; row < height; row++) { memset (acarry, 0, sizeof acarry); for (col=0; col < raw_width; col++) { carry = acarry[col & 1]; i = 2 * (carry[2] < 3); for (nbits=2+i; (ushort) carry[0] >> (nbits+i); nbits++); low = (sign = getbits(3)) & 3; sign = sign << 29 >> 31; if ((high = getbithuff(12,huff)) == 12) high = getbits(16-nbits) >> 1; carry[0] = (high << nbits) | getbits(nbits); diff = (carry[0] ^ sign) + carry[1]; carry[1] = (diff*3 + carry[1]) >> 5; carry[2] = carry[0] > 16 ? 0 : carry[2]+1; if (col >= width) continue; if (row < 2 && col < 2) pred = 0; else if (row < 2) pred = RAW(row,col-2); else if (col < 2) pred = RAW(row-2,col); else { w = RAW(row,col-2); n = RAW(row-2,col); nw = RAW(row-2,col-2); if ((w < nw && nw < n) || (n < nw && nw < w)) { if (ABS(w-nw) > 32 || ABS(n-nw) > 32) pred = w + n - nw; else pred = (w + n) >> 1; } else pred = ABS(w-nw) > ABS(n-nw) ? w : n; } if ((RAW(row,col) = pred + ((diff << 2) | low)) >> 12) derror(); } } } void CLASS minolta_rd175_load_raw() { uchar pixel[768]; unsigned irow, box, row, col; for (irow=0; irow < 1481; irow++) { if (fread (pixel, 1, 768, ifp) < 768) derror(); box = irow / 82; row = irow % 82 * 12 + ((box < 12) ? box | 1 : (box-12)*2); switch (irow) { case 1477: case 1479: continue; case 1476: row = 984; break; case 1480: row = 985; break; case 1478: row = 985; box = 1; } if ((box < 12) && (box & 1)) { for (col=0; col < 1533; col++, row ^= 1) if (col != 1) RAW(row,col) = (col+1) & 2 ? pixel[col/2-1] + pixel[col/2+1] : pixel[col/2] << 1; RAW(row,1) = pixel[1] << 1; RAW(row,1533) = pixel[765] << 1; } else for (col=row & 1; col < 1534; col+=2) RAW(row,col) = pixel[col/2] << 1; } maximum = 0xff << 1; } void CLASS quicktake_100_load_raw() { uchar pixel[484][644]; static const short gstep[16] = { -89,-60,-44,-32,-22,-15,-8,-2,2,8,15,22,32,44,60,89 }; static const short rstep[6][4] = { { -3,-1,1,3 }, { -5,-1,1,5 }, { -8,-2,2,8 }, { -13,-3,3,13 }, { -19,-4,4,19 }, { -28,-6,6,28 } }; static const short curve[256] = { 0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27, 28,29,30,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,53, 54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,74,75,76,77,78, 79,80,81,82,83,84,86,88,90,92,94,97,99,101,103,105,107,110,112,114,116, 118,120,123,125,127,129,131,134,136,138,140,142,144,147,149,151,153,155, 158,160,162,164,166,168,171,173,175,177,179,181,184,186,188,190,192,195, 197,199,201,203,205,208,210,212,214,216,218,221,223,226,230,235,239,244, 248,252,257,261,265,270,274,278,283,287,291,296,300,305,309,313,318,322, 326,331,335,339,344,348,352,357,361,365,370,374,379,383,387,392,396,400, 405,409,413,418,422,426,431,435,440,444,448,453,457,461,466,470,474,479, 483,487,492,496,500,508,519,531,542,553,564,575,587,598,609,620,631,643, 654,665,676,687,698,710,721,732,743,754,766,777,788,799,810,822,833,844, 855,866,878,889,900,911,922,933,945,956,967,978,989,1001,1012,1023 }; int rb, row, col, sharp, val=0; getbits(-1); memset (pixel, 0x80, sizeof pixel); for (row=2; row < height+2; row++) { for (col=2+(row & 1); col < width+2; col+=2) { val = ((pixel[row-1][col-1] + 2*pixel[row-1][col+1] + pixel[row][col-2]) >> 2) + gstep[getbits(4)]; pixel[row][col] = val = LIM(val,0,255); if (col < 4) pixel[row][col-2] = pixel[row+1][~row & 1] = val; if (row == 2) pixel[row-1][col+1] = pixel[row-1][col+3] = val; } pixel[row][col] = val; } for (rb=0; rb < 2; rb++) for (row=2+rb; row < height+2; row+=2) for (col=3-(row & 1); col < width+2; col+=2) { if (row < 4 || col < 4) sharp = 2; else { val = ABS(pixel[row-2][col] - pixel[row][col-2]) + ABS(pixel[row-2][col] - pixel[row-2][col-2]) + ABS(pixel[row][col-2] - pixel[row-2][col-2]); sharp = val < 4 ? 0 : val < 8 ? 1 : val < 16 ? 2 : val < 32 ? 3 : val < 48 ? 4 : 5; } val = ((pixel[row-2][col] + pixel[row][col-2]) >> 1) + rstep[sharp][getbits(2)]; pixel[row][col] = val = LIM(val,0,255); if (row < 4) pixel[row-2][col+2] = val; if (col < 4) pixel[row+2][col-2] = val; } for (row=2; row < height+2; row++) for (col=3-(row & 1); col < width+2; col+=2) { val = ((pixel[row][col-1] + (pixel[row][col] << 2) + pixel[row][col+1]) >> 1) - 0x100; pixel[row][col] = LIM(val,0,255); } for (row=0; row < height; row++) for (col=0; col < width; col++) RAW(row,col) = curve[pixel[row+2][col+2]]; maximum = 0x3ff; } #define radc_token(tree) ((signed char) getbithuff(8,huff[tree])) #define FORYX for (y=1; y < 3; y++) for (x=col+1; x >= col; x--) #define PREDICTOR (c ? (buf[c][y-1][x] + buf[c][y][x+1]) / 2 \ : (buf[c][y-1][x+1] + 2*buf[c][y-1][x] + buf[c][y][x+1]) / 4) void CLASS kodak_radc_load_raw() { static const char src[] = { 1,1, 2,3, 3,4, 4,2, 5,7, 6,5, 7,6, 7,8, 1,0, 2,1, 3,3, 4,4, 5,2, 6,7, 7,6, 8,5, 8,8, 2,1, 2,3, 3,0, 3,2, 3,4, 4,6, 5,5, 6,7, 6,8, 2,0, 2,1, 2,3, 3,2, 4,4, 5,6, 6,7, 7,5, 7,8, 2,1, 2,4, 3,0, 3,2, 3,3, 4,7, 5,5, 6,6, 6,8, 2,3, 3,1, 3,2, 3,4, 3,5, 3,6, 4,7, 5,0, 5,8, 2,3, 2,6, 3,0, 3,1, 4,4, 4,5, 4,7, 5,2, 5,8, 2,4, 2,7, 3,3, 3,6, 4,1, 4,2, 4,5, 5,0, 5,8, 2,6, 3,1, 3,3, 3,5, 3,7, 3,8, 4,0, 5,2, 5,4, 2,0, 2,1, 3,2, 3,3, 4,4, 4,5, 5,6, 5,7, 4,8, 1,0, 2,2, 2,-2, 1,-3, 1,3, 2,-17, 2,-5, 2,5, 2,17, 2,-7, 2,2, 2,9, 2,18, 2,-18, 2,-9, 2,-2, 2,7, 2,-28, 2,28, 3,-49, 3,-9, 3,9, 4,49, 5,-79, 5,79, 2,-1, 2,13, 2,26, 3,39, 4,-16, 5,55, 6,-37, 6,76, 2,-26, 2,-13, 2,1, 3,-39, 4,16, 5,-55, 6,-76, 6,37 }; ushort huff[19][256]; int row, col, tree, nreps, rep, step, i, c, s, r, x, y, val; short last[3] = { 16,16,16 }, mul[3], buf[3][3][386]; static const ushort pt[] = { 0,0, 1280,1344, 2320,3616, 3328,8000, 4095,16383, 65535,16383 }; for (i=2; i < 12; i+=2) for (c=pt[i-2]; c <= pt[i]; c++) curve[c] = (float) (c-pt[i-2]) / (pt[i]-pt[i-2]) * (pt[i+1]-pt[i-1]) + pt[i-1] + 0.5; for (s=i=0; i < sizeof src; i+=2) FORC(256 >> src[i]) huff[0][s++] = src[i] << 8 | (uchar) src[i+1]; s = kodak_cbpp == 243 ? 2 : 3; FORC(256) huff[18][c] = (8-s) << 8 | c >> s << s | 1 << (s-1); getbits(-1); for (i=0; i < sizeof(buf)/sizeof(short); i++) buf[0][0][i] = 2048; for (row=0; row < height; row+=4) { FORC3 mul[c] = getbits(6); FORC3 { val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c]; s = val > 65564 ? 10:12; x = ~(-1 << (s-1)); val <<= 12-s; for (i=0; i < sizeof(buf[0])/sizeof(short); i++) buf[c][0][i] = (buf[c][0][i] * val + x) >> s; last[c] = mul[c]; for (r=0; r <= !c; r++) { buf[c][1][width/2] = buf[c][2][width/2] = mul[c] << 7; for (tree=1, col=width/2; col > 0; ) { if ((tree = radc_token(tree))) { col -= 2; if (tree == 8) FORYX buf[c][y][x] = (uchar) radc_token(18) * mul[c]; else FORYX buf[c][y][x] = radc_token(tree+10) * 16 + PREDICTOR; } else do { nreps = (col > 2) ? radc_token(9) + 1 : 1; for (rep=0; rep < 8 && rep < nreps && col > 0; rep++) { col -= 2; FORYX buf[c][y][x] = PREDICTOR; if (rep & 1) { step = radc_token(10) << 4; FORYX buf[c][y][x] += step; } } } while (nreps == 9); } for (y=0; y < 2; y++) for (x=0; x < width/2; x++) { val = (buf[c][y+1][x] << 4) / mul[c]; if (val < 0) val = 0; if (c) RAW(row+y*2+c-1,x*2+2-c) = val; else RAW(row+r*2+y,x*2+y) = val; } memcpy (buf[c][0]+!c, buf[c][2], sizeof buf[c][0]-2*!c); } } for (y=row; y < row+4; y++) for (x=0; x < width; x++) if ((x+y) & 1) { r = x ? x-1 : x+1; s = x+1 < width ? x+1 : x-1; val = (RAW(y,x)-2048)*2 + (RAW(y,r)+RAW(y,s))/2; if (val < 0) val = 0; RAW(y,x) = val; } } for (i=0; i < height*width; i++) raw_image[i] = curve[raw_image[i]]; maximum = 0x3fff; } #undef FORYX #undef PREDICTOR #ifdef NO_JPEG void CLASS kodak_jpeg_load_raw() {} void CLASS lossy_dng_load_raw() {} #else METHODDEF(boolean) fill_input_buffer (j_decompress_ptr cinfo) { static uchar jpeg_buffer[4096]; size_t nbytes; nbytes = fread (jpeg_buffer, 1, 4096, ifp); swab (jpeg_buffer, jpeg_buffer, nbytes); cinfo->src->next_input_byte = jpeg_buffer; cinfo->src->bytes_in_buffer = nbytes; return TRUE; } void CLASS kodak_jpeg_load_raw() { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPARRAY buf; JSAMPLE (*pixel)[3]; int row, col; cinfo.err = jpeg_std_error (&jerr); jpeg_create_decompress (&cinfo); jpeg_stdio_src (&cinfo, ifp); cinfo.src->fill_input_buffer = fill_input_buffer; jpeg_read_header (&cinfo, TRUE); jpeg_start_decompress (&cinfo); if ((cinfo.output_width != width ) || (cinfo.output_height*2 != height ) || (cinfo.output_components != 3 )) { fprintf (stderr,_("%s: incorrect JPEG dimensions\n"), ifname); jpeg_destroy_decompress (&cinfo); longjmp (failure, 3); } buf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, width*3, 1); while (cinfo.output_scanline < cinfo.output_height) { row = cinfo.output_scanline * 2; jpeg_read_scanlines (&cinfo, buf, 1); pixel = (JSAMPLE (*)[3]) buf[0]; for (col=0; col < width; col+=2) { RAW(row+0,col+0) = pixel[col+0][1] << 1; RAW(row+1,col+1) = pixel[col+1][1] << 1; RAW(row+0,col+1) = pixel[col][0] + pixel[col+1][0]; RAW(row+1,col+0) = pixel[col][2] + pixel[col+1][2]; } } jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); maximum = 0xff << 1; } void CLASS lossy_dng_load_raw() { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPARRAY buf; JSAMPLE (*pixel)[3]; unsigned sorder=order, ntags, opcode, deg, i, j, c; unsigned save=data_offset-4, trow=0, tcol=0, row, col; ushort curve[3][256]; double coeff[9], tot; fseek (ifp, meta_offset, SEEK_SET); order = 0x4d4d; ntags = get4(); while (ntags--) { opcode = get4(); get4(); get4(); if (opcode != 8) { fseek (ifp, get4(), SEEK_CUR); continue; } fseek (ifp, 20, SEEK_CUR); if ((c = get4()) > 2) break; fseek (ifp, 12, SEEK_CUR); if ((deg = get4()) > 8) break; for (i=0; i <= deg && i < 9; i++) coeff[i] = getreal(12); for (i=0; i < 256; i++) { for (tot=j=0; j <= deg; j++) tot += coeff[j] * pow(i/255.0, j); curve[c][i] = tot*0xffff; } } order = sorder; cinfo.err = jpeg_std_error (&jerr); jpeg_create_decompress (&cinfo); while (trow < raw_height) { fseek (ifp, save+=4, SEEK_SET); if (tile_length < INT_MAX) fseek (ifp, get4(), SEEK_SET); jpeg_stdio_src (&cinfo, ifp); jpeg_read_header (&cinfo, TRUE); jpeg_start_decompress (&cinfo); buf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width*3, 1); while (cinfo.output_scanline < cinfo.output_height && (row = trow + cinfo.output_scanline) < height) { jpeg_read_scanlines (&cinfo, buf, 1); pixel = (JSAMPLE (*)[3]) buf[0]; for (col=0; col < cinfo.output_width && tcol+col < width; col++) { FORC3 image[row*width+tcol+col][c] = curve[c][pixel[col][c]]; } } jpeg_abort_decompress (&cinfo); if ((tcol += tile_width) >= raw_width) trow += tile_length + (tcol = 0); } jpeg_destroy_decompress (&cinfo); maximum = 0xffff; } #endif void CLASS kodak_dc120_load_raw() { static const int mul[4] = { 162, 192, 187, 92 }; static const int add[4] = { 0, 636, 424, 212 }; uchar pixel[848]; int row, shift, col; for (row=0; row < height; row++) { if (fread (pixel, 1, 848, ifp) < 848) derror(); shift = row * mul[row & 3] + add[row & 3]; for (col=0; col < width; col++) RAW(row,col) = (ushort) pixel[(col + shift) % 848]; } maximum = 0xff; } void CLASS eight_bit_load_raw() { uchar *pixel; unsigned row, col; pixel = (uchar *) calloc (raw_width, sizeof *pixel); merror (pixel, "eight_bit_load_raw()"); for (row=0; row < raw_height; row++) { if (fread (pixel, 1, raw_width, ifp) < raw_width) derror(); for (col=0; col < raw_width; col++) RAW(row,col) = curve[pixel[col]]; } free (pixel); maximum = curve[0xff]; } void CLASS kodak_yrgb_load_raw() { uchar *pixel; int row, col, y, cb, cr, rgb[3], c; pixel = (uchar *) calloc (raw_width, 3*sizeof *pixel); merror (pixel, "kodak_yrgb_load_raw()"); for (row=0; row < height; row++) { if (~row & 1) if (fread (pixel, raw_width, 3, ifp) < 3) derror(); for (col=0; col < raw_width; col++) { y = pixel[width*2*(row & 1) + col]; cb = pixel[width + (col & -2)] - 128; cr = pixel[width + (col & -2)+1] - 128; rgb[1] = y-((cb + cr + 2) >> 2); rgb[2] = rgb[1] + cb; rgb[0] = rgb[1] + cr; FORC3 image[row*width+col][c] = curve[LIM(rgb[c],0,255)]; } } free (pixel); maximum = curve[0xff]; } void CLASS kodak_262_load_raw() { static const uchar kodak_tree[2][26] = { { 0,1,5,1,1,2,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 }, { 0,3,1,1,1,1,1,2,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9 } }; ushort *huff[2]; uchar *pixel; int *strip, ns, c, row, col, chess, pi=0, pi1, pi2, pred, val; FORC(2) huff[c] = make_decoder (kodak_tree[c]); ns = (raw_height+63) >> 5; pixel = (uchar *) malloc (raw_width*32 + ns*4); merror (pixel, "kodak_262_load_raw()"); strip = (int *) (pixel + raw_width*32); order = 0x4d4d; FORC(ns) strip[c] = get4(); for (row=0; row < raw_height; row++) { if ((row & 31) == 0) { fseek (ifp, strip[row >> 5], SEEK_SET); getbits(-1); pi = 0; } for (col=0; col < raw_width; col++) { chess = (row + col) & 1; pi1 = chess ? pi-2 : pi-raw_width-1; pi2 = chess ? pi-2*raw_width : pi-raw_width+1; if (col <= chess) pi1 = -1; if (pi1 < 0) pi1 = pi2; if (pi2 < 0) pi2 = pi1; if (pi1 < 0 && col > 1) pi1 = pi2 = pi-2; pred = (pi1 < 0) ? 0 : (pixel[pi1] + pixel[pi2]) >> 1; pixel[pi] = val = pred + ljpeg_diff (huff[chess]); if (val >> 8) derror(); val = curve[pixel[pi++]]; RAW(row,col) = val; } } free (pixel); FORC(2) free (huff[c]); } int CLASS kodak_65000_decode (short *out, int bsize) { uchar c, blen[768]; ushort raw[6]; INT64 bitbuf=0; int save, bits=0, i, j, len, diff; save = ftell(ifp); bsize = (bsize + 3) & -4; for (i=0; i < bsize; i+=2) { c = fgetc(ifp); if ((blen[i ] = c & 15) > 12 || (blen[i+1] = c >> 4) > 12 ) { fseek (ifp, save, SEEK_SET); for (i=0; i < bsize; i+=8) { read_shorts (raw, 6); out[i ] = raw[0] >> 12 << 8 | raw[2] >> 12 << 4 | raw[4] >> 12; out[i+1] = raw[1] >> 12 << 8 | raw[3] >> 12 << 4 | raw[5] >> 12; for (j=0; j < 6; j++) out[i+2+j] = raw[j] & 0xfff; } return 1; } } if ((bsize & 7) == 4) { bitbuf = fgetc(ifp) << 8; bitbuf += fgetc(ifp); bits = 16; } for (i=0; i < bsize; i++) { len = blen[i]; if (bits < len) { for (j=0; j < 32; j+=8) bitbuf += (INT64) fgetc(ifp) << (bits+(j^8)); bits += 32; } diff = bitbuf & (0xffff >> (16-len)); bitbuf >>= len; bits -= len; if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; out[i] = diff; } return 0; } void CLASS kodak_65000_load_raw() { short buf[256]; int row, col, len, pred[2], ret, i; for (row=0; row < height; row++) for (col=0; col < width; col+=256) { pred[0] = pred[1] = 0; len = MIN (256, width-col); ret = kodak_65000_decode (buf, len); for (i=0; i < len; i++) if ((RAW(row,col+i) = curve[ret ? buf[i] : (pred[i & 1] += buf[i])]) >> 12) derror(); } } void CLASS kodak_ycbcr_load_raw() { short buf[384], *bp; int row, col, len, c, i, j, k, y[2][2], cb, cr, rgb[3]; ushort *ip; if (!image) return; for (row=0; row < height; row+=2) for (col=0; col < width; col+=128) { len = MIN (128, width-col); kodak_65000_decode (buf, len*3); y[0][1] = y[1][1] = cb = cr = 0; for (bp=buf, i=0; i < len; i+=2, bp+=2) { cb += bp[4]; cr += bp[5]; rgb[1] = -((cb + cr + 2) >> 2); rgb[2] = rgb[1] + cb; rgb[0] = rgb[1] + cr; for (j=0; j < 2; j++) for (k=0; k < 2; k++) { if ((y[j][k] = y[j][k^1] + *bp++) >> 10) derror(); ip = image[(row+j)*width + col+i+k]; FORC3 ip[c] = curve[LIM(y[j][k]+rgb[c], 0, 0xfff)]; } } } } void CLASS kodak_rgb_load_raw() { short buf[768], *bp; int row, col, len, c, i, rgb[3]; ushort *ip=image[0]; if (raw_image) free (raw_image); raw_image = 0; for (row=0; row < height; row++) for (col=0; col < width; col+=256) { len = MIN (256, width-col); kodak_65000_decode (buf, len*3); memset (rgb, 0, sizeof rgb); for (bp=buf, i=0; i < len; i++, ip+=4) FORC3 if ((ip[c] = rgb[c] += *bp++) >> 12) derror(); } } void CLASS kodak_thumb_load_raw() { int row, col; colors = thumb_misc >> 5; for (row=0; row < height; row++) for (col=0; col < width; col++) read_shorts (image[row*width+col], colors); maximum = (1 << (thumb_misc & 31)) - 1; } void CLASS sony_decrypt (unsigned *data, int len, int start, int key) { static unsigned pad[128], p; if (start) { for (p=0; p < 4; p++) pad[p] = key = key * 48828125 + 1; pad[3] = pad[3] << 1 | (pad[0]^pad[2]) >> 31; for (p=4; p < 127; p++) pad[p] = (pad[p-4]^pad[p-2]) << 1 | (pad[p-3]^pad[p-1]) >> 31; for (p=0; p < 127; p++) pad[p] = htonl(pad[p]); } while (len--) *data++ ^= pad[p++ & 127] = pad[(p+1) & 127] ^ pad[(p+65) & 127]; } void CLASS sony_load_raw() { uchar head[40]; ushort *pixel; unsigned i, key, row, col; fseek (ifp, 200896, SEEK_SET); fseek (ifp, (unsigned) fgetc(ifp)*4 - 1, SEEK_CUR); order = 0x4d4d; key = get4(); fseek (ifp, 164600, SEEK_SET); fread (head, 1, 40, ifp); sony_decrypt ((unsigned int *) head, 10, 1, key); for (i=26; i-- > 22; ) key = key << 8 | head[i]; fseek (ifp, data_offset, SEEK_SET); for (row=0; row < raw_height; row++) { pixel = raw_image + row*raw_width; if (fread (pixel, 2, raw_width, ifp) < raw_width) derror(); sony_decrypt ((unsigned int *) pixel, raw_width/2, !row, key); for (col=0; col < raw_width; col++) if ((pixel[col] = ntohs(pixel[col])) >> 14) derror(); } maximum = 0x3ff0; } void CLASS sony_arw_load_raw() { ushort huff[32768]; static const ushort tab[18] = { 0xf11,0xf10,0xe0f,0xd0e,0xc0d,0xb0c,0xa0b,0x90a,0x809, 0x708,0x607,0x506,0x405,0x304,0x303,0x300,0x202,0x201 }; int i, c, n, col, row, len, diff, sum=0; for (n=i=0; i < 18; i++) FORC(32768 >> (tab[i] >> 8)) huff[n++] = tab[i]; getbits(-1); for (col = raw_width; col--; ) for (row=0; row < raw_height+1; row+=2) { if (row == raw_height) row = 1; len = getbithuff(15,huff); diff = getbits(len); if ((diff & (1 << (len-1))) == 0) diff -= (1 << len) - 1; if ((sum += diff) >> 12) derror(); if (row < height) RAW(row,col) = sum; } } void CLASS sony_arw2_load_raw() { uchar *data, *dp; ushort pix[16]; int row, col, val, max, min, imax, imin, sh, bit, i; data = (uchar *) malloc (raw_width); merror (data, "sony_arw2_load_raw()"); for (row=0; row < height; row++) { fread (data, 1, raw_width, ifp); for (dp=data, col=0; col < raw_width-30; dp+=16) { max = 0x7ff & (val = sget4(dp)); min = 0x7ff & val >> 11; imax = 0x0f & val >> 22; imin = 0x0f & val >> 26; for (sh=0; sh < 4 && 0x80 << sh <= max-min; sh++); for (bit=30, i=0; i < 16; i++) if (i == imax) pix[i] = max; else if (i == imin) pix[i] = min; else { pix[i] = ((sget2(dp+(bit >> 3)) >> (bit & 7) & 0x7f) << sh) + min; if (pix[i] > 0x7ff) pix[i] = 0x7ff; bit += 7; } for (i=0; i < 16; i++, col+=2) RAW(row,col) = curve[pix[i] << 1] >> 2; col -= col & 1 ? 1:31; } } free (data); } void CLASS samsung_load_raw() { int row, col, c, i, dir, op[4], len[4]; order = 0x4949; for (row=0; row < raw_height; row++) { fseek (ifp, strip_offset+row*4, SEEK_SET); fseek (ifp, data_offset+get4(), SEEK_SET); ph1_bits(-1); FORC4 len[c] = row < 2 ? 7:4; for (col=0; col < raw_width; col+=16) { dir = ph1_bits(1); FORC4 op[c] = ph1_bits(2); FORC4 switch (op[c]) { case 3: len[c] = ph1_bits(4); break; case 2: len[c]--; break; case 1: len[c]++; } for (c=0; c < 16; c+=2) { i = len[((c & 1) << 1) | (c >> 3)]; RAW(row,col+c) = ((signed) ph1_bits(i) << (32-i) >> (32-i)) + (dir ? RAW(row+(~c | -2),col+c) : col ? RAW(row,col+(c | -2)) : 128); if (c == 14) c = -1; } } } } #define HOLE(row) ((holes >> (((row) - raw_height) & 7)) & 1) /* Kudos to Rich Taylor for figuring out SMaL's compression algorithm. */ void CLASS smal_decode_segment (unsigned seg[2][2], int holes) { uchar hist[3][13] = { { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, { 7, 7, 0, 0, 63, 55, 47, 39, 31, 23, 15, 7, 0 }, { 3, 3, 0, 0, 63, 47, 31, 15, 0 } }; int low, high=0xff, carry=0, nbits=8; int pix, s, count, bin, next, i, sym[3]; uchar diff, pred[]={0,0}; ushort data=0, range=0; fseek (ifp, seg[0][1]+1, SEEK_SET); getbits(-1); for (pix=seg[0][0]; pix < seg[1][0]; pix++) { for (s=0; s < 3; s++) { data = data << nbits | getbits(nbits); if (carry < 0) carry = (nbits += carry+1) < 1 ? nbits-1 : 0; while (--nbits >= 0) if ((data >> nbits & 0xff) == 0xff) break; if (nbits > 0) data = ((data & ((1 << (nbits-1)) - 1)) << 1) | ((data + (((data & (1 << (nbits-1)))) << 1)) & (-1 << nbits)); if (nbits >= 0) { data += getbits(1); carry = nbits - 8; } count = ((((data-range+1) & 0xffff) << 2) - 1) / (high >> 4); for (bin=0; hist[s][bin+5] > count; bin++); low = hist[s][bin+5] * (high >> 4) >> 2; if (bin) high = hist[s][bin+4] * (high >> 4) >> 2; high -= low; for (nbits=0; high << nbits < 128; nbits++); range = (range+low) << nbits; high <<= nbits; next = hist[s][1]; if (++hist[s][2] > hist[s][3]) { next = (next+1) & hist[s][0]; hist[s][3] = (hist[s][next+4] - hist[s][next+5]) >> 2; hist[s][2] = 1; } if (hist[s][hist[s][1]+4] - hist[s][hist[s][1]+5] > 1) { if (bin < hist[s][1]) for (i=bin; i < hist[s][1]; i++) hist[s][i+5]--; else if (next <= bin) for (i=hist[s][1]; i < bin; i++) hist[s][i+5]++; } hist[s][1] = next; sym[s] = bin; } diff = sym[2] << 5 | sym[1] << 2 | (sym[0] & 3); if (sym[0] & 4) diff = diff ? -diff : 0x80; if (ftell(ifp) + 12 >= seg[1][1]) diff = 0; raw_image[pix] = pred[pix & 1] += diff; if (!(pix & 1) && HOLE(pix / raw_width)) pix += 2; } maximum = 0xff; } void CLASS smal_v6_load_raw() { unsigned seg[2][2]; fseek (ifp, 16, SEEK_SET); seg[0][0] = 0; seg[0][1] = get2(); seg[1][0] = raw_width * raw_height; seg[1][1] = INT_MAX; smal_decode_segment (seg, 0); } int CLASS median4 (int *p) { int min, max, sum, i; min = max = sum = p[0]; for (i=1; i < 4; i++) { sum += p[i]; if (min > p[i]) min = p[i]; if (max < p[i]) max = p[i]; } return (sum - min - max) >> 1; } void CLASS fill_holes (int holes) { int row, col, val[4]; for (row=2; row < height-2; row++) { if (!HOLE(row)) continue; for (col=1; col < width-1; col+=4) { val[0] = RAW(row-1,col-1); val[1] = RAW(row-1,col+1); val[2] = RAW(row+1,col-1); val[3] = RAW(row+1,col+1); RAW(row,col) = median4(val); } for (col=2; col < width-2; col+=4) if (HOLE(row-2) || HOLE(row+2)) RAW(row,col) = (RAW(row,col-2) + RAW(row,col+2)) >> 1; else { val[0] = RAW(row,col-2); val[1] = RAW(row,col+2); val[2] = RAW(row-2,col); val[3] = RAW(row+2,col); RAW(row,col) = median4(val); } } } void CLASS smal_v9_load_raw() { unsigned seg[256][2], offset, nseg, holes, i; fseek (ifp, 67, SEEK_SET); offset = get4(); nseg = fgetc(ifp); fseek (ifp, offset, SEEK_SET); for (i=0; i < nseg*2; i++) seg[0][i] = get4() + data_offset*(i & 1); fseek (ifp, 78, SEEK_SET); holes = fgetc(ifp); fseek (ifp, 88, SEEK_SET); seg[nseg][0] = raw_height * raw_width; seg[nseg][1] = get4() + data_offset; for (i=0; i < nseg; i++) smal_decode_segment (seg+i, holes); if (holes) fill_holes (holes); } void CLASS redcine_load_raw() { #ifndef NO_JASPER int c, row, col; jas_stream_t *in; jas_image_t *jimg; jas_matrix_t *jmat; jas_seqent_t *data; ushort *img, *pix; jas_init(); in = jas_stream_fopen (ifname, "rb"); jas_stream_seek (in, data_offset+20, SEEK_SET); jimg = jas_image_decode (in, -1, 0); if (!jimg) longjmp (failure, 3); jmat = jas_matrix_create (height/2, width/2); merror (jmat, "redcine_load_raw()"); img = (ushort *) calloc ((height+2), (width+2)*2); merror (img, "redcine_load_raw()"); FORC4 { jas_image_readcmpt (jimg, c, 0, 0, width/2, height/2, jmat); data = jas_matrix_getref (jmat, 0, 0); for (row = c >> 1; row < height; row+=2) for (col = c & 1; col < width; col+=2) img[(row+1)*(width+2)+col+1] = data[(row/2)*(width/2)+col/2]; } for (col=1; col <= width; col++) { img[col] = img[2*(width+2)+col]; img[(height+1)*(width+2)+col] = img[(height-1)*(width+2)+col]; } for (row=0; row < height+2; row++) { img[row*(width+2)] = img[row*(width+2)+2]; img[(row+1)*(width+2)-1] = img[(row+1)*(width+2)-3]; } for (row=1; row <= height; row++) { pix = img + row*(width+2) + (col = 1 + (FC(row,1) & 1)); for ( ; col <= width; col+=2, pix+=2) { c = (((pix[0] - 0x800) << 3) + pix[-(width+2)] + pix[width+2] + pix[-1] + pix[1]) >> 2; pix[0] = LIM(c,0,4095); } } for (row=0; row < height; row++) for (col=0; col < width; col++) RAW(row,col) = curve[img[(row+1)*(width+2)+col+1]]; free (img); jas_matrix_destroy (jmat); jas_image_destroy (jimg); jas_stream_close (in); #endif } /* RESTRICTED code starts here */ void CLASS foveon_decoder (unsigned size, unsigned code) { static unsigned huff[1024]; struct decode *cur; int i, len; if (!code) { for (i=0; i < size; i++) huff[i] = get4(); memset (first_decode, 0, sizeof first_decode); free_decode = first_decode; } cur = free_decode++; if (free_decode > first_decode+2048) { fprintf (stderr,_("%s: decoder table overflow\n"), ifname); longjmp (failure, 2); } if (code) for (i=0; i < size; i++) if (huff[i] == code) { cur->leaf = i; return; } if ((len = code >> 27) > 26) return; code = (len+1) << 27 | (code & 0x3ffffff) << 1; cur->branch[0] = free_decode; foveon_decoder (size, code); cur->branch[1] = free_decode; foveon_decoder (size, code+1); } void CLASS foveon_thumb() { unsigned bwide, row, col, bitbuf=0, bit=1, c, i; char *buf; struct decode *dindex; short pred[3]; bwide = get4(); fprintf (ofp, "P6\n%d %d\n255\n", thumb_width, thumb_height); if (bwide > 0) { if (bwide < thumb_width*3) return; buf = (char *) malloc (bwide); merror (buf, "foveon_thumb()"); for (row=0; row < thumb_height; row++) { fread (buf, 1, bwide, ifp); fwrite (buf, 3, thumb_width, ofp); } free (buf); return; } foveon_decoder (256, 0); for (row=0; row < thumb_height; row++) { memset (pred, 0, sizeof pred); if (!bit) get4(); for (bit=col=0; col < thumb_width; col++) FORC3 { for (dindex=first_decode; dindex->branch[0]; ) { if ((bit = (bit-1) & 31) == 31) for (i=0; i < 4; i++) bitbuf = (bitbuf << 8) + fgetc(ifp); dindex = dindex->branch[bitbuf >> bit & 1]; } pred[c] += dindex->leaf; fputc (pred[c], ofp); } } } void CLASS foveon_sd_load_raw() { struct decode *dindex; short diff[1024]; unsigned bitbuf=0; int pred[3], row, col, bit=-1, c, i; read_shorts ((ushort *) diff, 1024); if (!load_flags) foveon_decoder (1024, 0); for (row=0; row < height; row++) { memset (pred, 0, sizeof pred); if (!bit && !load_flags && atoi(model+2) < 14) get4(); for (col=bit=0; col < width; col++) { if (load_flags) { bitbuf = get4(); FORC3 pred[2-c] += diff[bitbuf >> c*10 & 0x3ff]; } else FORC3 { for (dindex=first_decode; dindex->branch[0]; ) { if ((bit = (bit-1) & 31) == 31) for (i=0; i < 4; i++) bitbuf = (bitbuf << 8) + fgetc(ifp); dindex = dindex->branch[bitbuf >> bit & 1]; } pred[c] += diff[dindex->leaf]; if (pred[c] >> 16 && ~pred[c] >> 16) derror(); } FORC3 image[row*width+col][c] = pred[c]; } } } void CLASS foveon_huff (ushort *huff) { int i, j, clen, code; huff[0] = 8; for (i=0; i < 13; i++) { clen = getc(ifp); code = getc(ifp); for (j=0; j < 256 >> clen; ) huff[code+ ++j] = clen << 8 | i; } get2(); } void CLASS foveon_dp_load_raw() { unsigned c, roff[4], row, col, diff; ushort huff[512], vpred[2][2], hpred[2]; fseek (ifp, 8, SEEK_CUR); foveon_huff (huff); roff[0] = 48; FORC3 roff[c+1] = -(-(roff[c] + get4()) & -16); FORC3 { fseek (ifp, data_offset+roff[c], SEEK_SET); getbits(-1); vpred[0][0] = vpred[0][1] = vpred[1][0] = vpred[1][1] = 512; for (row=0; row < height; row++) { for (col=0; col < width; col++) { diff = ljpeg_diff(huff); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; image[row*width+col][c] = hpred[col & 1]; } } } } void CLASS foveon_load_camf() { unsigned type, wide, high, i, j, row, col, diff; ushort huff[258], vpred[2][2] = {{512,512},{512,512}}, hpred[2]; fseek (ifp, meta_offset, SEEK_SET); type = get4(); get4(); get4(); wide = get4(); high = get4(); if (type == 2) { fread (meta_data, 1, meta_length, ifp); for (i=0; i < meta_length; i++) { high = (high * 1597 + 51749) % 244944; wide = high * (INT64) 301593171 >> 24; meta_data[i] ^= ((((high << 8) - wide) >> 1) + wide) >> 17; } } else if (type == 4) { free (meta_data); meta_data = (char *) malloc (meta_length = wide*high*3/2); merror (meta_data, "foveon_load_camf()"); foveon_huff (huff); get4(); getbits(-1); for (j=row=0; row < high; row++) { for (col=0; col < wide; col++) { diff = ljpeg_diff(huff); if (col < 2) hpred[col] = vpred[row & 1][col] += diff; else hpred[col & 1] += diff; if (col & 1) { meta_data[j++] = hpred[0] >> 4; meta_data[j++] = hpred[0] << 4 | hpred[1] >> 8; meta_data[j++] = hpred[1]; } } } } else fprintf (stderr,_("%s has unknown CAMF type %d.\n"), ifname, type); } const char * CLASS foveon_camf_param (const char *block, const char *param) { unsigned idx, num; char *pos, *cp, *dp; for (idx=0; idx < meta_length; idx += sget4(pos+8)) { pos = meta_data + idx; if (strncmp (pos, "CMb", 3)) break; if (pos[3] != 'P') continue; if (strcmp (block, pos+sget4(pos+12))) continue; cp = pos + sget4(pos+16); num = sget4(cp); dp = pos + sget4(cp+4); while (num--) { cp += 8; if (!strcmp (param, dp+sget4(cp))) return dp+sget4(cp+4); } } return 0; } void * CLASS foveon_camf_matrix (unsigned dim[3], const char *name) { unsigned i, idx, type, ndim, size, *mat; char *pos, *cp, *dp; double dsize; for (idx=0; idx < meta_length; idx += sget4(pos+8)) { pos = meta_data + idx; if (strncmp (pos, "CMb", 3)) break; if (pos[3] != 'M') continue; if (strcmp (name, pos+sget4(pos+12))) continue; dim[0] = dim[1] = dim[2] = 1; cp = pos + sget4(pos+16); type = sget4(cp); if ((ndim = sget4(cp+4)) > 3) break; dp = pos + sget4(cp+8); for (i=ndim; i--; ) { cp += 12; dim[i] = sget4(cp); } if ((dsize = (double) dim[0]*dim[1]*dim[2]) > meta_length/4) break; mat = (unsigned *) malloc ((size = dsize) * 4); merror (mat, "foveon_camf_matrix()"); for (i=0; i < size; i++) if (type && type != 6) mat[i] = sget4(dp + i*4); else mat[i] = sget4(dp + i*2) & 0xffff; return mat; } fprintf (stderr,_("%s: \"%s\" matrix not found!\n"), ifname, name); return 0; } int CLASS foveon_fixed (void *ptr, int size, const char *name) { void *dp; unsigned dim[3]; if (!name) return 0; dp = foveon_camf_matrix (dim, name); if (!dp) return 0; memcpy (ptr, dp, size*4); free (dp); return 1; } float CLASS foveon_avg (short *pix, int range[2], float cfilt) { int i; float val, min=FLT_MAX, max=-FLT_MAX, sum=0; for (i=range[0]; i <= range[1]; i++) { sum += val = pix[i*4] + (pix[i*4]-pix[(i-1)*4]) * cfilt; if (min > val) min = val; if (max < val) max = val; } if (range[1] - range[0] == 1) return sum/2; return (sum - min - max) / (range[1] - range[0] - 1); } short * CLASS foveon_make_curve (double max, double mul, double filt) { short *curve; unsigned i, size; double x; if (!filt) filt = 0.8; size = 4*M_PI*max / filt; if (size == UINT_MAX) size--; curve = (short *) calloc (size+1, sizeof *curve); merror (curve, "foveon_make_curve()"); curve[0] = size; for (i=0; i < size; i++) { x = i*filt/max/4; curve[i+1] = (cos(x)+1)/2 * tanh(i*filt/mul) * mul + 0.5; } return curve; } void CLASS foveon_make_curves (short **curvep, float dq[3], float div[3], float filt) { double mul[3], max=0; int c; FORC3 mul[c] = dq[c]/div[c]; FORC3 if (max < mul[c]) max = mul[c]; FORC3 curvep[c] = foveon_make_curve (max, mul[c], filt); } int CLASS foveon_apply_curve (short *curve, int i) { if (abs(i) >= curve[0]) return 0; return i < 0 ? -curve[1-i] : curve[1+i]; } #define image ((short (*)[4]) image) void CLASS foveon_interpolate() { static const short hood[] = { -1,-1, -1,0, -1,1, 0,-1, 0,1, 1,-1, 1,0, 1,1 }; short *pix, prev[3], *curve[8], (*shrink)[3]; float cfilt=0, ddft[3][3][2], ppm[3][3][3]; float cam_xyz[3][3], correct[3][3], last[3][3], trans[3][3]; float chroma_dq[3], color_dq[3], diag[3][3], div[3]; float (*black)[3], (*sgain)[3], (*sgrow)[3]; float fsum[3], val, frow, num; int row, col, c, i, j, diff, sgx, irow, sum, min, max, limit; int dscr[2][2], dstb[4], (*smrow[7])[3], total[4], ipix[3]; int work[3][3], smlast, smred, smred_p=0, dev[3]; int satlev[3], keep[4], active[4]; unsigned dim[3], *badpix; double dsum=0, trsum[3]; char str[128]; const char* cp; if (verbose) fprintf (stderr,_("Foveon interpolation...\n")); foveon_load_camf(); foveon_fixed (dscr, 4, "DarkShieldColRange"); foveon_fixed (ppm[0][0], 27, "PostPolyMatrix"); foveon_fixed (satlev, 3, "SaturationLevel"); foveon_fixed (keep, 4, "KeepImageArea"); foveon_fixed (active, 4, "ActiveImageArea"); foveon_fixed (chroma_dq, 3, "ChromaDQ"); foveon_fixed (color_dq, 3, foveon_camf_param ("IncludeBlocks", "ColorDQ") ? "ColorDQ" : "ColorDQCamRGB"); if (foveon_camf_param ("IncludeBlocks", "ColumnFilter")) foveon_fixed (&cfilt, 1, "ColumnFilter"); memset (ddft, 0, sizeof ddft); if (!foveon_camf_param ("IncludeBlocks", "DarkDrift") || !foveon_fixed (ddft[1][0], 12, "DarkDrift")) for (i=0; i < 2; i++) { foveon_fixed (dstb, 4, i ? "DarkShieldBottom":"DarkShieldTop"); for (row = dstb[1]; row <= dstb[3]; row++) for (col = dstb[0]; col <= dstb[2]; col++) FORC3 ddft[i+1][c][1] += (short) image[row*width+col][c]; FORC3 ddft[i+1][c][1] /= (dstb[3]-dstb[1]+1) * (dstb[2]-dstb[0]+1); } if (!(cp = foveon_camf_param ("WhiteBalanceIlluminants", model2))) { fprintf (stderr,_("%s: Invalid white balance \"%s\"\n"), ifname, model2); return; } foveon_fixed (cam_xyz, 9, cp); foveon_fixed (correct, 9, foveon_camf_param ("WhiteBalanceCorrections", model2)); memset (last, 0, sizeof last); for (i=0; i < 3; i++) for (j=0; j < 3; j++) FORC3 last[i][j] += correct[i][c] * cam_xyz[c][j]; #define LAST(x,y) last[(i+x)%3][(c+y)%3] for (i=0; i < 3; i++) FORC3 diag[c][i] = LAST(1,1)*LAST(2,2) - LAST(1,2)*LAST(2,1); #undef LAST FORC3 div[c] = diag[c][0]*0.3127 + diag[c][1]*0.329 + diag[c][2]*0.3583; sprintf (str, "%sRGBNeutral", model2); if (foveon_camf_param ("IncludeBlocks", str)) foveon_fixed (div, 3, str); num = 0; FORC3 if (num < div[c]) num = div[c]; FORC3 div[c] /= num; memset (trans, 0, sizeof trans); for (i=0; i < 3; i++) for (j=0; j < 3; j++) FORC3 trans[i][j] += rgb_cam[i][c] * last[c][j] * div[j]; FORC3 trsum[c] = trans[c][0] + trans[c][1] + trans[c][2]; dsum = (6*trsum[0] + 11*trsum[1] + 3*trsum[2]) / 20; for (i=0; i < 3; i++) FORC3 last[i][c] = trans[i][c] * dsum / trsum[i]; memset (trans, 0, sizeof trans); for (i=0; i < 3; i++) for (j=0; j < 3; j++) FORC3 trans[i][j] += (i==c ? 32 : -1) * last[c][j] / 30; foveon_make_curves (curve, color_dq, div, cfilt); FORC3 chroma_dq[c] /= 3; foveon_make_curves (curve+3, chroma_dq, div, cfilt); FORC3 dsum += chroma_dq[c] / div[c]; curve[6] = foveon_make_curve (dsum, dsum, cfilt); curve[7] = foveon_make_curve (dsum*2, dsum*2, cfilt); sgain = (float (*)[3]) foveon_camf_matrix (dim, "SpatialGain"); if (!sgain) return; sgrow = (float (*)[3]) calloc (dim[1], sizeof *sgrow); sgx = (width + dim[1]-2) / (dim[1]-1); black = (float (*)[3]) calloc (height, sizeof *black); for (row=0; row < height; row++) { for (i=0; i < 6; i++) ddft[0][0][i] = ddft[1][0][i] + row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]); FORC3 black[row][c] = ( foveon_avg (image[row*width]+c, dscr[0], cfilt) + foveon_avg (image[row*width]+c, dscr[1], cfilt) * 3 - ddft[0][c][0] ) / 4 - ddft[0][c][1]; } memcpy (black, black+8, sizeof *black*8); memcpy (black+height-11, black+height-22, 11*sizeof *black); memcpy (last, black, sizeof last); for (row=1; row < height-1; row++) { FORC3 if (last[1][c] > last[0][c]) { if (last[1][c] > last[2][c]) black[row][c] = (last[0][c] > last[2][c]) ? last[0][c]:last[2][c]; } else if (last[1][c] < last[2][c]) black[row][c] = (last[0][c] < last[2][c]) ? last[0][c]:last[2][c]; memmove (last, last+1, 2*sizeof last[0]); memcpy (last[2], black[row+1], sizeof last[2]); } FORC3 black[row][c] = (last[0][c] + last[1][c])/2; FORC3 black[0][c] = (black[1][c] + black[3][c])/2; val = 1 - exp(-1/24.0); memcpy (fsum, black, sizeof fsum); for (row=1; row < height; row++) FORC3 fsum[c] += black[row][c] = (black[row][c] - black[row-1][c])*val + black[row-1][c]; memcpy (last[0], black[height-1], sizeof last[0]); FORC3 fsum[c] /= height; for (row = height; row--; ) FORC3 last[0][c] = black[row][c] = (black[row][c] - fsum[c] - last[0][c])*val + last[0][c]; memset (total, 0, sizeof total); for (row=2; row < height; row+=4) for (col=2; col < width; col+=4) { FORC3 total[c] += (short) image[row*width+col][c]; total[3]++; } for (row=0; row < height; row++) FORC3 black[row][c] += fsum[c]/2 + total[c]/(total[3]*100.0); for (row=0; row < height; row++) { for (i=0; i < 6; i++) ddft[0][0][i] = ddft[1][0][i] + row / (height-1.0) * (ddft[2][0][i] - ddft[1][0][i]); pix = image[row*width]; memcpy (prev, pix, sizeof prev); frow = row / (height-1.0) * (dim[2]-1); if ((irow = frow) == dim[2]-1) irow--; frow -= irow; for (i=0; i < dim[1]; i++) FORC3 sgrow[i][c] = sgain[ irow *dim[1]+i][c] * (1-frow) + sgain[(irow+1)*dim[1]+i][c] * frow; for (col=0; col < width; col++) { FORC3 { diff = pix[c] - prev[c]; prev[c] = pix[c]; ipix[c] = pix[c] + floor ((diff + (diff*diff >> 14)) * cfilt - ddft[0][c][1] - ddft[0][c][0] * ((float) col/width - 0.5) - black[row][c] ); } FORC3 { work[0][c] = ipix[c] * ipix[c] >> 14; work[2][c] = ipix[c] * work[0][c] >> 14; work[1][2-c] = ipix[(c+1) % 3] * ipix[(c+2) % 3] >> 14; } FORC3 { for (val=i=0; i < 3; i++) for ( j=0; j < 3; j++) val += ppm[c][i][j] * work[i][j]; ipix[c] = floor ((ipix[c] + floor(val)) * ( sgrow[col/sgx ][c] * (sgx - col%sgx) + sgrow[col/sgx+1][c] * (col%sgx) ) / sgx / div[c]); if (ipix[c] > 32000) ipix[c] = 32000; pix[c] = ipix[c]; } pix += 4; } } free (black); free (sgrow); free (sgain); if ((badpix = (unsigned int *) foveon_camf_matrix (dim, "BadPixels"))) { for (i=0; i < dim[0]; i++) { col = (badpix[i] >> 8 & 0xfff) - keep[0]; row = (badpix[i] >> 20 ) - keep[1]; if ((unsigned)(row-1) > height-3 || (unsigned)(col-1) > width-3) continue; memset (fsum, 0, sizeof fsum); for (sum=j=0; j < 8; j++) if (badpix[i] & (1 << j)) { FORC3 fsum[c] += (short) image[(row+hood[j*2])*width+col+hood[j*2+1]][c]; sum++; } if (sum) FORC3 image[row*width+col][c] = fsum[c]/sum; } free (badpix); } /* Array for 5x5 Gaussian averaging of red values */ smrow[6] = (int (*)[3]) calloc (width*5, sizeof **smrow); merror (smrow[6], "foveon_interpolate()"); for (i=0; i < 5; i++) smrow[i] = smrow[6] + i*width; /* Sharpen the reds against these Gaussian averages */ for (smlast=-1, row=2; row < height-2; row++) { while (smlast < row+2) { for (i=0; i < 6; i++) smrow[(i+5) % 6] = smrow[i]; pix = image[++smlast*width+2]; for (col=2; col < width-2; col++) { smrow[4][col][0] = (pix[0]*6 + (pix[-4]+pix[4])*4 + pix[-8]+pix[8] + 8) >> 4; pix += 4; } } pix = image[row*width+2]; for (col=2; col < width-2; col++) { smred = ( 6 * smrow[2][col][0] + 4 * (smrow[1][col][0] + smrow[3][col][0]) + smrow[0][col][0] + smrow[4][col][0] + 8 ) >> 4; if (col == 2) smred_p = smred; i = pix[0] + ((pix[0] - ((smred*7 + smred_p) >> 3)) >> 3); if (i > 32000) i = 32000; pix[0] = i; smred_p = smred; pix += 4; } } /* Adjust the brighter pixels for better linearity */ min = 0xffff; FORC3 { i = satlev[c] / div[c]; if (min > i) min = i; } limit = min * 9 >> 4; for (pix=image[0]; pix < image[height*width]; pix+=4) { if (pix[0] <= limit || pix[1] <= limit || pix[2] <= limit) continue; min = max = pix[0]; for (c=1; c < 3; c++) { if (min > pix[c]) min = pix[c]; if (max < pix[c]) max = pix[c]; } if (min >= limit*2) { pix[0] = pix[1] = pix[2] = max; } else { i = 0x4000 - ((min - limit) << 14) / limit; i = 0x4000 - (i*i >> 14); i = i*i >> 14; FORC3 pix[c] += (max - pix[c]) * i >> 14; } } /* Because photons that miss one detector often hit another, the sum R+G+B is much less noisy than the individual colors. So smooth the hues without smoothing the total. */ for (smlast=-1, row=2; row < height-2; row++) { while (smlast < row+2) { for (i=0; i < 6; i++) smrow[(i+5) % 6] = smrow[i]; pix = image[++smlast*width+2]; for (col=2; col < width-2; col++) { FORC3 smrow[4][col][c] = (pix[c-4]+2*pix[c]+pix[c+4]+2) >> 2; pix += 4; } } pix = image[row*width+2]; for (col=2; col < width-2; col++) { FORC3 dev[c] = -foveon_apply_curve (curve[7], pix[c] - ((smrow[1][col][c] + 2*smrow[2][col][c] + smrow[3][col][c]) >> 2)); sum = (dev[0] + dev[1] + dev[2]) >> 3; FORC3 pix[c] += dev[c] - sum; pix += 4; } } for (smlast=-1, row=2; row < height-2; row++) { while (smlast < row+2) { for (i=0; i < 6; i++) smrow[(i+5) % 6] = smrow[i]; pix = image[++smlast*width+2]; for (col=2; col < width-2; col++) { FORC3 smrow[4][col][c] = (pix[c-8]+pix[c-4]+pix[c]+pix[c+4]+pix[c+8]+2) >> 2; pix += 4; } } pix = image[row*width+2]; for (col=2; col < width-2; col++) { for (total[3]=375, sum=60, c=0; c < 3; c++) { for (total[c]=i=0; i < 5; i++) total[c] += smrow[i][col][c]; total[3] += total[c]; sum += pix[c]; } if (sum < 0) sum = 0; j = total[3] > 375 ? (sum << 16) / total[3] : sum * 174; FORC3 pix[c] += foveon_apply_curve (curve[6], ((j*total[c] + 0x8000) >> 16) - pix[c]); pix += 4; } } /* Transform the image to a different colorspace */ for (pix=image[0]; pix < image[height*width]; pix+=4) { FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]); sum = (pix[0]+pix[1]+pix[1]+pix[2]) >> 2; FORC3 pix[c] -= foveon_apply_curve (curve[c], pix[c]-sum); FORC3 { for (dsum=i=0; i < 3; i++) dsum += trans[c][i] * pix[i]; if (dsum < 0) dsum = 0; if (dsum > 24000) dsum = 24000; ipix[c] = dsum + 0.5; } FORC3 pix[c] = ipix[c]; } /* Smooth the image bottom-to-top and save at 1/4 scale */ shrink = (short (*)[3]) calloc ((height/4), (width/4)*sizeof *shrink); merror (shrink, "foveon_interpolate()"); for (row = height/4; row--; ) for (col=0; col < width/4; col++) { ipix[0] = ipix[1] = ipix[2] = 0; for (i=0; i < 4; i++) for (j=0; j < 4; j++) FORC3 ipix[c] += image[(row*4+i)*width+col*4+j][c]; FORC3 if (row+2 > height/4) shrink[row*(width/4)+col][c] = ipix[c] >> 4; else shrink[row*(width/4)+col][c] = (shrink[(row+1)*(width/4)+col][c]*1840 + ipix[c]*141 + 2048) >> 12; } /* From the 1/4-scale image, smooth right-to-left */ for (row=0; row < (height & ~3); row++) { ipix[0] = ipix[1] = ipix[2] = 0; if ((row & 3) == 0) for (col = width & ~3 ; col--; ) FORC3 smrow[0][col][c] = ipix[c] = (shrink[(row/4)*(width/4)+col/4][c]*1485 + ipix[c]*6707 + 4096) >> 13; /* Then smooth left-to-right */ ipix[0] = ipix[1] = ipix[2] = 0; for (col=0; col < (width & ~3); col++) FORC3 smrow[1][col][c] = ipix[c] = (smrow[0][col][c]*1485 + ipix[c]*6707 + 4096) >> 13; /* Smooth top-to-bottom */ if (row == 0) memcpy (smrow[2], smrow[1], sizeof **smrow * width); else for (col=0; col < (width & ~3); col++) FORC3 smrow[2][col][c] = (smrow[2][col][c]*6707 + smrow[1][col][c]*1485 + 4096) >> 13; /* Adjust the chroma toward the smooth values */ for (col=0; col < (width & ~3); col++) { for (i=j=30, c=0; c < 3; c++) { i += smrow[2][col][c]; j += image[row*width+col][c]; } j = (j << 16) / i; for (sum=c=0; c < 3; c++) { ipix[c] = foveon_apply_curve (curve[c+3], ((smrow[2][col][c] * j + 0x8000) >> 16) - image[row*width+col][c]); sum += ipix[c]; } sum >>= 3; FORC3 { i = image[row*width+col][c] + ipix[c] - sum; if (i < 0) i = 0; image[row*width+col][c] = i; } } } free (shrink); free (smrow[6]); for (i=0; i < 8; i++) free (curve[i]); /* Trim off the black border */ active[1] -= keep[1]; active[3] -= 2; i = active[2] - active[0]; for (row=0; row < active[3]-active[1]; row++) memcpy (image[row*i], image[(row+active[1])*width+active[0]], i * sizeof *image); width = i; height = row; } #undef image /* RESTRICTED code ends here */ void CLASS crop_masked_pixels() { int row, col; unsigned r, c, m, mblack[8], zero, val; if (load_raw == &CLASS phase_one_load_raw || load_raw == &CLASS phase_one_load_raw_c) phase_one_correct(); if (fuji_width) { for (row=0; row < raw_height-top_margin*2; row++) { for (col=0; col < fuji_width << !fuji_layout; col++) { if (fuji_layout) { r = fuji_width - 1 - col + (row >> 1); c = col + ((row+1) >> 1); } else { r = fuji_width - 1 + row - (col >> 1); c = row + ((col+1) >> 1); } if (r < height && c < width) BAYER(r,c) = RAW(row+top_margin,col+left_margin); } } } else { for (row=0; row < height; row++) for (col=0; col < width; col++) BAYER2(row,col) = RAW(row+top_margin,col+left_margin); } if (mask[0][3]) goto mask_set; if (load_raw == &CLASS canon_load_raw || load_raw == &CLASS lossless_jpeg_load_raw) { mask[0][1] = mask[1][1] = 2; mask[0][3] = -2; goto sides; } if (load_raw == &CLASS canon_600_load_raw || load_raw == &CLASS sony_load_raw || (load_raw == &CLASS eight_bit_load_raw && strncmp(model,"DC2",3)) || load_raw == &CLASS kodak_262_load_raw || (load_raw == &CLASS packed_load_raw && (load_flags & 32))) { sides: mask[0][0] = mask[1][0] = top_margin; mask[0][2] = mask[1][2] = top_margin+height; mask[0][3] += left_margin; mask[1][1] += left_margin+width; mask[1][3] += raw_width; } if (load_raw == &CLASS nokia_load_raw) { mask[0][2] = top_margin; mask[0][3] = width; } mask_set: memset (mblack, 0, sizeof mblack); for (zero=m=0; m < 8; m++) for (row=MAX(mask[m][0],0); row < MIN(mask[m][2],raw_height); row++) for (col=MAX(mask[m][1],0); col < MIN(mask[m][3],raw_width); col++) { c = FC(row-top_margin,col-left_margin); mblack[c] += val = RAW(row,col); mblack[4+c]++; zero += !val; } if (load_raw == &CLASS canon_600_load_raw && width < raw_width) { black = (mblack[0]+mblack[1]+mblack[2]+mblack[3]) / (mblack[4]+mblack[5]+mblack[6]+mblack[7]) - 4; canon_600_correct(); } else if (zero < mblack[4] && mblack[5] && mblack[6] && mblack[7]) FORC4 cblack[c] = mblack[c] / mblack[4+c]; } void CLASS remove_zeroes() { unsigned row, col, tot, n, r, c; for (row=0; row < height; row++) for (col=0; col < width; col++) if (BAYER(row,col) == 0) { tot = n = 0; for (r = row-2; r <= row+2; r++) for (c = col-2; c <= col+2; c++) if (r < height && c < width && FC(r,c) == FC(row,col) && BAYER(r,c)) tot += (n++,BAYER(r,c)); if (n) BAYER(row,col) = tot/n; } } /* Seach from the current directory up to the root looking for a ".badpixels" file, and fix those pixels now. */ void CLASS bad_pixels (const char *cfname) { FILE *fp=0; char *fname, *cp, line[128]; int len, time, row, col, r, c, rad, tot, n, fixed=0; if (!filters) return; if (cfname) fp = fopen (cfname, "r"); else { for (len=32 ; ; len *= 2) { fname = (char *) malloc (len); if (!fname) return; if (getcwd (fname, len-16)) break; free (fname); if (errno != ERANGE) return; } #if defined(WIN32) || defined(DJGPP) if (fname[1] == ':') memmove (fname, fname+2, len-2); for (cp=fname; *cp; cp++) if (*cp == '\\') *cp = '/'; #endif cp = fname + strlen(fname); if (cp[-1] == '/') cp--; while (*fname == '/') { strcpy (cp, "/.badpixels"); if ((fp = fopen (fname, "r"))) break; if (cp == fname) break; while (*--cp != '/'); } free (fname); } if (!fp) return; while (fgets (line, 128, fp)) { cp = strchr (line, '#'); if (cp) *cp = 0; if (sscanf (line, "%d %d %d", &col, &row, &time) != 3) continue; if ((unsigned) col >= width || (unsigned) row >= height) continue; if (time > timestamp) continue; for (tot=n=0, rad=1; rad < 3 && n==0; rad++) for (r = row-rad; r <= row+rad; r++) for (c = col-rad; c <= col+rad; c++) if ((unsigned) r < height && (unsigned) c < width && (r != row || c != col) && fcol(r,c) == fcol(row,col)) { tot += BAYER2(r,c); n++; } BAYER2(row,col) = tot/n; if (verbose) { if (!fixed++) fprintf (stderr,_("Fixed dead pixels at:")); fprintf (stderr, " %d,%d", col, row); } } if (fixed) fputc ('\n', stderr); fclose (fp); } void CLASS subtract (const char *fname) { FILE *fp; int dim[3]={0,0,0}, comment=0, number=0, error=0, nd=0, c, row, col; ushort *pixel; if (!(fp = fopen (fname, "rb"))) { perror (fname); return; } if (fgetc(fp) != 'P' || fgetc(fp) != '5') error = 1; while (!error && nd < 3 && (c = fgetc(fp)) != EOF) { if (c == '#') comment = 1; if (c == '\n') comment = 0; if (comment) continue; if (isdigit(c)) number = 1; if (number) { if (isdigit(c)) dim[nd] = dim[nd]*10 + c -'0'; else if (isspace(c)) { number = 0; nd++; } else error = 1; } } if (error || nd < 3) { fprintf (stderr,_("%s is not a valid PGM file!\n"), fname); fclose (fp); return; } else if (dim[0] != width || dim[1] != height || dim[2] != 65535) { fprintf (stderr,_("%s has the wrong dimensions!\n"), fname); fclose (fp); return; } pixel = (ushort *) calloc (width, sizeof *pixel); merror (pixel, "subtract()"); for (row=0; row < height; row++) { fread (pixel, 2, width, fp); for (col=0; col < width; col++) BAYER(row,col) = MAX (BAYER(row,col) - ntohs(pixel[col]), 0); } free (pixel); fclose (fp); memset (cblack, 0, sizeof cblack); black = 0; } void CLASS gamma_curve (double pwr, double ts, int mode, int imax) { int i; double g[6], bnd[2]={0,0}, r; g[0] = pwr; g[1] = ts; g[2] = g[3] = g[4] = 0; bnd[g[1] >= 1] = 1; if (g[1] && (g[1]-1)*(g[0]-1) <= 0) { for (i=0; i < 48; i++) { g[2] = (bnd[0] + bnd[1])/2; if (g[0]) bnd[(pow(g[2]/g[1],-g[0]) - 1)/g[0] - 1/g[2] > -1] = g[2]; else bnd[g[2]/exp(1-1/g[2]) < g[1]] = g[2]; } g[3] = g[2] / g[1]; if (g[0]) g[4] = g[2] * (1/g[0] - 1); } if (g[0]) g[5] = 1 / (g[1]*SQR(g[3])/2 - g[4]*(1 - g[3]) + (1 - pow(g[3],1+g[0]))*(1 + g[4])/(1 + g[0])) - 1; else g[5] = 1 / (g[1]*SQR(g[3])/2 + 1 - g[2] - g[3] - g[2]*g[3]*(log(g[3]) - 1)) - 1; if (!mode--) { memcpy (gamm, g, sizeof gamm); return; } for (i=0; i < 0x10000; i++) { curve[i] = 0xffff; if ((r = (double) i / imax) < 1) curve[i] = 0x10000 * ( mode ? (r < g[3] ? r*g[1] : (g[0] ? pow( r,g[0])*(1+g[4])-g[4] : log(r)*g[2]+1)) : (r < g[2] ? r/g[1] : (g[0] ? pow((r+g[4])/(1+g[4]),1/g[0]) : exp((r-1)/g[2])))); } } void CLASS pseudoinverse (double (*in)[3], double (*out)[3], int size) { double work[3][6], num; int i, j, k; for (i=0; i < 3; i++) { for (j=0; j < 6; j++) work[i][j] = j == i+3; for (j=0; j < 3; j++) for (k=0; k < size; k++) work[i][j] += in[k][i] * in[k][j]; } for (i=0; i < 3; i++) { num = work[i][i]; for (j=0; j < 6; j++) work[i][j] /= num; for (k=0; k < 3; k++) { if (k==i) continue; num = work[k][i]; for (j=0; j < 6; j++) work[k][j] -= work[i][j] * num; } } for (i=0; i < size; i++) for (j=0; j < 3; j++) for (out[i][j]=k=0; k < 3; k++) out[i][j] += work[j][k+3] * in[i][k]; } void CLASS cam_xyz_coeff (double cam_xyz[4][3]) { double cam_rgb[4][3], inverse[4][3], num; int i, j, k; for (i=0; i < colors; i++) /* Multiply out XYZ colorspace */ for (j=0; j < 3; j++) for (cam_rgb[i][j] = k=0; k < 3; k++) cam_rgb[i][j] += cam_xyz[i][k] * xyz_rgb[k][j]; for (i=0; i < colors; i++) { /* Normalize cam_rgb so that */ for (num=j=0; j < 3; j++) /* cam_rgb * (1,1,1) is (1,1,1,1) */ num += cam_rgb[i][j]; for (j=0; j < 3; j++) cam_rgb[i][j] /= num; pre_mul[i] = 1 / num; } pseudoinverse (cam_rgb, inverse, colors); for (raw_color = i=0; i < 3; i++) for (j=0; j < colors; j++) rgb_cam[i][j] = inverse[j][i]; } #ifdef COLORCHECK void CLASS colorcheck() { #define NSQ 24 // Coordinates of the GretagMacbeth ColorChecker squares // width, height, 1st_column, 1st_row int cut[NSQ][4]; // you must set these // ColorChecker Chart under 6500-kelvin illumination static const double gmb_xyY[NSQ][3] = { { 0.400, 0.350, 10.1 }, // Dark Skin { 0.377, 0.345, 35.8 }, // Light Skin { 0.247, 0.251, 19.3 }, // Blue Sky { 0.337, 0.422, 13.3 }, // Foliage { 0.265, 0.240, 24.3 }, // Blue Flower { 0.261, 0.343, 43.1 }, // Bluish Green { 0.506, 0.407, 30.1 }, // Orange { 0.211, 0.175, 12.0 }, // Purplish Blue { 0.453, 0.306, 19.8 }, // Moderate Red { 0.285, 0.202, 6.6 }, // Purple { 0.380, 0.489, 44.3 }, // Yellow Green { 0.473, 0.438, 43.1 }, // Orange Yellow { 0.187, 0.129, 6.1 }, // Blue { 0.305, 0.478, 23.4 }, // Green { 0.539, 0.313, 12.0 }, // Red { 0.448, 0.470, 59.1 }, // Yellow { 0.364, 0.233, 19.8 }, // Magenta { 0.196, 0.252, 19.8 }, // Cyan { 0.310, 0.316, 90.0 }, // White { 0.310, 0.316, 59.1 }, // Neutral 8 { 0.310, 0.316, 36.2 }, // Neutral 6.5 { 0.310, 0.316, 19.8 }, // Neutral 5 { 0.310, 0.316, 9.0 }, // Neutral 3.5 { 0.310, 0.316, 3.1 } }; // Black double gmb_cam[NSQ][4], gmb_xyz[NSQ][3]; double inverse[NSQ][3], cam_xyz[4][3], num; int c, i, j, k, sq, row, col, count[4]; memset (gmb_cam, 0, sizeof gmb_cam); for (sq=0; sq < NSQ; sq++) { FORCC count[c] = 0; for (row=cut[sq][3]; row < cut[sq][3]+cut[sq][1]; row++) for (col=cut[sq][2]; col < cut[sq][2]+cut[sq][0]; col++) { c = FC(row,col); if (c >= colors) c -= 2; gmb_cam[sq][c] += BAYER(row,col); count[c]++; } FORCC gmb_cam[sq][c] = gmb_cam[sq][c]/count[c] - black; gmb_xyz[sq][0] = gmb_xyY[sq][2] * gmb_xyY[sq][0] / gmb_xyY[sq][1]; gmb_xyz[sq][1] = gmb_xyY[sq][2]; gmb_xyz[sq][2] = gmb_xyY[sq][2] * (1 - gmb_xyY[sq][0] - gmb_xyY[sq][1]) / gmb_xyY[sq][1]; } pseudoinverse (gmb_xyz, inverse, NSQ); for (i=0; i < colors; i++) for (j=0; j < 3; j++) for (cam_xyz[i][j] = k=0; k < NSQ; k++) cam_xyz[i][j] += gmb_cam[k][i] * inverse[k][j]; cam_xyz_coeff (cam_xyz); if (verbose) { printf (" { \"%s %s\", %d,\n\t{", make, model, black); num = 10000 / (cam_xyz[1][0] + cam_xyz[1][1] + cam_xyz[1][2]); FORCC for (j=0; j < 3; j++) printf ("%c%d", (c | j) ? ',':' ', (int) (cam_xyz[c][j] * num + 0.5)); puts (" } },"); } #undef NSQ } #endif void CLASS hat_transform (float *temp, float *base, int st, int size, int sc) { int i; for (i=0; i < sc; i++) temp[i] = 2*base[st*i] + base[st*(sc-i)] + base[st*(i+sc)]; for (; i+sc < size; i++) temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(i+sc)]; for (; i < size; i++) temp[i] = 2*base[st*i] + base[st*(i-sc)] + base[st*(2*size-2-(i+sc))]; } void CLASS wavelet_denoise() { float *fimg=0, *temp, thold, mul[2], avg, diff; int scale=1, size, lev, hpass, lpass, row, col, nc, c, i, wlast, blk[2]; ushort *window[4]; static const float noise[] = { 0.8002,0.2735,0.1202,0.0585,0.0291,0.0152,0.0080,0.0044 }; if (verbose) fprintf (stderr,_("Wavelet denoising...\n")); while (maximum << scale < 0x10000) scale++; maximum <<= --scale; black <<= scale; FORC4 cblack[c] <<= scale; if ((size = iheight*iwidth) < 0x15550000) fimg = (float *) malloc ((size*3 + iheight + iwidth) * sizeof *fimg); merror (fimg, "wavelet_denoise()"); temp = fimg + size*3; if ((nc = colors) == 3 && filters) nc++; FORC(nc) { /* denoise R,G1,B,G3 individually */ for (i=0; i < size; i++) fimg[i] = 256 * sqrt(image[i][c] << scale); for (hpass=lev=0; lev < 5; lev++) { lpass = size*((lev & 1)+1); for (row=0; row < iheight; row++) { hat_transform (temp, fimg+hpass+row*iwidth, 1, iwidth, 1 << lev); for (col=0; col < iwidth; col++) fimg[lpass + row*iwidth + col] = temp[col] * 0.25; } for (col=0; col < iwidth; col++) { hat_transform (temp, fimg+lpass+col, iwidth, iheight, 1 << lev); for (row=0; row < iheight; row++) fimg[lpass + row*iwidth + col] = temp[row] * 0.25; } thold = threshold * noise[lev]; for (i=0; i < size; i++) { fimg[hpass+i] -= fimg[lpass+i]; if (fimg[hpass+i] < -thold) fimg[hpass+i] += thold; else if (fimg[hpass+i] > thold) fimg[hpass+i] -= thold; else fimg[hpass+i] = 0; if (hpass) fimg[i] += fimg[hpass+i]; } hpass = lpass; } for (i=0; i < size; i++) image[i][c] = CLIP(SQR(fimg[i]+fimg[lpass+i])/0x10000); } if (filters && colors == 3) { /* pull G1 and G3 closer together */ for (row=0; row < 2; row++) { mul[row] = 0.125 * pre_mul[FC(row+1,0) | 1] / pre_mul[FC(row,0) | 1]; blk[row] = cblack[FC(row,0) | 1]; } for (i=0; i < 4; i++) window[i] = (ushort *) fimg + width*i; for (wlast=-1, row=1; row < height-1; row++) { while (wlast < row+1) { for (wlast++, i=0; i < 4; i++) window[(i+3) & 3] = window[i]; for (col = FC(wlast,1) & 1; col < width; col+=2) window[2][col] = BAYER(wlast,col); } thold = threshold/512; for (col = (FC(row,0) & 1)+1; col < width-1; col+=2) { avg = ( window[0][col-1] + window[0][col+1] + window[2][col-1] + window[2][col+1] - blk[~row & 1]*4 ) * mul[row & 1] + (window[1][col] + blk[row & 1]) * 0.5; avg = avg < 0 ? 0 : sqrt(avg); diff = sqrt(BAYER(row,col)) - avg; if (diff < -thold) diff += thold; else if (diff > thold) diff -= thold; else diff = 0; BAYER(row,col) = CLIP(SQR(avg+diff) + 0.5); } } } free (fimg); } void CLASS scale_colors() { unsigned bottom, right, size, row, col, ur, uc, i, x, y, c, sum[8]; int val, dark, sat; double dsum[8], dmin, dmax; float scale_mul[4], fr, fc; ushort *img=0, *pix; if (user_mul[0]) memcpy (pre_mul, user_mul, sizeof pre_mul); if (use_auto_wb || (use_camera_wb && cam_mul[0] == -1)) { memset (dsum, 0, sizeof dsum); bottom = MIN (greybox[1]+greybox[3], height); right = MIN (greybox[0]+greybox[2], width); for (row=greybox[1]; row < bottom; row += 8) for (col=greybox[0]; col < right; col += 8) { memset (sum, 0, sizeof sum); for (y=row; y < row+8 && y < bottom; y++) for (x=col; x < col+8 && x < right; x++) FORC4 { if (filters) { c = fcol(y,x); val = BAYER2(y,x); } else val = image[y*width+x][c]; if (val > maximum-25) goto skip_block; if ((val -= cblack[c]) < 0) val = 0; sum[c] += val; sum[c+4]++; if (filters) break; } FORC(8) dsum[c] += sum[c]; skip_block: ; } FORC4 if (dsum[c]) pre_mul[c] = dsum[c+4] / dsum[c]; } if (use_camera_wb && cam_mul[0] != -1) { memset (sum, 0, sizeof sum); for (row=0; row < 8; row++) for (col=0; col < 8; col++) { c = FC(row,col); if ((val = white[row][col] - cblack[c]) > 0) sum[c] += val; sum[c+4]++; } if (sum[0] && sum[1] && sum[2] && sum[3]) FORC4 pre_mul[c] = (float) sum[c+4] / sum[c]; else if (cam_mul[0] && cam_mul[2]) memcpy (pre_mul, cam_mul, sizeof pre_mul); else fprintf (stderr,_("%s: Cannot use camera white balance.\n"), ifname); } if (pre_mul[1] == 0) pre_mul[1] = 1; if (pre_mul[3] == 0) pre_mul[3] = colors < 4 ? pre_mul[1] : 1; dark = black; sat = maximum; if (threshold) wavelet_denoise(); maximum -= black; for (dmin=DBL_MAX, dmax=c=0; c < 4; c++) { if (dmin > pre_mul[c]) dmin = pre_mul[c]; if (dmax < pre_mul[c]) dmax = pre_mul[c]; } if (!highlight) dmax = dmin; FORC4 scale_mul[c] = (pre_mul[c] /= dmax) * 65535.0 / maximum; if (verbose) { fprintf (stderr, _("Scaling with darkness %d, saturation %d, and\nmultipliers"), dark, sat); FORC4 fprintf (stderr, " %f", pre_mul[c]); fputc ('\n', stderr); } size = iheight*iwidth; for (i=0; i < size*4; i++) { val = image[0][i]; if (!val) continue; val -= cblack[i & 3]; val *= scale_mul[i & 3]; image[0][i] = CLIP(val); } if ((aber[0] != 1 || aber[2] != 1) && colors == 3) { if (verbose) fprintf (stderr,_("Correcting chromatic aberration...\n")); for (c=0; c < 4; c+=2) { if (aber[c] == 1) continue; img = (ushort *) malloc (size * sizeof *img); merror (img, "scale_colors()"); for (i=0; i < size; i++) img[i] = image[i][c]; for (row=0; row < iheight; row++) { ur = fr = (row - iheight*0.5) * aber[c] + iheight*0.5; if (ur > iheight-2) continue; fr -= ur; for (col=0; col < iwidth; col++) { uc = fc = (col - iwidth*0.5) * aber[c] + iwidth*0.5; if (uc > iwidth-2) continue; fc -= uc; pix = img + ur*iwidth + uc; image[row*iwidth+col][c] = (pix[ 0]*(1-fc) + pix[ 1]*fc) * (1-fr) + (pix[iwidth]*(1-fc) + pix[iwidth+1]*fc) * fr; } } free(img); } } } void CLASS pre_interpolate() { ushort (*img)[4]; int row, col, c; if (shrink) { if (half_size) { height = iheight; width = iwidth; if (filters == 9) { for (row=0; row < 3; row++) for (col=1; col < 4; col++) if (!(image[row*width+col][0] | image[row*width+col][2])) goto break2; break2: for ( ; row < height; row+=3) for (col=(col-1)%3+1; col < width-1; col+=3) { img = image + row*width+col; for (c=0; c < 3; c+=2) img[0][c] = (img[-1][c] + img[1][c]) >> 1; } } } else { img = (ushort (*)[4]) calloc (height, width*sizeof *img); merror (img, "pre_interpolate()"); for (row=0; row < height; row++) for (col=0; col < width; col++) { c = fcol(row,col); img[row*width+col][c] = image[(row >> 1)*iwidth+(col >> 1)][c]; } free (image); image = img; shrink = 0; } } if (filters > 1000 && colors == 3) { mix_green = four_color_rgb ^ half_size; if (four_color_rgb | half_size) colors++; else { for (row = FC(1,0) >> 1; row < height; row+=2) for (col = FC(row,1) & 1; col < width; col+=2) image[row*width+col][1] = image[row*width+col][3]; filters &= ~((filters & 0x55555555) << 1); } } if (half_size) filters = 0; } void CLASS border_interpolate (int border) { unsigned row, col, y, x, f, c, sum[8]; for (row=0; row < height; row++) for (col=0; col < width; col++) { if (col==border && row >= border && row < height-border) col = width-border; memset (sum, 0, sizeof sum); for (y=row-1; y != row+2; y++) for (x=col-1; x != col+2; x++) if (y < height && x < width) { f = fcol(y,x); sum[f] += image[y*width+x][f]; sum[f+4]++; } f = fcol(row,col); FORCC if (c != f && sum[c+4]) image[row*width+col][c] = sum[c] / sum[c+4]; } } void CLASS lin_interpolate() { int code[16][16][32], size=16, *ip, sum[4]; int f, c, i, x, y, row, col, shift, color; ushort *pix; if (verbose) fprintf (stderr,_("Bilinear interpolation...\n")); if (filters == 9) size = 6; border_interpolate(1); for (row=0; row < size; row++) for (col=0; col < size; col++) { ip = code[row][col]+1; f = fcol(row,col); memset (sum, 0, sizeof sum); for (y=-1; y <= 1; y++) for (x=-1; x <= 1; x++) { shift = (y==0) + (x==0); color = fcol(row+y,col+x); if (color == f) continue; *ip++ = (width*y + x)*4 + color; *ip++ = shift; *ip++ = color; sum[color] += 1 << shift; } code[row][col][0] = (ip - code[row][col]) / 3; FORCC if (c != f) { *ip++ = c; *ip++ = 256 / sum[c]; } } for (row=1; row < height-1; row++) for (col=1; col < width-1; col++) { pix = image[row*width+col]; ip = code[row % size][col % size]; memset (sum, 0, sizeof sum); for (i=*ip++; i--; ip+=3) sum[ip[2]] += pix[ip[0]] << ip[1]; for (i=colors; --i; ip+=2) pix[ip[0]] = sum[ip[0]] * ip[1] >> 8; } } /* This algorithm is officially called: "Interpolation using a Threshold-based variable number of gradients" described in http://scien.stanford.edu/pages/labsite/1999/psych221/projects/99/tingchen/algodep/vargra.html I've extended the basic idea to work with non-Bayer filter arrays. Gradients are numbered clockwise from NW=0 to W=7. */ void CLASS vng_interpolate() { static const signed char *cp, terms[] = { -2,-2,+0,-1,0,0x01, -2,-2,+0,+0,1,0x01, -2,-1,-1,+0,0,0x01, -2,-1,+0,-1,0,0x02, -2,-1,+0,+0,0,0x03, -2,-1,+0,+1,1,0x01, -2,+0,+0,-1,0,0x06, -2,+0,+0,+0,1,0x02, -2,+0,+0,+1,0,0x03, -2,+1,-1,+0,0,0x04, -2,+1,+0,-1,1,0x04, -2,+1,+0,+0,0,0x06, -2,+1,+0,+1,0,0x02, -2,+2,+0,+0,1,0x04, -2,+2,+0,+1,0,0x04, -1,-2,-1,+0,0,0x80, -1,-2,+0,-1,0,0x01, -1,-2,+1,-1,0,0x01, -1,-2,+1,+0,1,0x01, -1,-1,-1,+1,0,0x88, -1,-1,+1,-2,0,0x40, -1,-1,+1,-1,0,0x22, -1,-1,+1,+0,0,0x33, -1,-1,+1,+1,1,0x11, -1,+0,-1,+2,0,0x08, -1,+0,+0,-1,0,0x44, -1,+0,+0,+1,0,0x11, -1,+0,+1,-2,1,0x40, -1,+0,+1,-1,0,0x66, -1,+0,+1,+0,1,0x22, -1,+0,+1,+1,0,0x33, -1,+0,+1,+2,1,0x10, -1,+1,+1,-1,1,0x44, -1,+1,+1,+0,0,0x66, -1,+1,+1,+1,0,0x22, -1,+1,+1,+2,0,0x10, -1,+2,+0,+1,0,0x04, -1,+2,+1,+0,1,0x04, -1,+2,+1,+1,0,0x04, +0,-2,+0,+0,1,0x80, +0,-1,+0,+1,1,0x88, +0,-1,+1,-2,0,0x40, +0,-1,+1,+0,0,0x11, +0,-1,+2,-2,0,0x40, +0,-1,+2,-1,0,0x20, +0,-1,+2,+0,0,0x30, +0,-1,+2,+1,1,0x10, +0,+0,+0,+2,1,0x08, +0,+0,+2,-2,1,0x40, +0,+0,+2,-1,0,0x60, +0,+0,+2,+0,1,0x20, +0,+0,+2,+1,0,0x30, +0,+0,+2,+2,1,0x10, +0,+1,+1,+0,0,0x44, +0,+1,+1,+2,0,0x10, +0,+1,+2,-1,1,0x40, +0,+1,+2,+0,0,0x60, +0,+1,+2,+1,0,0x20, +0,+1,+2,+2,0,0x10, +1,-2,+1,+0,0,0x80, +1,-1,+1,+1,0,0x88, +1,+0,+1,+2,0,0x08, +1,+0,+2,-1,0,0x40, +1,+0,+2,+1,0,0x10 }, chood[] = { -1,-1, -1,0, -1,+1, 0,+1, +1,+1, +1,0, +1,-1, 0,-1 }; ushort (*brow[5])[4], *pix; int prow=8, pcol=2, *ip, *code[16][16], gval[8], gmin, gmax, sum[4]; int row, col, x, y, x1, x2, y1, y2, t, weight, grads, color, diag; int g, diff, thold, num, c; lin_interpolate(); if (verbose) fprintf (stderr,_("VNG interpolation...\n")); if (filters == 1) prow = pcol = 16; if (filters == 9) prow = pcol = 6; ip = (int *) calloc (prow*pcol, 1280); merror (ip, "vng_interpolate()"); for (row=0; row < prow; row++) /* Precalculate for VNG */ for (col=0; col < pcol; col++) { code[row][col] = ip; for (cp=terms, t=0; t < 64; t++) { y1 = *cp++; x1 = *cp++; y2 = *cp++; x2 = *cp++; weight = *cp++; grads = *cp++; color = fcol(row+y1,col+x1); if (fcol(row+y2,col+x2) != color) continue; diag = (fcol(row,col+1) == color && fcol(row+1,col) == color) ? 2:1; if (abs(y1-y2) == diag && abs(x1-x2) == diag) continue; *ip++ = (y1*width + x1)*4 + color; *ip++ = (y2*width + x2)*4 + color; *ip++ = weight; for (g=0; g < 8; g++) if (grads & 1<<g) *ip++ = g; *ip++ = -1; } *ip++ = INT_MAX; for (cp=chood, g=0; g < 8; g++) { y = *cp++; x = *cp++; *ip++ = (y*width + x) * 4; color = fcol(row,col); if (fcol(row+y,col+x) != color && fcol(row+y*2,col+x*2) == color) *ip++ = (y*width + x) * 8 + color; else *ip++ = 0; } } brow[4] = (ushort (*)[4]) calloc (width*3, sizeof **brow); merror (brow[4], "vng_interpolate()"); for (row=0; row < 3; row++) brow[row] = brow[4] + row*width; for (row=2; row < height-2; row++) { /* Do VNG interpolation */ for (col=2; col < width-2; col++) { pix = image[row*width+col]; ip = code[row % prow][col % pcol]; memset (gval, 0, sizeof gval); while ((g = ip[0]) != INT_MAX) { /* Calculate gradients */ diff = ABS(pix[g] - pix[ip[1]]) << ip[2]; gval[ip[3]] += diff; ip += 5; if ((g = ip[-1]) == -1) continue; gval[g] += diff; while ((g = *ip++) != -1) gval[g] += diff; } ip++; gmin = gmax = gval[0]; /* Choose a threshold */ for (g=1; g < 8; g++) { if (gmin > gval[g]) gmin = gval[g]; if (gmax < gval[g]) gmax = gval[g]; } if (gmax == 0) { memcpy (brow[2][col], pix, sizeof *image); continue; } thold = gmin + (gmax >> 1); memset (sum, 0, sizeof sum); color = fcol(row,col); for (num=g=0; g < 8; g++,ip+=2) { /* Average the neighbors */ if (gval[g] <= thold) { FORCC if (c == color && ip[1]) sum[c] += (pix[c] + pix[ip[1]]) >> 1; else sum[c] += pix[ip[0] + c]; num++; } } FORCC { /* Save to buffer */ t = pix[color]; if (c != color) t += (sum[c] - sum[color]) / num; brow[2][col][c] = CLIP(t); } } if (row > 3) /* Write buffer to image */ memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); for (g=0; g < 4; g++) brow[(g-1) & 3] = brow[g]; } memcpy (image[(row-2)*width+2], brow[0]+2, (width-4)*sizeof *image); memcpy (image[(row-1)*width+2], brow[1]+2, (width-4)*sizeof *image); free (brow[4]); free (code[0][0]); } /* Patterned Pixel Grouping Interpolation by Alain Desbiolles */ void CLASS ppg_interpolate() { int dir[5] = { 1, width, -1, -width, 1 }; int row, col, diff[2], guess[2], c, d, i; ushort (*pix)[4]; border_interpolate(3); if (verbose) fprintf (stderr,_("PPG interpolation...\n")); /* Fill in the green layer with gradients and pattern recognition: */ for (row=3; row < height-3; row++) for (col=3+(FC(row,3) & 1), c=FC(row,col); col < width-3; col+=2) { pix = image + row*width+col; for (i=0; (d=dir[i]) > 0; i++) { guess[i] = (pix[-d][1] + pix[0][c] + pix[d][1]) * 2 - pix[-2*d][c] - pix[2*d][c]; diff[i] = ( ABS(pix[-2*d][c] - pix[ 0][c]) + ABS(pix[ 2*d][c] - pix[ 0][c]) + ABS(pix[ -d][1] - pix[ d][1]) ) * 3 + ( ABS(pix[ 3*d][1] - pix[ d][1]) + ABS(pix[-3*d][1] - pix[-d][1]) ) * 2; } d = dir[i = diff[0] > diff[1]]; pix[0][1] = ULIM(guess[i] >> 2, pix[d][1], pix[-d][1]); } /* Calculate red and blue for each green pixel: */ for (row=1; row < height-1; row++) for (col=1+(FC(row,2) & 1), c=FC(row,col+1); col < width-1; col+=2) { pix = image + row*width+col; for (i=0; (d=dir[i]) > 0; c=2-c, i++) pix[0][c] = CLIP((pix[-d][c] + pix[d][c] + 2*pix[0][1] - pix[-d][1] - pix[d][1]) >> 1); } /* Calculate blue for red pixels and vice versa: */ for (row=1; row < height-1; row++) for (col=1+(FC(row,1) & 1), c=2-FC(row,col); col < width-1; col+=2) { pix = image + row*width+col; for (i=0; (d=dir[i]+dir[i+1]) > 0; i++) { diff[i] = ABS(pix[-d][c] - pix[d][c]) + ABS(pix[-d][1] - pix[0][1]) + ABS(pix[ d][1] - pix[0][1]); guess[i] = pix[-d][c] + pix[d][c] + 2*pix[0][1] - pix[-d][1] - pix[d][1]; } if (diff[0] != diff[1]) pix[0][c] = CLIP(guess[diff[0] > diff[1]] >> 1); else pix[0][c] = CLIP((guess[0]+guess[1]) >> 2); } } void CLASS cielab (ushort rgb[3], short lab[3]) { int c, i, j, k; float r, xyz[3]; static float cbrt[0x10000], xyz_cam[3][4]; if (!rgb) { for (i=0; i < 0x10000; i++) { r = i / 65535.0; cbrt[i] = r > 0.008856 ? pow(r,1/3.0) : 7.787*r + 16/116.0; } for (i=0; i < 3; i++) for (j=0; j < colors; j++) for (xyz_cam[i][j] = k=0; k < 3; k++) xyz_cam[i][j] += xyz_rgb[i][k] * rgb_cam[k][j] / d65_white[i]; return; } xyz[0] = xyz[1] = xyz[2] = 0.5; FORCC { xyz[0] += xyz_cam[0][c] * rgb[c]; xyz[1] += xyz_cam[1][c] * rgb[c]; xyz[2] += xyz_cam[2][c] * rgb[c]; } xyz[0] = cbrt[CLIP((int) xyz[0])]; xyz[1] = cbrt[CLIP((int) xyz[1])]; xyz[2] = cbrt[CLIP((int) xyz[2])]; lab[0] = 64 * (116 * xyz[1] - 16); lab[1] = 64 * 500 * (xyz[0] - xyz[1]); lab[2] = 64 * 200 * (xyz[1] - xyz[2]); } #define TS 512 /* Tile Size */ #define fcol(row,col) xtrans[(row+top_margin+6)%6][(col+left_margin+6)%6] /* Frank Markesteijn's algorithm for Fuji X-Trans sensors */ void CLASS xtrans_interpolate (int passes) { int c, d, f, g, h, i, v, ng, row, col, top, left, mrow, mcol; int val, ndir, pass, hm[8], avg[4], color[3][8]; static const short orth[12] = { 1,0,0,1,-1,0,0,-1,1,0,0,1 }, patt[2][16] = { { 0,1,0,-1,2,0,-1,0,1,1,1,-1,0,0,0,0 }, { 0,1,0,-2,1,0,-2,0,1,1,-2,-2,1,-1,-1,1 } }, dir[4] = { 1,TS,TS+1,TS-1 }; short allhex[3][3][2][8], *hex; ushort min, max, sgrow, sgcol; ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; short (*lab) [TS][3], (*lix)[3]; float (*drv)[TS][TS], diff[6], tr; char (*homo)[TS][TS], *buffer; if (verbose) fprintf (stderr,_("%d-pass X-Trans interpolation...\n"), passes); cielab (0,0); border_interpolate(6); ndir = 4 << (passes > 1); buffer = (char *) malloc (TS*TS*(ndir*11+6)); merror (buffer, "xtrans_interpolate()"); rgb = (ushort(*)[TS][TS][3]) buffer; lab = (short (*) [TS][3])(buffer + TS*TS*(ndir*6)); drv = (float (*)[TS][TS]) (buffer + TS*TS*(ndir*6+6)); homo = (char (*)[TS][TS]) (buffer + TS*TS*(ndir*10+6)); /* Map a green hexagon around each non-green pixel and vice versa: */ for (row=0; row < 3; row++) for (col=0; col < 3; col++) for (ng=d=0; d < 10; d+=2) { g = fcol(row,col) == 1; if (fcol(row+orth[d],col+orth[d+2]) == 1) ng=0; else ng++; if (ng == 4) { sgrow = row; sgcol = col; } if (ng == g+1) FORC(8) { v = orth[d ]*patt[g][c*2] + orth[d+1]*patt[g][c*2+1]; h = orth[d+2]*patt[g][c*2] + orth[d+3]*patt[g][c*2+1]; allhex[row][col][0][c^(g*2 & d)] = h + v*width; allhex[row][col][1][c^(g*2 & d)] = h + v*TS; } } /* Set green1 and green3 to the minimum and maximum allowed values: */ for (row=2; row < height-2; row++) for (min=~(max=0), col=2; col < width-2; col++) { if (fcol(row,col) == 1 && (min=~(max=0))) continue; pix = image + row*width + col; hex = allhex[row % 3][col % 3][0]; if (!max) FORC(6) { val = pix[hex[c]][1]; if (min > val) min = val; if (max < val) max = val; } pix[0][1] = min; pix[0][3] = max; switch ((row-sgrow) % 3) { case 1: if (row < height-3) { row++; col--; } break; case 2: if ((min=~(max=0)) && (col+=2) < width-3 && row > 2) row--; } } for (top=3; top < height-19; top += TS-16) for (left=3; left < width-19; left += TS-16) { mrow = MIN (top+TS, height-3); mcol = MIN (left+TS, width-3); for (row=top; row < mrow; row++) for (col=left; col < mcol; col++) memcpy (rgb[0][row-top][col-left], image[row*width+col], 6); FORC3 memcpy (rgb[c+1], rgb[0], sizeof *rgb); /* Interpolate green horizontally, vertically, and along both diagonals: */ for (row=top; row < mrow; row++) for (col=left; col < mcol; col++) { if ((f = fcol(row,col)) == 1) continue; pix = image + row*width + col; hex = allhex[row % 3][col % 3][0]; color[1][0] = 174 * (pix[ hex[1]][1] + pix[ hex[0]][1]) - 46 * (pix[2*hex[1]][1] + pix[2*hex[0]][1]); color[1][1] = 223 * pix[ hex[3]][1] + pix[ hex[2]][1] * 33 + 92 * (pix[ 0 ][f] - pix[ -hex[2]][f]); FORC(2) color[1][2+c] = 164 * pix[hex[4+c]][1] + 92 * pix[-2*hex[4+c]][1] + 33 * (2*pix[0][f] - pix[3*hex[4+c]][f] - pix[-3*hex[4+c]][f]); FORC4 rgb[c^!((row-sgrow) % 3)][row-top][col-left][1] = LIM(color[1][c] >> 8,pix[0][1],pix[0][3]); } for (pass=0; pass < passes; pass++) { if (pass == 1) memcpy (rgb+=4, buffer, 4*sizeof *rgb); /* Recalculate green from interpolated values of closer pixels: */ if (pass) { for (row=top+2; row < mrow-2; row++) for (col=left+2; col < mcol-2; col++) { if ((f = fcol(row,col)) == 1) continue; pix = image + row*width + col; hex = allhex[row % 3][col % 3][1]; for (d=3; d < 6; d++) { rix = &rgb[(d-2)^!((row-sgrow) % 3)][row-top][col-left]; val = rix[-2*hex[d]][1] + 2*rix[hex[d]][1] - rix[-2*hex[d]][f] - 2*rix[hex[d]][f] + 3*rix[0][f]; rix[0][1] = LIM(val/3,pix[0][1],pix[0][3]); } } } /* Interpolate red and blue values for solitary green pixels: */ for (row=(top-sgrow+4)/3*3+sgrow; row < mrow-2; row+=3) for (col=(left-sgcol+4)/3*3+sgcol; col < mcol-2; col+=3) { rix = &rgb[0][row-top][col-left]; h = fcol(row,col+1); memset (diff, 0, sizeof diff); for (i=1, d=0; d < 6; d++, i^=TS^1, h^=2) { for (c=0; c < 2; c++, h^=2) { g = 2*rix[0][1] - rix[i<<c][1] - rix[-i<<c][1]; color[h][d] = g + rix[i<<c][h] + rix[-i<<c][h]; if (d > 1) diff[d] += SQR (rix[i<<c][1] - rix[-i<<c][1] - rix[i<<c][h] + rix[-i<<c][h]) + SQR(g); } if (d > 1 && (d & 1)) if (diff[d-1] < diff[d]) FORC(2) color[c*2][d] = color[c*2][d-1]; if (d < 2 || (d & 1)) { FORC(2) rix[0][c*2] = CLIP(color[c*2][d]/2); rix += TS*TS; } } } /* Interpolate red for blue pixels and vice versa: */ for (row=top+1; row < mrow-1; row++) for (col=left+1; col < mcol-1; col++) { if ((f = 2-fcol(row,col)) == 1) continue; rix = &rgb[0][row-top][col-left]; i = (row-sgrow) % 3 ? TS:1; for (d=0; d < 4; d++, rix += TS*TS) rix[0][f] = CLIP((rix[i][f] + rix[-i][f] + 2*rix[0][1] - rix[i][1] - rix[-i][1])/2); } /* Fill in red and blue for 2x2 blocks of green: */ for (row=top+2; row < mrow-2; row++) if ((row-sgrow) % 3) for (col=left+2; col < mcol-2; col++) if ((col-sgcol) % 3) { rix = &rgb[0][row-top][col-left]; hex = allhex[row % 3][col % 3][1]; for (d=0; d < ndir; d+=2, rix += TS*TS) if (hex[d] + hex[d+1]) { g = 3*rix[0][1] - 2*rix[hex[d]][1] - rix[hex[d+1]][1]; for (c=0; c < 4; c+=2) rix[0][c] = CLIP((g + 2*rix[hex[d]][c] + rix[hex[d+1]][c])/3); } else { g = 2*rix[0][1] - rix[hex[d]][1] - rix[hex[d+1]][1]; for (c=0; c < 4; c+=2) rix[0][c] = CLIP((g + rix[hex[d]][c] + rix[hex[d+1]][c])/2); } } } rgb = (ushort(*)[TS][TS][3]) buffer; mrow -= top; mcol -= left; /* Convert to CIELab and differentiate in all directions: */ for (d=0; d < ndir; d++) { for (row=2; row < mrow-2; row++) for (col=2; col < mcol-2; col++) cielab (rgb[d][row][col], lab[row][col]); for (f=dir[d & 3],row=3; row < mrow-3; row++) for (col=3; col < mcol-3; col++) { lix = &lab[row][col]; g = 2*lix[0][0] - lix[f][0] - lix[-f][0]; drv[d][row][col] = SQR(g) + SQR((2*lix[0][1] - lix[f][1] - lix[-f][1] + g*500/232)) + SQR((2*lix[0][2] - lix[f][2] - lix[-f][2] - g*500/580)); } } /* Build homogeneity maps from the derivatives: */ memset(homo, 0, ndir*TS*TS); for (row=4; row < mrow-4; row++) for (col=4; col < mcol-4; col++) { for (tr=FLT_MAX, d=0; d < ndir; d++) if (tr > drv[d][row][col]) tr = drv[d][row][col]; tr *= 8; for (d=0; d < ndir; d++) for (v=-1; v <= 1; v++) for (h=-1; h <= 1; h++) if (drv[d][row+v][col+h] <= tr) homo[d][row][col]++; } /* Average the most homogenous pixels for the final result: */ if (height-top < TS+4) mrow = height-top+2; if (width-left < TS+4) mcol = width-left+2; for (row = MIN(top,8); row < mrow-8; row++) for (col = MIN(left,8); col < mcol-8; col++) { for (d=0; d < ndir; d++) for (hm[d]=0, v=-2; v <= 2; v++) for (h=-2; h <= 2; h++) hm[d] += homo[d][row+v][col+h]; for (d=0; d < ndir-4; d++) if (hm[d] < hm[d+4]) hm[d ] = 0; else if (hm[d] > hm[d+4]) hm[d+4] = 0; for (max=hm[0],d=1; d < ndir; d++) if (max < hm[d]) max = hm[d]; max -= max >> 3; memset (avg, 0, sizeof avg); for (d=0; d < ndir; d++) if (hm[d] >= max) { FORC3 avg[c] += rgb[d][row][col][c]; avg[3]++; } FORC3 image[(row+top)*width+col+left][c] = avg[c]/avg[3]; } } free(buffer); } #undef fcol /* Adaptive Homogeneity-Directed interpolation is based on the work of Keigo Hirakawa, Thomas Parks, and Paul Lee. */ void CLASS ahd_interpolate() { int i, j, top, left, row, col, tr, tc, c, d, val, hm[2]; static const int dir[4] = { -1, 1, -TS, TS }; unsigned ldiff[2][4], abdiff[2][4], leps, abeps; ushort (*rgb)[TS][TS][3], (*rix)[3], (*pix)[4]; short (*lab)[TS][TS][3], (*lix)[3]; char (*homo)[TS][TS], *buffer; if (verbose) fprintf (stderr,_("AHD interpolation...\n")); cielab (0,0); border_interpolate(5); buffer = (char *) malloc (26*TS*TS); merror (buffer, "ahd_interpolate()"); rgb = (ushort(*)[TS][TS][3]) buffer; lab = (short (*)[TS][TS][3])(buffer + 12*TS*TS); homo = (char (*)[TS][TS]) (buffer + 24*TS*TS); for (top=2; top < height-5; top += TS-6) for (left=2; left < width-5; left += TS-6) { /* Interpolate green horizontally and vertically: */ for (row=top; row < top+TS && row < height-2; row++) { col = left + (FC(row,left) & 1); for (c = FC(row,col); col < left+TS && col < width-2; col+=2) { pix = image + row*width+col; val = ((pix[-1][1] + pix[0][c] + pix[1][1]) * 2 - pix[-2][c] - pix[2][c]) >> 2; rgb[0][row-top][col-left][1] = ULIM(val,pix[-1][1],pix[1][1]); val = ((pix[-width][1] + pix[0][c] + pix[width][1]) * 2 - pix[-2*width][c] - pix[2*width][c]) >> 2; rgb[1][row-top][col-left][1] = ULIM(val,pix[-width][1],pix[width][1]); } } /* Interpolate red and blue, and convert to CIELab: */ for (d=0; d < 2; d++) for (row=top+1; row < top+TS-1 && row < height-3; row++) for (col=left+1; col < left+TS-1 && col < width-3; col++) { pix = image + row*width+col; rix = &rgb[d][row-top][col-left]; lix = &lab[d][row-top][col-left]; if ((c = 2 - FC(row,col)) == 1) { c = FC(row+1,col); val = pix[0][1] + (( pix[-1][2-c] + pix[1][2-c] - rix[-1][1] - rix[1][1] ) >> 1); rix[0][2-c] = CLIP(val); val = pix[0][1] + (( pix[-width][c] + pix[width][c] - rix[-TS][1] - rix[TS][1] ) >> 1); } else val = rix[0][1] + (( pix[-width-1][c] + pix[-width+1][c] + pix[+width-1][c] + pix[+width+1][c] - rix[-TS-1][1] - rix[-TS+1][1] - rix[+TS-1][1] - rix[+TS+1][1] + 1) >> 2); rix[0][c] = CLIP(val); c = FC(row,col); rix[0][c] = pix[0][c]; cielab (rix[0],lix[0]); } /* Build homogeneity maps from the CIELab images: */ memset (homo, 0, 2*TS*TS); for (row=top+2; row < top+TS-2 && row < height-4; row++) { tr = row-top; for (col=left+2; col < left+TS-2 && col < width-4; col++) { tc = col-left; for (d=0; d < 2; d++) { lix = &lab[d][tr][tc]; for (i=0; i < 4; i++) { ldiff[d][i] = ABS(lix[0][0]-lix[dir[i]][0]); abdiff[d][i] = SQR(lix[0][1]-lix[dir[i]][1]) + SQR(lix[0][2]-lix[dir[i]][2]); } } leps = MIN(MAX(ldiff[0][0],ldiff[0][1]), MAX(ldiff[1][2],ldiff[1][3])); abeps = MIN(MAX(abdiff[0][0],abdiff[0][1]), MAX(abdiff[1][2],abdiff[1][3])); for (d=0; d < 2; d++) for (i=0; i < 4; i++) if (ldiff[d][i] <= leps && abdiff[d][i] <= abeps) homo[d][tr][tc]++; } } /* Combine the most homogenous pixels for the final result: */ for (row=top+3; row < top+TS-3 && row < height-5; row++) { tr = row-top; for (col=left+3; col < left+TS-3 && col < width-5; col++) { tc = col-left; for (d=0; d < 2; d++) for (hm[d]=0, i=tr-1; i <= tr+1; i++) for (j=tc-1; j <= tc+1; j++) hm[d] += homo[d][i][j]; if (hm[0] != hm[1]) FORC3 image[row*width+col][c] = rgb[hm[1] > hm[0]][tr][tc][c]; else FORC3 image[row*width+col][c] = (rgb[0][tr][tc][c] + rgb[1][tr][tc][c]) >> 1; } } } free (buffer); } #undef TS void CLASS median_filter() { ushort (*pix)[4]; int pass, c, i, j, k, med[9]; static const uchar opt[] = /* Optimal 9-element median search */ { 1,2, 4,5, 7,8, 0,1, 3,4, 6,7, 1,2, 4,5, 7,8, 0,3, 5,8, 4,7, 3,6, 1,4, 2,5, 4,7, 4,2, 6,4, 4,2 }; for (pass=1; pass <= med_passes; pass++) { if (verbose) fprintf (stderr,_("Median filter pass %d...\n"), pass); for (c=0; c < 3; c+=2) { for (pix = image; pix < image+width*height; pix++) pix[0][3] = pix[0][c]; for (pix = image+width; pix < image+width*(height-1); pix++) { if ((pix-image+1) % width < 2) continue; for (k=0, i = -width; i <= width; i += width) for (j = i-1; j <= i+1; j++) med[k++] = pix[j][3] - pix[j][1]; for (i=0; i < sizeof opt; i+=2) if (med[opt[i]] > med[opt[i+1]]) SWAP (med[opt[i]] , med[opt[i+1]]); pix[0][c] = CLIP(med[4] + pix[0][1]); } } } } void CLASS blend_highlights() { int clip=INT_MAX, row, col, c, i, j; static const float trans[2][4][4] = { { { 1,1,1 }, { 1.7320508,-1.7320508,0 }, { -1,-1,2 } }, { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; static const float itrans[2][4][4] = { { { 1,0.8660254,-0.5 }, { 1,-0.8660254,-0.5 }, { 1,0,1 } }, { { 1,1,1,1 }, { 1,-1,1,-1 }, { 1,1,-1,-1 }, { 1,-1,-1,1 } } }; float cam[2][4], lab[2][4], sum[2], chratio; if ((unsigned) (colors-3) > 1) return; if (verbose) fprintf (stderr,_("Blending highlights...\n")); FORCC if (clip > (i = 65535*pre_mul[c])) clip = i; for (row=0; row < height; row++) for (col=0; col < width; col++) { FORCC if (image[row*width+col][c] > clip) break; if (c == colors) continue; FORCC { cam[0][c] = image[row*width+col][c]; cam[1][c] = MIN(cam[0][c],clip); } for (i=0; i < 2; i++) { FORCC for (lab[i][c]=j=0; j < colors; j++) lab[i][c] += trans[colors-3][c][j] * cam[i][j]; for (sum[i]=0,c=1; c < colors; c++) sum[i] += SQR(lab[i][c]); } chratio = sqrt(sum[1]/sum[0]); for (c=1; c < colors; c++) lab[0][c] *= chratio; FORCC for (cam[0][c]=j=0; j < colors; j++) cam[0][c] += itrans[colors-3][c][j] * lab[0][j]; FORCC image[row*width+col][c] = cam[0][c] / colors; } } #define SCALE (4 >> shrink) void CLASS recover_highlights() { float *map, sum, wgt, grow; int hsat[4], count, spread, change, val, i; unsigned high, wide, mrow, mcol, row, col, kc, c, d, y, x; ushort *pixel; static const signed char dir[8][2] = { {-1,-1}, {-1,0}, {-1,1}, {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1} }; if (verbose) fprintf (stderr,_("Rebuilding highlights...\n")); grow = pow (2, 4-highlight); FORCC hsat[c] = 32000 * pre_mul[c]; for (kc=0, c=1; c < colors; c++) if (pre_mul[kc] < pre_mul[c]) kc = c; high = height / SCALE; wide = width / SCALE; map = (float *) calloc (high, wide*sizeof *map); merror (map, "recover_highlights()"); FORCC if (c != kc) { memset (map, 0, high*wide*sizeof *map); for (mrow=0; mrow < high; mrow++) for (mcol=0; mcol < wide; mcol++) { sum = wgt = count = 0; for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { pixel = image[row*width+col]; if (pixel[c] / hsat[c] == 1 && pixel[kc] > 24000) { sum += pixel[c]; wgt += pixel[kc]; count++; } } if (count == SCALE*SCALE) map[mrow*wide+mcol] = sum / wgt; } for (spread = 32/grow; spread--; ) { for (mrow=0; mrow < high; mrow++) for (mcol=0; mcol < wide; mcol++) { if (map[mrow*wide+mcol]) continue; sum = count = 0; for (d=0; d < 8; d++) { y = mrow + dir[d][0]; x = mcol + dir[d][1]; if (y < high && x < wide && map[y*wide+x] > 0) { sum += (1 + (d & 1)) * map[y*wide+x]; count += 1 + (d & 1); } } if (count > 3) map[mrow*wide+mcol] = - (sum+grow) / (count+grow); } for (change=i=0; i < high*wide; i++) if (map[i] < 0) { map[i] = -map[i]; change = 1; } if (!change) break; } for (i=0; i < high*wide; i++) if (map[i] == 0) map[i] = 1; for (mrow=0; mrow < high; mrow++) for (mcol=0; mcol < wide; mcol++) { for (row = mrow*SCALE; row < (mrow+1)*SCALE; row++) for (col = mcol*SCALE; col < (mcol+1)*SCALE; col++) { pixel = image[row*width+col]; if (pixel[c] / hsat[c] > 1) { val = pixel[kc] * map[mrow*wide+mcol]; if (pixel[c] < val) pixel[c] = CLIP(val); } } } } free (map); } #undef SCALE void CLASS tiff_get (unsigned base, unsigned *tag, unsigned *type, unsigned *len, unsigned *save) { *tag = get2(); *type = get2(); *len = get4(); *save = ftell(ifp) + 4; if (*len * ("11124811248488"[*type < 14 ? *type:0]-'0') > 4) fseek (ifp, get4()+base, SEEK_SET); } void CLASS parse_thumb_note (int base, unsigned toff, unsigned tlen) { unsigned entries, tag, type, len, save; entries = get2(); while (entries--) { tiff_get (base, &tag, &type, &len, &save); if (tag == toff) thumb_offset = get4()+base; if (tag == tlen) thumb_length = get4(); fseek (ifp, save, SEEK_SET); } } int CLASS parse_tiff_ifd (int base); void CLASS parse_makernote (int base, int uptag) { static const uchar xlat[2][256] = { { 0xc1,0xbf,0x6d,0x0d,0x59,0xc5,0x13,0x9d,0x83,0x61,0x6b,0x4f,0xc7,0x7f,0x3d,0x3d, 0x53,0x59,0xe3,0xc7,0xe9,0x2f,0x95,0xa7,0x95,0x1f,0xdf,0x7f,0x2b,0x29,0xc7,0x0d, 0xdf,0x07,0xef,0x71,0x89,0x3d,0x13,0x3d,0x3b,0x13,0xfb,0x0d,0x89,0xc1,0x65,0x1f, 0xb3,0x0d,0x6b,0x29,0xe3,0xfb,0xef,0xa3,0x6b,0x47,0x7f,0x95,0x35,0xa7,0x47,0x4f, 0xc7,0xf1,0x59,0x95,0x35,0x11,0x29,0x61,0xf1,0x3d,0xb3,0x2b,0x0d,0x43,0x89,0xc1, 0x9d,0x9d,0x89,0x65,0xf1,0xe9,0xdf,0xbf,0x3d,0x7f,0x53,0x97,0xe5,0xe9,0x95,0x17, 0x1d,0x3d,0x8b,0xfb,0xc7,0xe3,0x67,0xa7,0x07,0xf1,0x71,0xa7,0x53,0xb5,0x29,0x89, 0xe5,0x2b,0xa7,0x17,0x29,0xe9,0x4f,0xc5,0x65,0x6d,0x6b,0xef,0x0d,0x89,0x49,0x2f, 0xb3,0x43,0x53,0x65,0x1d,0x49,0xa3,0x13,0x89,0x59,0xef,0x6b,0xef,0x65,0x1d,0x0b, 0x59,0x13,0xe3,0x4f,0x9d,0xb3,0x29,0x43,0x2b,0x07,0x1d,0x95,0x59,0x59,0x47,0xfb, 0xe5,0xe9,0x61,0x47,0x2f,0x35,0x7f,0x17,0x7f,0xef,0x7f,0x95,0x95,0x71,0xd3,0xa3, 0x0b,0x71,0xa3,0xad,0x0b,0x3b,0xb5,0xfb,0xa3,0xbf,0x4f,0x83,0x1d,0xad,0xe9,0x2f, 0x71,0x65,0xa3,0xe5,0x07,0x35,0x3d,0x0d,0xb5,0xe9,0xe5,0x47,0x3b,0x9d,0xef,0x35, 0xa3,0xbf,0xb3,0xdf,0x53,0xd3,0x97,0x53,0x49,0x71,0x07,0x35,0x61,0x71,0x2f,0x43, 0x2f,0x11,0xdf,0x17,0x97,0xfb,0x95,0x3b,0x7f,0x6b,0xd3,0x25,0xbf,0xad,0xc7,0xc5, 0xc5,0xb5,0x8b,0xef,0x2f,0xd3,0x07,0x6b,0x25,0x49,0x95,0x25,0x49,0x6d,0x71,0xc7 }, { 0xa7,0xbc,0xc9,0xad,0x91,0xdf,0x85,0xe5,0xd4,0x78,0xd5,0x17,0x46,0x7c,0x29,0x4c, 0x4d,0x03,0xe9,0x25,0x68,0x11,0x86,0xb3,0xbd,0xf7,0x6f,0x61,0x22,0xa2,0x26,0x34, 0x2a,0xbe,0x1e,0x46,0x14,0x68,0x9d,0x44,0x18,0xc2,0x40,0xf4,0x7e,0x5f,0x1b,0xad, 0x0b,0x94,0xb6,0x67,0xb4,0x0b,0xe1,0xea,0x95,0x9c,0x66,0xdc,0xe7,0x5d,0x6c,0x05, 0xda,0xd5,0xdf,0x7a,0xef,0xf6,0xdb,0x1f,0x82,0x4c,0xc0,0x68,0x47,0xa1,0xbd,0xee, 0x39,0x50,0x56,0x4a,0xdd,0xdf,0xa5,0xf8,0xc6,0xda,0xca,0x90,0xca,0x01,0x42,0x9d, 0x8b,0x0c,0x73,0x43,0x75,0x05,0x94,0xde,0x24,0xb3,0x80,0x34,0xe5,0x2c,0xdc,0x9b, 0x3f,0xca,0x33,0x45,0xd0,0xdb,0x5f,0xf5,0x52,0xc3,0x21,0xda,0xe2,0x22,0x72,0x6b, 0x3e,0xd0,0x5b,0xa8,0x87,0x8c,0x06,0x5d,0x0f,0xdd,0x09,0x19,0x93,0xd0,0xb9,0xfc, 0x8b,0x0f,0x84,0x60,0x33,0x1c,0x9b,0x45,0xf1,0xf0,0xa3,0x94,0x3a,0x12,0x77,0x33, 0x4d,0x44,0x78,0x28,0x3c,0x9e,0xfd,0x65,0x57,0x16,0x94,0x6b,0xfb,0x59,0xd0,0xc8, 0x22,0x36,0xdb,0xd2,0x63,0x98,0x43,0xa1,0x04,0x87,0x86,0xf7,0xa6,0x26,0xbb,0xd6, 0x59,0x4d,0xbf,0x6a,0x2e,0xaa,0x2b,0xef,0xe6,0x78,0xb6,0x4e,0xe0,0x2f,0xdc,0x7c, 0xbe,0x57,0x19,0x32,0x7e,0x2a,0xd0,0xb8,0xba,0x29,0x00,0x3c,0x52,0x7d,0xa8,0x49, 0x3b,0x2d,0xeb,0x25,0x49,0xfa,0xa3,0xaa,0x39,0xa7,0xc5,0xa7,0x50,0x11,0x36,0xfb, 0xc6,0x67,0x4a,0xf5,0xa5,0x12,0x65,0x7e,0xb0,0xdf,0xaf,0x4e,0xb3,0x61,0x7f,0x2f } }; unsigned offset=0, entries, tag, type, len, save, c; unsigned ver97=0, serial=0, i, wbi=0, wb[4]={0,0,0,0}; uchar buf97[324], ci, cj, ck; short morder, sorder=order; char buf[10]; /* The MakerNote might have its own TIFF header (possibly with its own byte-order!), or it might just be a table. */ if (!strcmp(make,"Nokia")) return; fread (buf, 1, 10, ifp); if (!strncmp (buf,"KDK" ,3) || /* these aren't TIFF tables */ !strncmp (buf,"VER" ,3) || !strncmp (buf,"IIII",4) || !strncmp (buf,"MMMM",4)) return; if (!strncmp (buf,"KC" ,2) || /* Konica KD-400Z, KD-510Z */ !strncmp (buf,"MLY" ,3)) { /* Minolta DiMAGE G series */ order = 0x4d4d; while ((i=ftell(ifp)) < data_offset && i < 16384) { wb[0] = wb[2]; wb[2] = wb[1]; wb[1] = wb[3]; wb[3] = get2(); if (wb[1] == 256 && wb[3] == 256 && wb[0] > 256 && wb[0] < 640 && wb[2] > 256 && wb[2] < 640) FORC4 cam_mul[c] = wb[c]; } goto quit; } if (!strcmp (buf,"Nikon")) { base = ftell(ifp); order = get2(); if (get2() != 42) goto quit; offset = get4(); fseek (ifp, offset-8, SEEK_CUR); } else if (!strcmp (buf,"OLYMPUS")) { base = ftell(ifp)-10; fseek (ifp, -2, SEEK_CUR); order = get2(); get2(); } else if (!strncmp (buf,"SONY",4) || !strcmp (buf,"Panasonic")) { goto nf; } else if (!strncmp (buf,"FUJIFILM",8)) { base = ftell(ifp)-10; nf: order = 0x4949; fseek (ifp, 2, SEEK_CUR); } else if (!strcmp (buf,"OLYMP") || !strcmp (buf,"LEICA") || !strcmp (buf,"Ricoh") || !strcmp (buf,"EPSON")) fseek (ifp, -2, SEEK_CUR); else if (!strcmp (buf,"AOC") || !strcmp (buf,"QVC")) fseek (ifp, -4, SEEK_CUR); else { fseek (ifp, -10, SEEK_CUR); if (!strncmp(make,"SAMSUNG",7)) base = ftell(ifp); } entries = get2(); if (entries > 1000) return; morder = order; while (entries--) { order = morder; tiff_get (base, &tag, &type, &len, &save); tag |= uptag << 16; if (tag == 2 && strstr(make,"NIKON") && !iso_speed) iso_speed = (get2(),get2()); if (tag == 4 && len > 26 && len < 35) { if ((i=(get4(),get2())) != 0x7fff && !iso_speed) iso_speed = 50 * pow (2, i/32.0 - 4); if ((i=(get2(),get2())) != 0x7fff && !aperture) aperture = pow (2, i/64.0); if ((i=get2()) != 0xffff && !shutter) shutter = pow (2, (short) i/-32.0); wbi = (get2(),get2()); shot_order = (get2(),get2()); } if ((tag == 4 || tag == 0x114) && !strncmp(make,"KONICA",6)) { fseek (ifp, tag == 4 ? 140:160, SEEK_CUR); switch (get2()) { case 72: flip = 0; break; case 76: flip = 6; break; case 82: flip = 5; break; } } if (tag == 7 && type == 2 && len > 20) fgets (model2, 64, ifp); if (tag == 8 && type == 4) shot_order = get4(); if (tag == 9 && !strcmp(make,"Canon")) fread (artist, 64, 1, ifp); if (tag == 0xc && len == 4) FORC3 cam_mul[(c << 1 | c >> 1) & 3] = getreal(type); if (tag == 0xd && type == 7 && get2() == 0xaaaa) { for (c=i=2; (ushort) c != 0xbbbb && i < len; i++) c = c << 8 | fgetc(ifp); while ((i+=4) < len-5) if (get4() == 257 && (i=len) && (c = (get4(),fgetc(ifp))) < 3) flip = "065"[c]-'0'; } if (tag == 0x10 && type == 4) unique_id = get4(); if (tag == 0x11 && is_raw && !strncmp(make,"NIKON",5)) { fseek (ifp, get4()+base, SEEK_SET); parse_tiff_ifd (base); } if (tag == 0x14 && type == 7) { if (len == 2560) { fseek (ifp, 1248, SEEK_CUR); goto get2_256; } fread (buf, 1, 10, ifp); if (!strncmp(buf,"NRW ",4)) { fseek (ifp, strcmp(buf+4,"0100") ? 46:1546, SEEK_CUR); cam_mul[0] = get4() << 2; cam_mul[1] = get4() + get4(); cam_mul[2] = get4() << 2; } } if (tag == 0x15 && type == 2 && is_raw) fread (model, 64, 1, ifp); if (strstr(make,"PENTAX")) { if (tag == 0x1b) tag = 0x1018; if (tag == 0x1c) tag = 0x1017; } if (tag == 0x1d) while ((c = fgetc(ifp)) && c != EOF) serial = serial*10 + (isdigit(c) ? c - '0' : c % 10); if (tag == 0x81 && type == 4) { data_offset = get4(); fseek (ifp, data_offset + 41, SEEK_SET); raw_height = get2() * 2; raw_width = get2(); filters = 0x61616161; } if (tag == 0x29 && type == 1) { c = wbi < 18 ? "012347800000005896"[wbi]-'0' : 0; fseek (ifp, 8 + c*32, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get4(); } if ((tag == 0x81 && type == 7) || (tag == 0x100 && type == 7) || (tag == 0x280 && type == 1)) { thumb_offset = ftell(ifp); thumb_length = len; } if (tag == 0x88 && type == 4 && (thumb_offset = get4())) thumb_offset += base; if (tag == 0x89 && type == 4) thumb_length = get4(); if (tag == 0x8c || tag == 0x96) meta_offset = ftell(ifp); if (tag == 0x97) { for (i=0; i < 4; i++) ver97 = ver97 * 10 + fgetc(ifp)-'0'; switch (ver97) { case 100: fseek (ifp, 68, SEEK_CUR); FORC4 cam_mul[(c >> 1) | ((c & 1) << 1)] = get2(); break; case 102: fseek (ifp, 6, SEEK_CUR); goto get2_rggb; case 103: fseek (ifp, 16, SEEK_CUR); FORC4 cam_mul[c] = get2(); } if (ver97 >= 200) { if (ver97 != 205) fseek (ifp, 280, SEEK_CUR); fread (buf97, 324, 1, ifp); } } if (tag == 0xa1 && type == 7) { order = 0x4949; fseek (ifp, 140, SEEK_CUR); FORC3 cam_mul[c] = get4(); } if (tag == 0xa4 && type == 3) { fseek (ifp, wbi*48, SEEK_CUR); FORC3 cam_mul[c] = get2(); } if (tag == 0xa7 && (unsigned) (ver97-200) < 17) { ci = xlat[0][serial & 0xff]; cj = xlat[1][fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp)]; ck = 0x60; for (i=0; i < 324; i++) buf97[i] ^= (cj += ci * ck++); i = "66666>666;6A;:;55"[ver97-200] - '0'; FORC4 cam_mul[c ^ (c >> 1) ^ (i & 1)] = sget2 (buf97 + (i & -2) + c*2); } if (tag == 0x200 && len == 3) shot_order = (get4(),get4()); if (tag == 0x200 && len == 4) FORC4 cblack[c ^ c >> 1] = get2(); if (tag == 0x201 && len == 4) goto get2_rggb; if (tag == 0x220 && type == 7) meta_offset = ftell(ifp); if (tag == 0x401 && type == 4 && len == 4) FORC4 cblack[c ^ c >> 1] = get4(); if (tag == 0xe01) { /* Nikon Capture Note */ order = 0x4949; fseek (ifp, 22, SEEK_CUR); for (offset=22; offset+22 < len; offset += 22+i) { tag = get4(); fseek (ifp, 14, SEEK_CUR); i = get4()-4; if (tag == 0x76a43207) flip = get2(); else fseek (ifp, i, SEEK_CUR); } } if (tag == 0xe80 && len == 256 && type == 7) { fseek (ifp, 48, SEEK_CUR); cam_mul[0] = get2() * 508 * 1.078 / 0x10000; cam_mul[2] = get2() * 382 * 1.173 / 0x10000; } if (tag == 0xf00 && type == 7) { if (len == 614) fseek (ifp, 176, SEEK_CUR); else if (len == 734 || len == 1502) fseek (ifp, 148, SEEK_CUR); else goto next; goto get2_256; } if ((tag == 0x1011 && len == 9) || tag == 0x20400200) for (i=0; i < 3; i++) FORC3 cmatrix[i][c] = ((short) get2()) / 256.0; if ((tag == 0x1012 || tag == 0x20400600) && len == 4) FORC4 cblack[c ^ c >> 1] = get2(); if (tag == 0x1017 || tag == 0x20400100) cam_mul[0] = get2() / 256.0; if (tag == 0x1018 || tag == 0x20400100) cam_mul[2] = get2() / 256.0; if (tag == 0x2011 && len == 2) { get2_256: order = 0x4d4d; cam_mul[0] = get2() / 256.0; cam_mul[2] = get2() / 256.0; } if ((tag | 0x70) == 0x2070 && type == 4) fseek (ifp, get4()+base, SEEK_SET); if (tag == 0x2020) parse_thumb_note (base, 257, 258); if (tag == 0x2040) parse_makernote (base, 0x2040); if (tag == 0xb028) { fseek (ifp, get4()+base, SEEK_SET); parse_thumb_note (base, 136, 137); } if (tag == 0x4001 && len > 500) { i = len == 582 ? 50 : len == 653 ? 68 : len == 5120 ? 142 : 126; fseek (ifp, i, SEEK_CUR); get2_rggb: FORC4 cam_mul[c ^ (c >> 1)] = get2(); i = len >> 3 == 164 ? 112:22; fseek (ifp, i, SEEK_CUR); FORC4 sraw_mul[c ^ (c >> 1)] = get2(); } if (tag == 0xa021) FORC4 cam_mul[c ^ (c >> 1)] = get4(); if (tag == 0xa028) FORC4 cam_mul[c ^ (c >> 1)] -= get4(); next: fseek (ifp, save, SEEK_SET); } quit: order = sorder; } /* Since the TIFF DateTime string has no timezone information, assume that the camera's clock was set to Universal Time. */ void CLASS get_timestamp (int reversed) { struct tm t; char str[20]; int i; str[19] = 0; if (reversed) for (i=19; i--; ) str[i] = fgetc(ifp); else fread (str, 19, 1, ifp); memset (&t, 0, sizeof t); if (sscanf (str, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6) return; t.tm_year -= 1900; t.tm_mon -= 1; t.tm_isdst = -1; if (mktime(&t) > 0) timestamp = mktime(&t); } void CLASS parse_exif (int base) { unsigned kodak, entries, tag, type, len, save, c; double expo; kodak = !strncmp(make,"EASTMAN",7) && tiff_nifds < 3; entries = get2(); while (entries--) { tiff_get (base, &tag, &type, &len, &save); switch (tag) { case 33434: shutter = getreal(type); break; case 33437: aperture = getreal(type); break; case 34855: iso_speed = get2(); break; case 36867: case 36868: get_timestamp(0); break; case 37377: if ((expo = -getreal(type)) < 128) shutter = pow (2, expo); break; case 37378: aperture = pow (2, getreal(type)/2); break; case 37386: focal_len = getreal(type); break; case 37500: parse_makernote (base, 0); break; case 40962: if (kodak) raw_width = get4(); break; case 40963: if (kodak) raw_height = get4(); break; case 41730: if (get4() == 0x20002) for (exif_cfa=c=0; c < 8; c+=2) exif_cfa |= fgetc(ifp) * 0x01010101 << c; } fseek (ifp, save, SEEK_SET); } } void CLASS parse_gps (int base) { unsigned entries, tag, type, len, save, c; entries = get2(); while (entries--) { tiff_get (base, &tag, &type, &len, &save); switch (tag) { case 1: case 3: case 5: gpsdata[29+tag/2] = getc(ifp); break; case 2: case 4: case 7: FORC(6) gpsdata[tag/3*6+c] = get4(); break; case 6: FORC(2) gpsdata[18+c] = get4(); break; case 18: case 29: fgets ((char *) (gpsdata+14+tag/3), MIN(len,12), ifp); } fseek (ifp, save, SEEK_SET); } } void CLASS romm_coeff (float romm_cam[3][3]) { static const float rgb_romm[3][3] = /* ROMM == Kodak ProPhoto */ { { 2.034193, -0.727420, -0.306766 }, { -0.228811, 1.231729, -0.002922 }, { -0.008565, -0.153273, 1.161839 } }; int i, j, k; for (i=0; i < 3; i++) for (j=0; j < 3; j++) for (cmatrix[i][j] = k=0; k < 3; k++) cmatrix[i][j] += rgb_romm[i][k] * romm_cam[k][j]; } void CLASS parse_mos (int offset) { char data[40]; int skip, from, i, c, neut[4], planes=0, frot=0; static const char *mod[] = { "","DCB2","Volare","Cantare","CMost","Valeo 6","Valeo 11","Valeo 22", "Valeo 11p","Valeo 17","","Aptus 17","Aptus 22","Aptus 75","Aptus 65", "Aptus 54S","Aptus 65S","Aptus 75S","AFi 5","AFi 6","AFi 7", "","","","","","","","","","","","","","","","","","AFi-II 12" }; float romm_cam[3][3]; fseek (ifp, offset, SEEK_SET); while (1) { if (get4() != 0x504b5453) break; get4(); fread (data, 1, 40, ifp); skip = get4(); from = ftell(ifp); if (!strcmp(data,"JPEG_preview_data")) { thumb_offset = from; thumb_length = skip; } if (!strcmp(data,"icc_camera_profile")) { profile_offset = from; profile_length = skip; } if (!strcmp(data,"ShootObj_back_type")) { fscanf (ifp, "%d", &i); if ((unsigned) i < sizeof mod / sizeof (*mod)) strcpy (model, mod[i]); } if (!strcmp(data,"icc_camera_to_tone_matrix")) { for (i=0; i < 9; i++) romm_cam[0][i] = int_to_float(get4()); romm_coeff (romm_cam); } if (!strcmp(data,"CaptProf_color_matrix")) { for (i=0; i < 9; i++) fscanf (ifp, "%f", &romm_cam[0][i]); romm_coeff (romm_cam); } if (!strcmp(data,"CaptProf_number_of_planes")) fscanf (ifp, "%d", &planes); if (!strcmp(data,"CaptProf_raw_data_rotation")) fscanf (ifp, "%d", &flip); if (!strcmp(data,"CaptProf_mosaic_pattern")) FORC4 { fscanf (ifp, "%d", &i); if (i == 1) frot = c ^ (c >> 1); } if (!strcmp(data,"ImgProf_rotation_angle")) { fscanf (ifp, "%d", &i); flip = i - flip; } if (!strcmp(data,"NeutObj_neutrals") && !cam_mul[0]) { FORC4 fscanf (ifp, "%d", neut+c); FORC3 cam_mul[c] = (float) neut[0] / neut[c+1]; } if (!strcmp(data,"Rows_data")) load_flags = get4(); parse_mos (from); fseek (ifp, skip+from, SEEK_SET); } if (planes) filters = (planes == 1) * 0x01010101 * (uchar) "\x94\x61\x16\x49"[(flip/90 + frot) & 3]; } void CLASS linear_table (unsigned len) { int i; if (len > 0x1000) len = 0x1000; read_shorts (curve, len); for (i=len; i < 0x1000; i++) curve[i] = curve[i-1]; maximum = curve[0xfff]; } void CLASS parse_kodak_ifd (int base) { unsigned entries, tag, type, len, save; int i, c, wbi=-2, wbtemp=6500; float mul[3]={1,1,1}, num; static const int wbtag[] = { 64037,64040,64039,64041,-1,-1,64042 }; entries = get2(); if (entries > 1024) return; while (entries--) { tiff_get (base, &tag, &type, &len, &save); if (tag == 1020) wbi = getint(type); if (tag == 1021 && len == 72) { /* WB set in software */ fseek (ifp, 40, SEEK_CUR); FORC3 cam_mul[c] = 2048.0 / get2(); wbi = -2; } if (tag == 2118) wbtemp = getint(type); if (tag == 2130 + wbi) FORC3 mul[c] = getreal(type); if (tag == 2140 + wbi && wbi >= 0) FORC3 { for (num=i=0; i < 4; i++) num += getreal(type) * pow (wbtemp/100.0, i); cam_mul[c] = 2048 / (num * mul[c]); } if (tag == 2317) linear_table (len); if (tag == 6020) iso_speed = getint(type); if (tag == 64013) wbi = fgetc(ifp); if ((unsigned) wbi < 7 && tag == wbtag[wbi]) FORC3 cam_mul[c] = get4(); if (tag == 64019) width = getint(type); if (tag == 64020) height = (getint(type)+1) & -2; fseek (ifp, save, SEEK_SET); } } void CLASS parse_minolta (int base); int CLASS parse_tiff (int base); int CLASS parse_tiff_ifd (int base) { unsigned entries, tag, type, len, plen=16, save; int ifd, use_cm=0, cfa, i, j, c, ima_len=0; int blrr=1, blrc=1, dblack[] = { 0,0,0,0 }; char software[64], *cbuf, *cp; uchar cfa_pat[16], cfa_pc[] = { 0,1,2,3 }, tab[256]; double cc[4][4], cm[4][3], cam_xyz[4][3], num; double ab[]={ 1,1,1,1 }, asn[] = { 0,0,0,0 }, xyz[] = { 1,1,1 }; unsigned sony_curve[] = { 0,0,0,0,0,4095 }; unsigned *buf, sony_offset=0, sony_length=0, sony_key=0; struct jhead jh; FILE *sfp; if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0]) return 1; ifd = tiff_nifds++; for (j=0; j < 4; j++) for (i=0; i < 4; i++) cc[j][i] = i == j; entries = get2(); if (entries > 512) return 1; while (entries--) { tiff_get (base, &tag, &type, &len, &save); switch (tag) { case 5: width = get2(); break; case 6: height = get2(); break; case 7: width += get2(); break; case 9: if ((i = get2())) filters = i; break; case 17: case 18: if (type == 3 && len == 1) cam_mul[(tag-17)*2] = get2() / 256.0; break; case 23: if (type == 3) iso_speed = get2(); break; case 36: case 37: case 38: cam_mul[tag-0x24] = get2(); break; case 39: if (len < 50 || cam_mul[0]) break; fseek (ifp, 12, SEEK_CUR); FORC3 cam_mul[c] = get2(); break; case 46: if (type != 7 || fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) break; thumb_offset = ftell(ifp) - 2; thumb_length = len; break; case 61440: /* Fuji HS10 table */ parse_tiff_ifd (base); break; case 2: case 256: case 61441: /* ImageWidth */ tiff_ifd[ifd].width = getint(type); break; case 3: case 257: case 61442: /* ImageHeight */ tiff_ifd[ifd].height = getint(type); break; case 258: /* BitsPerSample */ case 61443: tiff_ifd[ifd].samples = len & 7; tiff_ifd[ifd].bps = getint(type); break; case 61446: raw_height = 0; if (tiff_ifd[ifd].bps > 12) break; load_raw = &CLASS packed_load_raw; load_flags = get4() ? 24:80; break; case 259: /* Compression */ tiff_ifd[ifd].comp = getint(type); break; case 262: /* PhotometricInterpretation */ tiff_ifd[ifd].phint = get2(); break; case 270: /* ImageDescription */ fread (desc, 512, 1, ifp); break; case 271: /* Make */ fgets (make, 64, ifp); break; case 272: /* Model */ fgets (model, 64, ifp); break; case 280: /* Panasonic RW2 offset */ if (type != 4) break; load_raw = &CLASS panasonic_load_raw; load_flags = 0x2008; case 273: /* StripOffset */ case 513: /* JpegIFOffset */ case 61447: tiff_ifd[ifd].offset = get4()+base; if (!tiff_ifd[ifd].bps && tiff_ifd[ifd].offset > 0) { fseek (ifp, tiff_ifd[ifd].offset, SEEK_SET); if (ljpeg_start (&jh, 1)) { tiff_ifd[ifd].comp = 6; tiff_ifd[ifd].width = jh.wide; tiff_ifd[ifd].height = jh.high; tiff_ifd[ifd].bps = jh.bits; tiff_ifd[ifd].samples = jh.clrs; if (!(jh.sraw || (jh.clrs & 1))) tiff_ifd[ifd].width *= jh.clrs; i = order; parse_tiff (tiff_ifd[ifd].offset + 12); order = i; } } break; case 274: /* Orientation */ tiff_ifd[ifd].flip = "50132467"[get2() & 7]-'0'; break; case 277: /* SamplesPerPixel */ tiff_ifd[ifd].samples = getint(type) & 7; break; case 279: /* StripByteCounts */ case 514: case 61448: tiff_ifd[ifd].bytes = get4(); break; case 61454: FORC3 cam_mul[(4-c) % 3] = getint(type); break; case 305: case 11: /* Software */ fgets (software, 64, ifp); if (!strncmp(software,"Adobe",5) || !strncmp(software,"dcraw",5) || !strncmp(software,"UFRaw",5) || !strncmp(software,"Bibble",6) || !strncmp(software,"Nikon Scan",10) || !strcmp (software,"Digital Photo Professional")) is_raw = 0; break; case 306: /* DateTime */ get_timestamp(0); break; case 315: /* Artist */ fread (artist, 64, 1, ifp); break; case 322: /* TileWidth */ tiff_ifd[ifd].tile_width = getint(type); break; case 323: /* TileLength */ tiff_ifd[ifd].tile_length = getint(type); break; case 324: /* TileOffsets */ tiff_ifd[ifd].offset = len > 1 ? ftell(ifp) : get4(); if (len == 4) { load_raw = &CLASS sinar_4shot_load_raw; is_raw = 5; } break; case 330: /* SubIFDs */ if (!strcmp(model,"DSLR-A100") && tiff_ifd[ifd].width == 3872) { load_raw = &CLASS sony_arw_load_raw; data_offset = get4()+base; ifd++; break; } if(len > 1000) len=1000; /* 1000 SubIFDs is enough */ while (len--) { i = ftell(ifp); fseek (ifp, get4()+base, SEEK_SET); if (parse_tiff_ifd (base)) break; fseek (ifp, i+4, SEEK_SET); } break; case 400: strcpy (make, "Sarnoff"); maximum = 0xfff; break; case 28688: FORC4 sony_curve[c+1] = get2() >> 2 & 0xfff; for (i=0; i < 5; i++) for (j = sony_curve[i]+1; j <= sony_curve[i+1]; j++) curve[j] = curve[j-1] + (1 << i); break; case 29184: sony_offset = get4(); break; case 29185: sony_length = get4(); break; case 29217: sony_key = get4(); break; case 29264: parse_minolta (ftell(ifp)); raw_width = 0; break; case 29443: FORC4 cam_mul[c ^ (c < 2)] = get2(); break; case 29459: FORC4 cam_mul[c] = get2(); i = (cam_mul[1] == 1024 && cam_mul[2] == 1024) << 1; SWAP (cam_mul[i],cam_mul[i+1]) break; case 33405: /* Model2 */ fgets (model2, 64, ifp); break; case 33422: /* CFAPattern */ case 64777: /* Kodak P-series */ if ((plen=len) > 16) plen = 16; fread (cfa_pat, 1, plen, ifp); for (colors=cfa=i=0; i < plen && colors < 4; i++) { colors += !(cfa & (1 << cfa_pat[i])); cfa |= 1 << cfa_pat[i]; } if (cfa == 070) memcpy (cfa_pc,"\003\004\005",3); /* CMY */ if (cfa == 072) memcpy (cfa_pc,"\005\003\004\001",4); /* GMCY */ goto guess_cfa_pc; case 33424: case 65024: fseek (ifp, get4()+base, SEEK_SET); parse_kodak_ifd (base); break; case 33434: /* ExposureTime */ shutter = getreal(type); break; case 33437: /* FNumber */ aperture = getreal(type); break; case 34306: /* Leaf white balance */ FORC4 cam_mul[c ^ 1] = 4096.0 / get2(); break; case 34307: /* Leaf CatchLight color matrix */ fread (software, 1, 7, ifp); if (strncmp(software,"MATRIX",6)) break; colors = 4; for (raw_color = i=0; i < 3; i++) { FORC4 fscanf (ifp, "%f", &rgb_cam[i][c^1]); if (!use_camera_wb) continue; num = 0; FORC4 num += rgb_cam[i][c]; FORC4 rgb_cam[i][c] /= num; } break; case 34310: /* Leaf metadata */ parse_mos (ftell(ifp)); case 34303: strcpy (make, "Leaf"); break; case 34665: /* EXIF tag */ fseek (ifp, get4()+base, SEEK_SET); parse_exif (base); break; case 34853: /* GPSInfo tag */ fseek (ifp, get4()+base, SEEK_SET); parse_gps (base); break; case 34675: /* InterColorProfile */ case 50831: /* AsShotICCProfile */ profile_offset = ftell(ifp); profile_length = len; break; case 37122: /* CompressedBitsPerPixel */ kodak_cbpp = get4(); break; case 37386: /* FocalLength */ focal_len = getreal(type); break; case 37393: /* ImageNumber */ shot_order = getint(type); break; case 37400: /* old Kodak KDC tag */ for (raw_color = i=0; i < 3; i++) { getreal(type); FORC3 rgb_cam[i][c] = getreal(type); } break; case 40976: strip_offset = get4(); load_raw = &CLASS samsung_load_raw; break; case 46275: /* Imacon tags */ strcpy (make, "Imacon"); data_offset = ftell(ifp); ima_len = len; break; case 46279: if (!ima_len) break; fseek (ifp, 38, SEEK_CUR); case 46274: fseek (ifp, 40, SEEK_CUR); raw_width = get4(); raw_height = get4(); left_margin = get4() & 7; width = raw_width - left_margin - (get4() & 7); top_margin = get4() & 7; height = raw_height - top_margin - (get4() & 7); if (raw_width == 7262) { height = 5444; width = 7244; left_margin = 7; } fseek (ifp, 52, SEEK_CUR); FORC3 cam_mul[c] = getreal(11); fseek (ifp, 114, SEEK_CUR); flip = (get2() >> 7) * 90; if (width * height * 6 == ima_len) { if (flip % 180 == 90) SWAP(width,height); raw_width = width; raw_height = height; left_margin = top_margin = filters = flip = 0; } sprintf (model, "Ixpress %d-Mp", height*width/1000000); load_raw = &CLASS imacon_full_load_raw; if (filters) { if (left_margin & 1) filters = 0x61616161; load_raw = &CLASS unpacked_load_raw; } maximum = 0xffff; break; case 50454: /* Sinar tag */ case 50455: if (!(cbuf = (char *) malloc(len))) break; fread (cbuf, 1, len, ifp); for (cp = cbuf-1; cp && cp < cbuf+len; cp = strchr(cp,'\n')) if (!strncmp (++cp,"Neutral ",8)) sscanf (cp+8, "%f %f %f", cam_mul, cam_mul+1, cam_mul+2); free (cbuf); break; case 50458: if (!make[0]) strcpy (make, "Hasselblad"); break; case 50459: /* Hasselblad tag */ i = order; j = ftell(ifp); c = tiff_nifds; order = get2(); fseek (ifp, j+(get2(),get4()), SEEK_SET); parse_tiff_ifd (j); maximum = 0xffff; tiff_nifds = c; order = i; break; case 50706: /* DNGVersion */ FORC4 dng_version = (dng_version << 8) + fgetc(ifp); if (!make[0]) strcpy (make, "DNG"); is_raw = 1; break; case 50710: /* CFAPlaneColor */ if (len > 4) len = 4; colors = len; fread (cfa_pc, 1, colors, ifp); guess_cfa_pc: FORCC tab[cfa_pc[c]] = c; cdesc[c] = 0; for (i=16; i--; ) filters = filters << 2 | tab[cfa_pat[i % plen]]; filters -= !filters; break; case 50711: /* CFALayout */ if (get2() == 2) { fuji_width = 1; filters = 0x49494949; } break; case 291: case 50712: /* LinearizationTable */ linear_table (len); break; case 50713: /* BlackLevelRepeatDim */ blrr = get2(); blrc = get2(); break; case 61450: blrr = blrc = 2; case 50714: /* BlackLevel */ black = getreal(type); if ((unsigned)(filters+1) < 1000) break; dblack[0] = black; dblack[1] = (blrc == 2) ? getreal(type):dblack[0]; dblack[2] = (blrr == 2) ? getreal(type):dblack[0]; dblack[3] = (blrc == 2 && blrr == 2) ? getreal(type):dblack[1]; if (colors == 3) filters |= ((filters >> 2 & 0x22222222) | (filters << 2 & 0x88888888)) & filters << 1; FORC4 cblack[filters >> (c << 1) & 3] = dblack[c]; black = 0; break; case 50715: /* BlackLevelDeltaH */ case 50716: /* BlackLevelDeltaV */ for (num=i=0; i < len && i < 65536; i++) num += getreal(type); black += num/len + 0.5; break; case 50717: /* WhiteLevel */ maximum = getint(type); break; case 50718: /* DefaultScale */ pixel_aspect = getreal(type); pixel_aspect /= getreal(type); break; case 50721: /* ColorMatrix1 */ case 50722: /* ColorMatrix2 */ FORCC for (j=0; j < 3; j++) cm[c][j] = getreal(type); use_cm = 1; break; case 50723: /* CameraCalibration1 */ case 50724: /* CameraCalibration2 */ for (i=0; i < colors; i++) FORCC cc[i][c] = getreal(type); break; case 50727: /* AnalogBalance */ FORCC ab[c] = getreal(type); break; case 50728: /* AsShotNeutral */ FORCC asn[c] = getreal(type); break; case 50729: /* AsShotWhiteXY */ xyz[0] = getreal(type); xyz[1] = getreal(type); xyz[2] = 1 - xyz[0] - xyz[1]; FORC3 xyz[c] /= d65_white[c]; break; case 50740: /* DNGPrivateData */ if (dng_version) break; parse_minolta (j = get4()+base); fseek (ifp, j, SEEK_SET); parse_tiff_ifd (base); break; case 50752: read_shorts (cr2_slice, 3); break; case 50829: /* ActiveArea */ top_margin = getint(type); left_margin = getint(type); height = getint(type) - top_margin; width = getint(type) - left_margin; break; case 50830: /* MaskedAreas */ for (i=0; i < len && i < 32; i++) mask[0][i] = getint(type); black = 0; break; case 51009: /* OpcodeList2 */ meta_offset = ftell(ifp); break; case 64772: /* Kodak P-series */ if (len < 13) break; fseek (ifp, 16, SEEK_CUR); data_offset = get4(); fseek (ifp, 28, SEEK_CUR); data_offset += get4(); load_raw = &CLASS packed_load_raw; break; case 65026: if (type == 2) fgets (model2, 64, ifp); } fseek (ifp, save, SEEK_SET); } if (sony_length && (buf = (unsigned *) malloc(sony_length))) { fseek (ifp, sony_offset, SEEK_SET); fread (buf, sony_length, 1, ifp); sony_decrypt (buf, sony_length/4, 1, sony_key); sfp = ifp; if ((ifp = tmpfile())) { fwrite (buf, sony_length, 1, ifp); fseek (ifp, 0, SEEK_SET); parse_tiff_ifd (-sony_offset); fclose (ifp); } ifp = sfp; free (buf); } for (i=0; i < colors; i++) FORCC cc[i][c] *= ab[i]; if (use_cm) { FORCC for (i=0; i < 3; i++) for (cam_xyz[c][i]=j=0; j < colors; j++) cam_xyz[c][i] += cc[c][j] * cm[j][i] * xyz[i]; cam_xyz_coeff (cam_xyz); } if (asn[0]) { cam_mul[3] = 0; FORCC cam_mul[c] = 1 / asn[c]; } if (!use_cm) FORCC pre_mul[c] /= cc[c][c]; return 0; } int CLASS parse_tiff (int base) { int doff; fseek (ifp, base, SEEK_SET); order = get2(); if (order != 0x4949 && order != 0x4d4d) return 0; get2(); while ((doff = get4())) { fseek (ifp, doff+base, SEEK_SET); if (parse_tiff_ifd (base)) break; } return 1; } void CLASS apply_tiff() { int max_samp=0, raw=-1, thm=-1, i; struct jhead jh; thumb_misc = 16; if (thumb_offset) { fseek (ifp, thumb_offset, SEEK_SET); if (ljpeg_start (&jh, 1)) { if((unsigned)jh.bits<17 && (unsigned)jh.wide < 0x10000 && (unsigned)jh.high < 0x10000) { thumb_misc = jh.bits; thumb_width = jh.wide; thumb_height = jh.high; } } } for (i=0; i < tiff_nifds; i++) { if (max_samp < tiff_ifd[i].samples) max_samp = tiff_ifd[i].samples; if (max_samp > 3) max_samp = 3; if ((tiff_ifd[i].comp != 6 || tiff_ifd[i].samples != 3) && unsigned(tiff_ifd[i].width | tiff_ifd[i].height) < 0x10000 && (unsigned)tiff_ifd[i].bps < 33 && (unsigned)tiff_ifd[i].samples < 13 && tiff_ifd[i].width*tiff_ifd[i].height > raw_width*raw_height) { raw_width = tiff_ifd[i].width; raw_height = tiff_ifd[i].height; tiff_bps = tiff_ifd[i].bps; tiff_compress = tiff_ifd[i].comp; data_offset = tiff_ifd[i].offset; tiff_flip = tiff_ifd[i].flip; tiff_samples = tiff_ifd[i].samples; tile_width = tiff_ifd[i].tile_width; tile_length = tiff_ifd[i].tile_length; raw = i; } } if (!tile_width ) tile_width = INT_MAX; if (!tile_length) tile_length = INT_MAX; for (i=tiff_nifds; i--; ) if (tiff_ifd[i].flip) tiff_flip = tiff_ifd[i].flip; if (raw >= 0 && !load_raw) switch (tiff_compress) { case 32767: if (tiff_ifd[raw].bytes == raw_width*raw_height) { tiff_bps = 12; load_raw = &CLASS sony_arw2_load_raw; break; } if (tiff_ifd[raw].bytes*8 != raw_width*raw_height*tiff_bps) { raw_height += 8; load_raw = &CLASS sony_arw_load_raw; break; } load_flags = 79; case 32769: load_flags++; case 32770: case 32773: goto slr; case 0: case 1: if (!strncmp(make,"OLYMPUS",7) && tiff_ifd[raw].bytes*2 == raw_width*raw_height*3) load_flags = 24; if (tiff_ifd[raw].bytes*5 == raw_width*raw_height*8) { load_flags = 81; tiff_bps = 12; } slr: switch (tiff_bps) { case 8: load_raw = &CLASS eight_bit_load_raw; break; case 12: if (tiff_ifd[raw].phint == 2) load_flags = 6; load_raw = &CLASS packed_load_raw; break; case 14: load_flags = 0; case 16: load_raw = &CLASS unpacked_load_raw; if (!strncmp(make,"OLYMPUS",7) && tiff_ifd[raw].bytes*7 > raw_width*raw_height) load_raw = &CLASS olympus_load_raw; } break; case 6: case 7: case 99: load_raw = &CLASS lossless_jpeg_load_raw; break; case 262: load_raw = &CLASS kodak_262_load_raw; break; case 34713: if ((raw_width+9)/10*16*raw_height == tiff_ifd[raw].bytes) { load_raw = &CLASS packed_load_raw; load_flags = 1; } else if (raw_width*raw_height*2 == tiff_ifd[raw].bytes) { load_raw = &CLASS unpacked_load_raw; load_flags = 4; order = 0x4d4d; } else load_raw = &CLASS nikon_load_raw; break; case 65535: load_raw = &CLASS pentax_load_raw; break; case 65000: switch (tiff_ifd[raw].phint) { case 2: load_raw = &CLASS kodak_rgb_load_raw; filters = 0; break; case 6: load_raw = &CLASS kodak_ycbcr_load_raw; filters = 0; break; case 32803: load_raw = &CLASS kodak_65000_load_raw; } case 32867: case 34892: break; default: is_raw = 0; } if (!dng_version) if ( (tiff_samples == 3 && tiff_ifd[raw].bytes && tiff_bps != 14 && tiff_compress != 32769 && tiff_compress != 32770) || (tiff_bps == 8 && !strcasestr(make,"Kodak") && !strstr(model2,"DEBUG RAW"))) is_raw = 0; for (i=0; i < tiff_nifds; i++) if (i != raw && tiff_ifd[i].samples == max_samp && tiff_ifd[i].bps>0 && tiff_ifd[i].bps < 33 && unsigned(tiff_ifd[i].width | tiff_ifd[i].height) < 0x10000 && tiff_ifd[i].width * tiff_ifd[i].height / (SQR(tiff_ifd[i].bps)+1) > thumb_width * thumb_height / (SQR(thumb_misc)+1) && tiff_ifd[i].comp != 34892) { thumb_width = tiff_ifd[i].width; thumb_height = tiff_ifd[i].height; thumb_offset = tiff_ifd[i].offset; thumb_length = tiff_ifd[i].bytes; thumb_misc = tiff_ifd[i].bps; thm = i; } if (thm >= 0) { thumb_misc |= tiff_ifd[thm].samples << 5; switch (tiff_ifd[thm].comp) { case 0: write_thumb = &CLASS layer_thumb; break; case 1: if (tiff_ifd[thm].bps <= 8) write_thumb = &CLASS ppm_thumb; else if (!strcmp(make,"Imacon")) write_thumb = &CLASS ppm16_thumb; else thumb_load_raw = &CLASS kodak_thumb_load_raw; break; case 65000: thumb_load_raw = tiff_ifd[thm].phint == 6 ? &CLASS kodak_ycbcr_load_raw : &CLASS kodak_rgb_load_raw; } } } void CLASS parse_minolta (int base) { int save, tag, len, offset, high=0, wide=0, i, c; short sorder=order; fseek (ifp, base, SEEK_SET); if (fgetc(ifp) || fgetc(ifp)-'M' || fgetc(ifp)-'R') return; order = fgetc(ifp) * 0x101; offset = base + get4() + 8; while ((save=ftell(ifp)) < offset) { for (tag=i=0; i < 4; i++) tag = tag << 8 | fgetc(ifp); len = get4(); switch (tag) { case 0x505244: /* PRD */ fseek (ifp, 8, SEEK_CUR); high = get2(); wide = get2(); break; case 0x574247: /* WBG */ get4(); i = strcmp(model,"DiMAGE A200") ? 0:3; FORC4 cam_mul[c ^ (c >> 1) ^ i] = get2(); break; case 0x545457: /* TTW */ parse_tiff (ftell(ifp)); data_offset = offset; } fseek (ifp, save+len+8, SEEK_SET); } raw_height = high; raw_width = wide; order = sorder; } /* Many cameras have a "debug mode" that writes JPEG and raw at the same time. The raw file has no header, so try to to open the matching JPEG file and read its metadata. */ void CLASS parse_external_jpeg() { const char *file, *ext; char *jname, *jfile, *jext; FILE *save=ifp; ext = strrchr (ifname, '.'); file = strrchr (ifname, '/'); if (!file) file = strrchr (ifname, '\\'); if (!file) file = ifname-1; file++; if (!ext || strlen(ext) != 4 || ext-file != 8) return; jname = (char *) malloc (strlen(ifname) + 1); merror (jname, "parse_external_jpeg()"); strcpy (jname, ifname); jfile = file - ifname + jname; jext = ext - ifname + jname; if (strcasecmp (ext, ".jpg")) { strcpy (jext, isupper(ext[1]) ? ".JPG":".jpg"); if (isdigit(*file)) { memcpy (jfile, file+4, 4); memcpy (jfile+4, file, 4); } } else while (isdigit(*--jext)) { if (*jext != '9') { (*jext)++; break; } *jext = '0'; } if (strcmp (jname, ifname)) { if ((ifp = fopen (jname, "rb"))) { if (verbose) fprintf (stderr,_("Reading metadata from %s ...\n"), jname); parse_tiff (12); thumb_offset = 0; is_raw = 1; fclose (ifp); } } if (!timestamp) fprintf (stderr,_("Failed to read metadata from %s\n"), jname); free (jname); ifp = save; } /* CIFF block 0x1030 contains an 8x8 white sample. Load this into white[][] for use in scale_colors(). */ void CLASS ciff_block_1030() { static const ushort key[] = { 0x410, 0x45f3 }; int i, bpp, row, col, vbits=0; unsigned long bitbuf=0; if ((get2(),get4()) != 0x80008 || !get4()) return; bpp = get2(); if (bpp != 10 && bpp != 12) return; for (i=row=0; row < 8; row++) for (col=0; col < 8; col++) { if (vbits < bpp) { bitbuf = bitbuf << 16 | (get2() ^ key[i++ & 1]); vbits += 16; } white[row][col] = bitbuf << (LONG_BIT - vbits) >> (LONG_BIT - bpp); vbits -= bpp; } } /* Parse a CIFF file, better known as Canon CRW format. */ void CLASS parse_ciff (int offset, int length, int depth) { int tboff, nrecs, c, type, len, save, wbi=-1; ushort key[] = { 0x410, 0x45f3 }; fseek (ifp, offset+length-4, SEEK_SET); tboff = get4() + offset; fseek (ifp, tboff, SEEK_SET); nrecs = get2(); if ((nrecs | depth) > 127) return; while (nrecs--) { type = get2(); len = get4(); save = ftell(ifp) + 4; fseek (ifp, offset+get4(), SEEK_SET); if ((((type >> 8) + 8) | 8) == 0x38) parse_ciff (ftell(ifp), len, depth+1); /* Parse a sub-table */ if (type == 0x0810) fread (artist, 64, 1, ifp); if (type == 0x080a) { fread (make, 64, 1, ifp); fseek (ifp, strlen(make) - 63, SEEK_CUR); fread (model, 64, 1, ifp); } if (type == 0x1810) { width = get4(); height = get4(); pixel_aspect = int_to_float(get4()); flip = get4(); } if (type == 0x1835) /* Get the decoder table */ tiff_compress = get4(); if (type == 0x2007) { thumb_offset = ftell(ifp); thumb_length = len; } if (type == 0x1818) { shutter = pow (2, -int_to_float((get4(),get4()))); aperture = pow (2, int_to_float(get4())/2); } if (type == 0x102a) { iso_speed = pow (2, (get4(),get2())/32.0 - 4) * 50; aperture = pow (2, (get2(),(short)get2())/64.0); shutter = pow (2,-((short)get2())/32.0); wbi = (get2(),get2()); if (wbi > 17) wbi = 0; fseek (ifp, 32, SEEK_CUR); if (shutter > 1e6) shutter = get2()/10.0; } if (type == 0x102c) { if (get2() > 512) { /* Pro90, G1 */ fseek (ifp, 118, SEEK_CUR); FORC4 cam_mul[c ^ 2] = get2(); } else { /* G2, S30, S40 */ fseek (ifp, 98, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2(); } } if (type == 0x0032) { if (len == 768) { /* EOS D30 */ fseek (ifp, 72, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1)] = 1024.0 / get2(); if (!wbi) cam_mul[0] = -1; /* use my auto white balance */ } else if (!cam_mul[0]) { if (get2() == key[0]) /* Pro1, G6, S60, S70 */ c = (strstr(model,"Pro1") ? "012346000000000000":"01345:000000006008")[wbi]-'0'+ 2; else { /* G3, G5, S45, S50 */ c = "023457000000006000"[wbi]-'0'; key[0] = key[1] = 0; } fseek (ifp, 78 + c*8, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1) ^ 1] = get2() ^ key[c & 1]; if (!wbi) cam_mul[0] = -1; } } if (type == 0x10a9) { /* D60, 10D, 300D, and clones */ if (len > 66) wbi = "0134567028"[wbi]-'0'; fseek (ifp, 2 + wbi*8, SEEK_CUR); FORC4 cam_mul[c ^ (c >> 1)] = get2(); } if (type == 0x1030 && (0x18040 >> wbi & 1)) ciff_block_1030(); /* all that don't have 0x10a9 */ if (type == 0x1031) { raw_width = (get2(),get2()); raw_height = get2(); } if (type == 0x5029) { focal_len = len >> 16; if ((len & 0xffff) == 2) focal_len /= 32; } if (type == 0x5813) flash_used = int_to_float(len); if (type == 0x5814) canon_ev = int_to_float(len); if (type == 0x5817) shot_order = len; if (type == 0x5834) unique_id = len; if (type == 0x580e) timestamp = len; if (type == 0x180e) timestamp = get4(); #ifdef LOCALTIME if ((type | 0x4000) == 0x580e) timestamp = mktime (gmtime (×tamp)); #endif fseek (ifp, save, SEEK_SET); } } void CLASS parse_rollei() { char line[128], *val; struct tm t; fseek (ifp, 0, SEEK_SET); memset (&t, 0, sizeof t); do { fgets (line, 128, ifp); if ((val = strchr(line,'='))) *val++ = 0; else val = line + strlen(line); if (!strcmp(line,"DAT")) sscanf (val, "%d.%d.%d", &t.tm_mday, &t.tm_mon, &t.tm_year); if (!strcmp(line,"TIM")) sscanf (val, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); if (!strcmp(line,"HDR")) thumb_offset = atoi(val); if (!strcmp(line,"X ")) raw_width = atoi(val); if (!strcmp(line,"Y ")) raw_height = atoi(val); if (!strcmp(line,"TX ")) thumb_width = atoi(val); if (!strcmp(line,"TY ")) thumb_height = atoi(val); } while (strncmp(line,"EOHD",4)); data_offset = thumb_offset + thumb_width * thumb_height * 2; t.tm_year -= 1900; t.tm_mon -= 1; if (mktime(&t) > 0) timestamp = mktime(&t); strcpy (make, "Rollei"); strcpy (model,"d530flex"); write_thumb = &CLASS rollei_thumb; } void CLASS parse_sinar_ia() { int entries, off; char str[8], *cp; order = 0x4949; fseek (ifp, 4, SEEK_SET); entries = get4(); fseek (ifp, get4(), SEEK_SET); while (entries--) { off = get4(); get4(); fread (str, 8, 1, ifp); if (!strcmp(str,"META")) meta_offset = off; if (!strcmp(str,"THUMB")) thumb_offset = off; if (!strcmp(str,"RAW0")) data_offset = off; } fseek (ifp, meta_offset+20, SEEK_SET); fread (make, 64, 1, ifp); make[63] = 0; if ((cp = strchr(make,' '))) { strcpy (model, cp+1); *cp = 0; } raw_width = get2(); raw_height = get2(); load_raw = &CLASS unpacked_load_raw; thumb_width = (get4(),get2()); thumb_height = get2(); write_thumb = &CLASS ppm_thumb; maximum = 0x3fff; } void CLASS parse_phase_one (int base) { unsigned entries, tag, type, len, data, save, i, c; float romm_cam[3][3]; char *cp; memset (&ph1, 0, sizeof ph1); fseek (ifp, base, SEEK_SET); order = get4() & 0xffff; if (get4() >> 8 != 0x526177) return; /* "Raw" */ fseek (ifp, get4()+base, SEEK_SET); entries = get4(); get4(); while (entries--) { tag = get4(); type = get4(); len = get4(); data = get4(); save = ftell(ifp); fseek (ifp, base+data, SEEK_SET); switch (tag) { case 0x100: flip = "0653"[data & 3]-'0'; break; case 0x106: for (i=0; i < 9; i++) romm_cam[0][i] = getreal(11); romm_coeff (romm_cam); break; case 0x107: FORC3 cam_mul[c] = getreal(11); break; case 0x108: raw_width = data; break; case 0x109: raw_height = data; break; case 0x10a: left_margin = data; break; case 0x10b: top_margin = data; break; case 0x10c: width = data; break; case 0x10d: height = data; break; case 0x10e: ph1.format = data; break; case 0x10f: data_offset = data+base; break; case 0x110: meta_offset = data+base; meta_length = len; break; case 0x112: ph1.key_off = save - 4; break; case 0x210: ph1.tag_210 = int_to_float(data); break; case 0x21a: ph1.tag_21a = data; break; case 0x21c: strip_offset = data+base; break; case 0x21d: ph1.black = data; break; case 0x222: ph1.split_col = data; break; case 0x223: ph1.black_off = data+base; break; case 0x301: model[63] = 0; fread (model, 1, 63, ifp); if ((cp = strstr(model," camera"))) *cp = 0; } fseek (ifp, save, SEEK_SET); } load_raw = ph1.format < 3 ? &CLASS phase_one_load_raw : &CLASS phase_one_load_raw_c; maximum = 0xffff; strcpy (make, "Phase One"); if (model[0]) return; switch (raw_height) { case 2060: strcpy (model,"LightPhase"); break; case 2682: strcpy (model,"H 10"); break; case 4128: strcpy (model,"H 20"); break; case 5488: strcpy (model,"H 25"); break; } } void CLASS parse_fuji (int offset) { unsigned entries, tag, len, save, c; fseek (ifp, offset, SEEK_SET); entries = get4(); if (entries > 255) return; while (entries--) { tag = get2(); len = get2(); save = ftell(ifp); if (tag == 0x100) { raw_height = get2(); raw_width = get2(); } else if (tag == 0x121) { height = get2(); if ((width = get2()) == 4284) width += 3; } else if (tag == 0x130) { fuji_layout = fgetc(ifp) >> 7; fuji_width = !(fgetc(ifp) & 8); } else if (tag == 0x131) { filters = 9; FORC(36) xtrans[0][35-c] = fgetc(ifp) & 3; } else if (tag == 0x2ff0) { FORC4 cam_mul[c ^ 1] = get2(); } else if (tag == 0xc000) { c = order; order = 0x4949; if ((tag = get4()) > 10000) tag = get4(); width = tag; height = get4(); order = c; } fseek (ifp, save+len, SEEK_SET); } height <<= fuji_layout; width >>= fuji_layout; } int CLASS parse_jpeg (int offset) { int len, save, hlen, mark; fseek (ifp, offset, SEEK_SET); if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return 0; while (fgetc(ifp) == 0xff && (mark = fgetc(ifp)) != 0xda) { order = 0x4d4d; len = get2() - 2; save = ftell(ifp); if (mark == 0xc0 || mark == 0xc3) { fgetc(ifp); raw_height = get2(); raw_width = get2(); } order = get2(); hlen = get4(); if (get4() == 0x48454150) /* "HEAP" */ parse_ciff (save+hlen, len-hlen, 0); if (parse_tiff (save+6)) apply_tiff(); fseek (ifp, save+len, SEEK_SET); } return 1; } void CLASS parse_riff() { unsigned i, size, end; char tag[4], date[64], month[64]; static const char mon[12][4] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; struct tm t; order = 0x4949; fread (tag, 4, 1, ifp); size = get4(); end = ftell(ifp) + size; if (!memcmp(tag,"RIFF",4) || !memcmp(tag,"LIST",4)) { get4(); while (ftell(ifp)+7 < end) parse_riff(); } else if (!memcmp(tag,"nctg",4)) { while (ftell(ifp)+7 < end) { i = get2(); size = get2(); if ((i+1) >> 1 == 10 && size == 20) get_timestamp(0); else fseek (ifp, size, SEEK_CUR); } } else if (!memcmp(tag,"IDIT",4) && size < 64) { fread (date, 64, 1, ifp); date[size] = 0; memset (&t, 0, sizeof t); if (sscanf (date, "%*s %s %d %d:%d:%d %d", month, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec, &t.tm_year) == 6) { for (i=0; i < 12 && strcasecmp(mon[i],month); i++); t.tm_mon = i; t.tm_year -= 1900; if (mktime(&t) > 0) timestamp = mktime(&t); } } else fseek (ifp, size, SEEK_CUR); } void CLASS parse_smal (int offset, int fsize) { int ver; fseek (ifp, offset+2, SEEK_SET); order = 0x4949; ver = fgetc(ifp); if (ver == 6) fseek (ifp, 5, SEEK_CUR); if (get4() != fsize) return; if (ver > 6) data_offset = get4(); raw_height = height = get2(); raw_width = width = get2(); strcpy (make, "SMaL"); sprintf (model, "v%d %dx%d", ver, width, height); if (ver == 6) load_raw = &CLASS smal_v6_load_raw; if (ver == 9) load_raw = &CLASS smal_v9_load_raw; } void CLASS parse_cine() { unsigned off_head, off_setup, off_image, i; order = 0x4949; fseek (ifp, 4, SEEK_SET); is_raw = get2() == 2; fseek (ifp, 14, SEEK_CUR); is_raw *= get4(); off_head = get4(); off_setup = get4(); off_image = get4(); timestamp = get4(); if ((i = get4())) timestamp = i; fseek (ifp, off_head+4, SEEK_SET); raw_width = get4(); raw_height = get4(); switch (get2(),get2()) { case 8: load_raw = &CLASS eight_bit_load_raw; break; case 16: load_raw = &CLASS unpacked_load_raw; } fseek (ifp, off_setup+792, SEEK_SET); strcpy (make, "CINE"); sprintf (model, "%d", get4()); fseek (ifp, 12, SEEK_CUR); switch ((i=get4()) & 0xffffff) { case 3: filters = 0x94949494; break; case 4: filters = 0x49494949; break; default: is_raw = 0; } fseek (ifp, 72, SEEK_CUR); switch ((get4()+3600) % 360) { case 270: flip = 4; break; case 180: flip = 1; break; case 90: flip = 7; break; case 0: flip = 2; } cam_mul[0] = getreal(11); cam_mul[2] = getreal(11); maximum = ~(-1 << get4()); fseek (ifp, 668, SEEK_CUR); shutter = get4()/1000000000.0; fseek (ifp, off_image, SEEK_SET); if (shot_select < is_raw) fseek (ifp, shot_select*8, SEEK_CUR); data_offset = (INT64) get4() + 8; data_offset += (INT64) get4() << 32; } void CLASS parse_redcine() { unsigned i, len, rdvo; order = 0x4d4d; is_raw = 0; fseek (ifp, 52, SEEK_SET); width = get4(); height = get4(); fseek (ifp, 0, SEEK_END); fseek (ifp, -(i = ftello(ifp) & 511), SEEK_CUR); if (get4() != i || get4() != 0x52454f42) { fprintf (stderr,_("%s: Tail is missing, parsing from head...\n"), ifname); fseek (ifp, 0, SEEK_SET); while ((len = get4()) != EOF) { if (get4() == 0x52454456) if (is_raw++ == shot_select) data_offset = ftello(ifp) - 8; fseek (ifp, len-8, SEEK_CUR); } } else { rdvo = get4(); fseek (ifp, 12, SEEK_CUR); is_raw = get4(); fseeko (ifp, rdvo+8 + shot_select*4, SEEK_SET); data_offset = get4(); } } char * CLASS foveon_gets (int offset, char *str, int len) { int i; fseek (ifp, offset, SEEK_SET); for (i=0; i < len-1; i++) if ((str[i] = get2()) == 0) break; str[i] = 0; return str; } void CLASS parse_foveon() { int entries, img=0, off, len, tag, save, i, wide, high, pent, poff[256][2]; char name[64], value[64]; order = 0x4949; /* Little-endian */ fseek (ifp, 36, SEEK_SET); flip = get4(); fseek (ifp, -4, SEEK_END); fseek (ifp, get4(), SEEK_SET); if (get4() != 0x64434553) return; /* SECd */ entries = (get4(),get4()); while (entries--) { off = get4(); len = get4(); tag = get4(); save = ftell(ifp); fseek (ifp, off, SEEK_SET); if (get4() != (0x20434553 | (tag << 24))) return; switch (tag) { case 0x47414d49: /* IMAG */ case 0x32414d49: /* IMA2 */ fseek (ifp, 8, SEEK_CUR); pent = get4(); wide = get4(); high = get4(); if (wide > raw_width && high > raw_height) { switch (pent) { case 5: load_flags = 1; case 6: load_raw = &CLASS foveon_sd_load_raw; break; case 30: load_raw = &CLASS foveon_dp_load_raw; break; default: load_raw = 0; } raw_width = wide; raw_height = high; data_offset = off+28; is_foveon = 1; } fseek (ifp, off+28, SEEK_SET); if (fgetc(ifp) == 0xff && fgetc(ifp) == 0xd8 && thumb_length < len-28) { thumb_offset = off+28; thumb_length = len-28; write_thumb = &CLASS jpeg_thumb; } if (++img == 2 && !thumb_length) { thumb_offset = off+24; thumb_width = wide; thumb_height = high; write_thumb = &CLASS foveon_thumb; } break; case 0x464d4143: /* CAMF */ meta_offset = off+8; meta_length = len-28; break; case 0x504f5250: /* PROP */ pent = (get4(),get4()); fseek (ifp, 12, SEEK_CUR); off += pent*8 + 24; if ((unsigned) pent > 256) pent=256; for (i=0; i < pent*2; i++) poff[0][i] = off + get4()*2; for (i=0; i < pent; i++) { foveon_gets (poff[i][0], name, 64); foveon_gets (poff[i][1], value, 64); if (!strcmp (name, "ISO")) iso_speed = atoi(value); if (!strcmp (name, "CAMMANUF")) strcpy (make, value); if (!strcmp (name, "CAMMODEL")) strcpy (model, value); if (!strcmp (name, "WB_DESC")) strcpy (model2, value); if (!strcmp (name, "TIME")) timestamp = atoi(value); if (!strcmp (name, "EXPTIME")) shutter = atoi(value) / 1000000.0; if (!strcmp (name, "APERTURE")) aperture = atof(value); if (!strcmp (name, "FLENGTH")) focal_len = atof(value); } #ifdef LOCALTIME timestamp = mktime (gmtime (×tamp)); #endif } fseek (ifp, save, SEEK_SET); } } /* All matrices are from Adobe DNG Converter unless otherwise noted. */ void CLASS adobe_coeff (const char *make, const char *model) { static const struct { const char *prefix; short black, maximum, trans[12]; } table[] = { { "AgfaPhoto DC-833m", 0, 0, /* DJC */ { 11438,-3762,-1115,-2409,9914,2497,-1227,2295,5300 } }, { "Apple QuickTake", 0, 0, /* DJC */ { 21392,-5653,-3353,2406,8010,-415,7166,1427,2078 } }, { "Canon EOS D2000", 0, 0, { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, { "Canon EOS D6000", 0, 0, { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, { "Canon EOS D30", 0, 0, { 9805,-2689,-1312,-5803,13064,3068,-2438,3075,8775 } }, { "Canon EOS D60", 0, 0xfa0, { 6188,-1341,-890,-7168,14489,2937,-2640,3228,8483 } }, { "Canon EOS 5D Mark III", 0, 0x3c80, { 6722,-635,-963,-4287,12460,2028,-908,2162,5668 } }, { "Canon EOS 5D Mark II", 0, 0x3cf0, { 4716,603,-830,-7798,15474,2480,-1496,1937,6651 } }, { "Canon EOS 5D", 0, 0xe6c, { 6347,-479,-972,-8297,15954,2480,-1968,2131,7649 } }, { "Canon EOS 6D", 0, 0x3c82, { 7034,-804,-1014,-4420,12564,2058,-851,1994,5758 } }, { "Canon EOS 7D", 0, 0x3510, { 6844,-996,-856,-3876,11761,2396,-593,1772,6198 } }, { "Canon EOS 10D", 0, 0xfa0, { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, { "Canon EOS 20Da", 0, 0, { 14155,-5065,-1382,-6550,14633,2039,-1623,1824,6561 } }, { "Canon EOS 20D", 0, 0xfff, { 6599,-537,-891,-8071,15783,2424,-1983,2234,7462 } }, { "Canon EOS 30D", 0, 0, { 6257,-303,-1000,-7880,15621,2396,-1714,1904,7046 } }, { "Canon EOS 40D", 0, 0x3f60, { 6071,-747,-856,-7653,15365,2441,-2025,2553,7315 } }, { "Canon EOS 50D", 0, 0x3d93, { 4920,616,-593,-6493,13964,2784,-1774,3178,7005 } }, { "Canon EOS 60D", 0, 0x2ff7, { 6719,-994,-925,-4408,12426,2211,-887,2129,6051 } }, { "Canon EOS 100D", 0, 0x350f, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 300D", 0, 0xfa0, { 8197,-2000,-1118,-6714,14335,2592,-2536,3178,8266 } }, { "Canon EOS 350D", 0, 0xfff, { 6018,-617,-965,-8645,15881,2975,-1530,1719,7642 } }, { "Canon EOS 400D", 0, 0xe8e, { 7054,-1501,-990,-8156,15544,2812,-1278,1414,7796 } }, { "Canon EOS 450D", 0, 0x390d, { 5784,-262,-821,-7539,15064,2672,-1982,2681,7427 } }, { "Canon EOS 500D", 0, 0x3479, { 4763,712,-646,-6821,14399,2640,-1921,3276,6561 } }, { "Canon EOS 550D", 0, 0x3dd7, { 6941,-1164,-857,-3825,11597,2534,-416,1540,6039 } }, { "Canon EOS 600D", 0, 0x3510, { 6461,-907,-882,-4300,12184,2378,-819,1944,5931 } }, { "Canon EOS 650D", 0, 0x354d, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 700D", 0, 0x3c00, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS 1000D", 0, 0xe43, { 6771,-1139,-977,-7818,15123,2928,-1244,1437,7533 } }, { "Canon EOS 1100D", 0, 0x3510, { 6444,-904,-893,-4563,12308,2535,-903,2016,6728 } }, { "Canon EOS M", 0, 0, { 6602,-841,-939,-4472,12458,2247,-975,2039,6148 } }, { "Canon EOS-1Ds Mark III", 0, 0x3bb0, { 5859,-211,-930,-8255,16017,2353,-1732,1887,7448 } }, { "Canon EOS-1Ds Mark II", 0, 0xe80, { 6517,-602,-867,-8180,15926,2378,-1618,1771,7633 } }, { "Canon EOS-1D Mark IV", 0, 0x3bb0, { 6014,-220,-795,-4109,12014,2361,-561,1824,5787 } }, { "Canon EOS-1D Mark III", 0, 0x3bb0, { 6291,-540,-976,-8350,16145,2311,-1714,1858,7326 } }, { "Canon EOS-1D Mark II N", 0, 0xe80, { 6240,-466,-822,-8180,15825,2500,-1801,1938,8042 } }, { "Canon EOS-1D Mark II", 0, 0xe80, { 6264,-582,-724,-8312,15948,2504,-1744,1919,8664 } }, { "Canon EOS-1DS", 0, 0xe20, { 4374,3631,-1743,-7520,15212,2472,-2892,3632,8161 } }, { "Canon EOS-1D C", 0, 0x3c4e, { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, { "Canon EOS-1D X", 0, 0x3c4e, { 6847,-614,-1014,-4669,12737,2139,-1197,2488,6846 } }, { "Canon EOS-1D", 0, 0xe20, { 6806,-179,-1020,-8097,16415,1687,-3267,4236,7690 } }, { "Canon PowerShot A530", 0, 0, { 0 } }, /* don't want the A5 matrix */ { "Canon PowerShot A50", 0, 0, { -5300,9846,1776,3436,684,3939,-5540,9879,6200,-1404,11175,217 } }, { "Canon PowerShot A5", 0, 0, { -4801,9475,1952,2926,1611,4094,-5259,10164,5947,-1554,10883,547 } }, { "Canon PowerShot G10", 0, 0, { 11093,-3906,-1028,-5047,12492,2879,-1003,1750,5561 } }, { "Canon PowerShot G11", 0, 0, { 12177,-4817,-1069,-1612,9864,2049,-98,850,4471 } }, { "Canon PowerShot G12", 0, 0, { 13244,-5501,-1248,-1508,9858,1935,-270,1083,4366 } }, { "Canon PowerShot G15", 0, 0, { 7474,-2301,-567,-4056,11456,2975,-222,716,4181 } }, { "Canon PowerShot G1 X", 0, 0, { 7378,-1255,-1043,-4088,12251,2048,-876,1946,5805 } }, { "Canon PowerShot G1", 0, 0, { -4778,9467,2172,4743,-1141,4344,-5146,9908,6077,-1566,11051,557 } }, { "Canon PowerShot G2", 0, 0, { 9087,-2693,-1049,-6715,14382,2537,-2291,2819,7790 } }, { "Canon PowerShot G3", 0, 0, { 9212,-2781,-1073,-6573,14189,2605,-2300,2844,7664 } }, { "Canon PowerShot G5", 0, 0, { 9757,-2872,-933,-5972,13861,2301,-1622,2328,7212 } }, { "Canon PowerShot G6", 0, 0, { 9877,-3775,-871,-7613,14807,3072,-1448,1305,7485 } }, { "Canon PowerShot G9", 0, 0, { 7368,-2141,-598,-5621,13254,2625,-1418,1696,5743 } }, { "Canon PowerShot Pro1", 0, 0, { 10062,-3522,-999,-7643,15117,2730,-765,817,7323 } }, { "Canon PowerShot Pro70", 34, 0, { -4155,9818,1529,3939,-25,4522,-5521,9870,6610,-2238,10873,1342 } }, { "Canon PowerShot Pro90", 0, 0, { -4963,9896,2235,4642,-987,4294,-5162,10011,5859,-1770,11230,577 } }, { "Canon PowerShot S30", 0, 0, { 10566,-3652,-1129,-6552,14662,2006,-2197,2581,7670 } }, { "Canon PowerShot S40", 0, 0, { 8510,-2487,-940,-6869,14231,2900,-2318,2829,9013 } }, { "Canon PowerShot S45", 0, 0, { 8163,-2333,-955,-6682,14174,2751,-2077,2597,8041 } }, { "Canon PowerShot S50", 0, 0, { 8882,-2571,-863,-6348,14234,2288,-1516,2172,6569 } }, { "Canon PowerShot S60", 0, 0, { 8795,-2482,-797,-7804,15403,2573,-1422,1996,7082 } }, { "Canon PowerShot S70", 0, 0, { 9976,-3810,-832,-7115,14463,2906,-901,989,7889 } }, { "Canon PowerShot S90", 0, 0, { 12374,-5016,-1049,-1677,9902,2078,-83,852,4683 } }, { "Canon PowerShot S95", 0, 0, { 13440,-5896,-1279,-1236,9598,1931,-180,1001,4651 } }, { "Canon PowerShot S100", 0, 0, { 7968,-2565,-636,-2873,10697,2513,180,667,4211 } }, { "Canon PowerShot S110", 0, 0, { 8039,-2643,-654,-3783,11230,2930,-206,690,4194 } }, { "Canon PowerShot SX1 IS", 0, 0, { 6578,-259,-502,-5974,13030,3309,-308,1058,4970 } }, { "Canon PowerShot SX50 HS", 0, 0, { 12432,-4753,-1247,-2110,10691,1629,-412,1623,4926 } }, { "Canon PowerShot A3300", 0, 0, /* DJC */ { 10826,-3654,-1023,-3215,11310,1906,0,999,4960 } }, { "Canon PowerShot A470", 0, 0, /* DJC */ { 12513,-4407,-1242,-2680,10276,2405,-878,2215,4734 } }, { "Canon PowerShot A610", 0, 0, /* DJC */ { 15591,-6402,-1592,-5365,13198,2168,-1300,1824,5075 } }, { "Canon PowerShot A620", 0, 0, /* DJC */ { 15265,-6193,-1558,-4125,12116,2010,-888,1639,5220 } }, { "Canon PowerShot A630", 0, 0, /* DJC */ { 14201,-5308,-1757,-6087,14472,1617,-2191,3105,5348 } }, { "Canon PowerShot A640", 0, 0, /* DJC */ { 13124,-5329,-1390,-3602,11658,1944,-1612,2863,4885 } }, { "Canon PowerShot A650", 0, 0, /* DJC */ { 9427,-3036,-959,-2581,10671,1911,-1039,1982,4430 } }, { "Canon PowerShot A720", 0, 0, /* DJC */ { 14573,-5482,-1546,-1266,9799,1468,-1040,1912,3810 } }, { "Canon PowerShot S3 IS", 0, 0, /* DJC */ { 14062,-5199,-1446,-4712,12470,2243,-1286,2028,4836 } }, { "Canon PowerShot SX110 IS", 0, 0, /* DJC */ { 14134,-5576,-1527,-1991,10719,1273,-1158,1929,3581 } }, { "Canon PowerShot SX220", 0, 0, /* DJC */ { 13898,-5076,-1447,-1405,10109,1297,-244,1860,3687 } }, { "Casio EX-S20", 0, 0, /* DJC */ { 11634,-3924,-1128,-4968,12954,2015,-1588,2648,7206 } }, { "Casio EX-Z750", 0, 0, /* DJC */ { 10819,-3873,-1099,-4903,13730,1175,-1755,3751,4632 } }, { "Casio EX-Z10", 128, 0xfff, /* DJC */ { 9790,-3338,-603,-2321,10222,2099,-344,1273,4799 } }, { "CINE 650", 0, 0, { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, { "CINE 660", 0, 0, { 3390,480,-500,-800,3610,340,-550,2336,1192 } }, { "CINE", 0, 0, { 20183,-4295,-423,-3940,15330,3985,-280,4870,9800 } }, { "Contax N Digital", 0, 0xf1e, { 7777,1285,-1053,-9280,16543,2916,-3677,5679,7060 } }, { "Epson R-D1", 0, 0, { 6827,-1878,-732,-8429,16012,2564,-704,592,7145 } }, { "Fujifilm E550", 0, 0, { 11044,-3888,-1120,-7248,15168,2208,-1531,2277,8069 } }, { "Fujifilm E900", 0, 0, { 9183,-2526,-1078,-7461,15071,2574,-2022,2440,8639 } }, { "Fujifilm F5", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm F6", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm F77", 0, 0xfe9, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm F7", 0, 0, { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, { "Fujifilm F8", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm S100FS", 514, 0, { 11521,-4355,-1065,-6524,13767,3058,-1466,1984,6045 } }, { "Fujifilm S200EXR", 512, 0x3fff, { 11401,-4498,-1312,-5088,12751,2613,-838,1568,5941 } }, { "Fujifilm S20Pro", 0, 0, { 10004,-3219,-1201,-7036,15047,2107,-1863,2565,7736 } }, { "Fujifilm S2Pro", 128, 0, { 12492,-4690,-1402,-7033,15423,1647,-1507,2111,7697 } }, { "Fujifilm S3Pro", 0, 0, { 11807,-4612,-1294,-8927,16968,1988,-2120,2741,8006 } }, { "Fujifilm S5Pro", 0, 0, { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, { "Fujifilm S5000", 0, 0, { 8754,-2732,-1019,-7204,15069,2276,-1702,2334,6982 } }, { "Fujifilm S5100", 0, 0, { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, { "Fujifilm S5500", 0, 0, { 11940,-4431,-1255,-6766,14428,2542,-993,1165,7421 } }, { "Fujifilm S5200", 0, 0, { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, { "Fujifilm S5600", 0, 0, { 9636,-2804,-988,-7442,15040,2589,-1803,2311,8621 } }, { "Fujifilm S6", 0, 0, { 12628,-4887,-1401,-6861,14996,1962,-2198,2782,7091 } }, { "Fujifilm S7000", 0, 0, { 10190,-3506,-1312,-7153,15051,2238,-2003,2399,7505 } }, { "Fujifilm S9000", 0, 0, { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, { "Fujifilm S9500", 0, 0, { 10491,-3423,-1145,-7385,15027,2538,-1809,2275,8692 } }, { "Fujifilm S9100", 0, 0, { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, { "Fujifilm S9600", 0, 0, { 12343,-4515,-1285,-7165,14899,2435,-1895,2496,8800 } }, { "Fujifilm SL1000", 0, 0, { 11705,-4262,-1107,-2282,10791,1709,-555,1713,4945 } }, { "Fujifilm IS-1", 0, 0, { 21461,-10807,-1441,-2332,10599,1999,289,875,7703 } }, { "Fujifilm IS Pro", 0, 0, { 12300,-5110,-1304,-9117,17143,1998,-1947,2448,8100 } }, { "Fujifilm HS10 HS11", 0, 0xf68, { 12440,-3954,-1183,-1123,9674,1708,-83,1614,4086 } }, { "Fujifilm HS20EXR", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm HS3", 0, 0, { 13690,-5358,-1474,-3369,11600,1998,-132,1554,4395 } }, { "Fujifilm HS50EXR", 0, 0, { 12085,-4727,-953,-3257,11489,2002,-511,2046,4592 } }, { "Fujifilm X100S", 0, 0, { 10592,-4262,-1008,-3514,11355,2465,-870,2025,6386 } }, { "Fujifilm X100", 0, 0, { 12161,-4457,-1069,-5034,12874,2400,-795,1724,6904 } }, { "Fujifilm X10", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, { "Fujifilm X20", 0, 0, { 11768,-4971,-1133,-4904,12927,2183,-480,1723,4605 } }, { "Fujifilm X-Pro1", 0, 0, { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, { "Fujifilm X-E1", 0, 0, { 10413,-3996,-993,-3721,11640,2361,-733,1540,6011 } }, { "Fujifilm XF1", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, { "Fujifilm X-S1", 0, 0, { 13509,-6199,-1254,-4430,12733,1865,-331,1441,5022 } }, { "Imacon Ixpress", 0, 0, /* DJC */ { 7025,-1415,-704,-5188,13765,1424,-1248,2742,6038 } }, { "Kodak NC2000", 0, 0, { 13891,-6055,-803,-465,9919,642,2121,82,1291 } }, { "Kodak DCS315C", 8, 0, { 17523,-4827,-2510,756,8546,-137,6113,1649,2250 } }, { "Kodak DCS330C", 8, 0, { 20620,-7572,-2801,-103,10073,-396,3551,-233,2220 } }, { "Kodak DCS420", 0, 0, { 10868,-1852,-644,-1537,11083,484,2343,628,2216 } }, { "Kodak DCS460", 0, 0, { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, { "Kodak EOSDCS1", 0, 0, { 10592,-2206,-967,-1944,11685,230,2206,670,1273 } }, { "Kodak EOSDCS3B", 0, 0, { 9898,-2700,-940,-2478,12219,206,1985,634,1031 } }, { "Kodak DCS520C", 178, 0, { 24542,-10860,-3401,-1490,11370,-297,2858,-605,3225 } }, { "Kodak DCS560C", 177, 0, { 20482,-7172,-3125,-1033,10410,-285,2542,226,3136 } }, { "Kodak DCS620C", 177, 0, { 23617,-10175,-3149,-2054,11749,-272,2586,-489,3453 } }, { "Kodak DCS620X", 176, 0, { 13095,-6231,154,12221,-21,-2137,895,4602,2258 } }, { "Kodak DCS660C", 173, 0, { 18244,-6351,-2739,-791,11193,-521,3711,-129,2802 } }, { "Kodak DCS720X", 0, 0, { 11775,-5884,950,9556,1846,-1286,-1019,6221,2728 } }, { "Kodak DCS760C", 0, 0, { 16623,-6309,-1411,-4344,13923,323,2285,274,2926 } }, { "Kodak DCS Pro SLR", 0, 0, { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, { "Kodak DCS Pro 14nx", 0, 0, { 5494,2393,-232,-6427,13850,2846,-1876,3997,5445 } }, { "Kodak DCS Pro 14", 0, 0, { 7791,3128,-776,-8588,16458,2039,-2455,4006,6198 } }, { "Kodak ProBack645", 0, 0, { 16414,-6060,-1470,-3555,13037,473,2545,122,4948 } }, { "Kodak ProBack", 0, 0, { 21179,-8316,-2918,-915,11019,-165,3477,-180,4210 } }, { "Kodak P712", 0, 0, { 9658,-3314,-823,-5163,12695,2768,-1342,1843,6044 } }, { "Kodak P850", 0, 0xf7c, { 10511,-3836,-1102,-6946,14587,2558,-1481,1792,6246 } }, { "Kodak P880", 0, 0xfff, { 12805,-4662,-1376,-7480,15267,2360,-1626,2194,7904 } }, { "Kodak EasyShare Z980", 0, 0, { 11313,-3559,-1101,-3893,11891,2257,-1214,2398,4908 } }, { "Kodak EasyShare Z981", 0, 0, { 12729,-4717,-1188,-1367,9187,2582,274,860,4411 } }, { "Kodak EasyShare Z990", 0, 0xfed, { 11749,-4048,-1309,-1867,10572,1489,-138,1449,4522 } }, { "Kodak EASYSHARE Z1015", 0, 0xef1, { 11265,-4286,-992,-4694,12343,2647,-1090,1523,5447 } }, { "Leaf CMost", 0, 0, { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, { "Leaf Valeo 6", 0, 0, { 3952,2189,449,-6701,14585,2275,-4536,7349,6536 } }, { "Leaf Aptus 54S", 0, 0, { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, { "Leaf Aptus 65", 0, 0, { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, { "Leaf Aptus 75", 0, 0, { 7914,1414,-1190,-8777,16582,2280,-2811,4605,5562 } }, { "Leaf", 0, 0, { 8236,1746,-1314,-8251,15953,2428,-3673,5786,5771 } }, { "Mamiya ZD", 0, 0, { 7645,2579,-1363,-8689,16717,2015,-3712,5941,5961 } }, { "Micron 2010", 110, 0, /* DJC */ { 16695,-3761,-2151,155,9682,163,3433,951,4904 } }, { "Minolta DiMAGE 5", 0, 0xf7d, { 8983,-2942,-963,-6556,14476,2237,-2426,2887,8014 } }, { "Minolta DiMAGE 7Hi", 0, 0xf7d, { 11368,-3894,-1242,-6521,14358,2339,-2475,3056,7285 } }, { "Minolta DiMAGE 7", 0, 0xf7d, { 9144,-2777,-998,-6676,14556,2281,-2470,3019,7744 } }, { "Minolta DiMAGE A1", 0, 0xf8b, { 9274,-2547,-1167,-8220,16323,1943,-2273,2720,8340 } }, { "Minolta DiMAGE A200", 0, 0, { 8560,-2487,-986,-8112,15535,2771,-1209,1324,7743 } }, { "Minolta DiMAGE A2", 0, 0xf8f, { 9097,-2726,-1053,-8073,15506,2762,-966,981,7763 } }, { "Minolta DiMAGE Z2", 0, 0, /* DJC */ { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, { "Minolta DYNAX 5", 0, 0xffb, { 10284,-3283,-1086,-7957,15762,2316,-829,882,6644 } }, { "Minolta DYNAX 7", 0, 0xffb, { 10239,-3104,-1099,-8037,15727,2451,-927,925,6871 } }, { "Motorola PIXL", 0, 0, /* DJC */ { 8898,-989,-1033,-3292,11619,1674,-661,3178,5216 } }, { "Nikon D100", 0, 0, { 5902,-933,-782,-8983,16719,2354,-1402,1455,6464 } }, { "Nikon D1H", 0, 0, { 7577,-2166,-926,-7454,15592,1934,-2377,2808,8606 } }, { "Nikon D1X", 0, 0, { 7702,-2245,-975,-9114,17242,1875,-2679,3055,8521 } }, { "Nikon D1", 0, 0, /* multiplied by 2.218750, 1.0, 1.148438 */ { 16772,-4726,-2141,-7611,15713,1972,-2846,3494,9521 } }, { "Nikon D200", 0, 0xfbc, { 8367,-2248,-763,-8758,16447,2422,-1527,1550,8053 } }, { "Nikon D2H", 0, 0, { 5710,-901,-615,-8594,16617,2024,-2975,4120,6830 } }, { "Nikon D2X", 0, 0, { 10231,-2769,-1255,-8301,15900,2552,-797,680,7148 } }, { "Nikon D3000", 0, 0, { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, { "Nikon D3100", 0, 0, { 7911,-2167,-813,-5327,13150,2408,-1288,2483,7968 } }, { "Nikon D3200", 0, 0xfb9, { 7013,-1408,-635,-5268,12902,2640,-1470,2801,7379 } }, { "Nikon D300", 0, 0, { 9030,-1992,-715,-8465,16302,2255,-2689,3217,8069 } }, { "Nikon D3X", 0, 0, { 7171,-1986,-648,-8085,15555,2718,-2170,2512,7457 } }, { "Nikon D3S", 0, 0, { 8828,-2406,-694,-4874,12603,2541,-660,1509,7587 } }, { "Nikon D3", 0, 0, { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, { "Nikon D40X", 0, 0, { 8819,-2543,-911,-9025,16928,2151,-1329,1213,8449 } }, { "Nikon D40", 0, 0, { 6992,-1668,-806,-8138,15748,2543,-874,850,7897 } }, { "Nikon D4", 0, 0, { 8598,-2848,-857,-5618,13606,2195,-1002,1773,7137 } }, { "Nikon D5000", 0, 0xf00, { 7309,-1403,-519,-8474,16008,2622,-2433,2826,8064 } }, { "Nikon D5100", 0, 0x3de6, { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon D5200", 0, 0, { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, { "Nikon D50", 0, 0, { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, { "Nikon D600", 0, 0x3e07, { 8178,-2245,-609,-4857,12394,2776,-1207,2086,7298 } }, { "Nikon D60", 0, 0, { 8736,-2458,-935,-9075,16894,2251,-1354,1242,8263 } }, { "Nikon D7000", 0, 0, { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon D7100", 0, 0, { 8322,-3112,-1047,-6367,14342,2179,-988,1638,6394 } }, { "Nikon D700", 0, 0, { 8139,-2171,-663,-8747,16541,2295,-1925,2008,8093 } }, { "Nikon D70", 0, 0, { 7732,-2422,-789,-8238,15884,2498,-859,783,7330 } }, { "Nikon D800", 0, 0, { 7866,-2108,-555,-4869,12483,2681,-1176,2069,7501 } }, { "Nikon D80", 0, 0, { 8629,-2410,-883,-9055,16940,2171,-1490,1363,8520 } }, { "Nikon D90", 0, 0xf00, { 7309,-1403,-519,-8474,16008,2622,-2434,2826,8064 } }, { "Nikon E700", 0, 0x3dd, /* DJC */ { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, { "Nikon E800", 0, 0x3dd, /* DJC */ { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, { "Nikon E950", 0, 0x3dd, /* DJC */ { -3746,10611,1665,9621,-1734,2114,-2389,7082,3064,3406,6116,-244 } }, { "Nikon E995", 0, 0, /* copied from E5000 */ { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, { "Nikon E2100", 0, 0, /* copied from Z2, new white balance */ { 13142,-4152,-1596,-4655,12374,2282,-1769,2696,6711} }, { "Nikon E2500", 0, 0, { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, { "Nikon E3200", 0, 0, /* DJC */ { 9846,-2085,-1019,-3278,11109,2170,-774,2134,5745 } }, { "Nikon E4300", 0, 0, /* copied from Minolta DiMAGE Z2 */ { 11280,-3564,-1370,-4655,12374,2282,-1423,2168,5396 } }, { "Nikon E4500", 0, 0, { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, { "Nikon E5000", 0, 0, { -5547,11762,2189,5814,-558,3342,-4924,9840,5949,688,9083,96 } }, { "Nikon E5400", 0, 0, { 9349,-2987,-1001,-7919,15766,2266,-2098,2680,6839 } }, { "Nikon E5700", 0, 0, { -5368,11478,2368,5537,-113,3148,-4969,10021,5782,778,9028,211 } }, { "Nikon E8400", 0, 0, { 7842,-2320,-992,-8154,15718,2599,-1098,1342,7560 } }, { "Nikon E8700", 0, 0, { 8489,-2583,-1036,-8051,15583,2643,-1307,1407,7354 } }, { "Nikon E8800", 0, 0, { 7971,-2314,-913,-8451,15762,2894,-1442,1520,7610 } }, { "Nikon COOLPIX A", 0, 0, { 8198,-2239,-724,-4871,12389,2798,-1043,2050,7181 } }, { "Nikon COOLPIX P330", 0, 0, { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, { "Nikon COOLPIX P6000", 0, 0, { 9698,-3367,-914,-4706,12584,2368,-837,968,5801 } }, { "Nikon COOLPIX P7000", 0, 0, { 11432,-3679,-1111,-3169,11239,2202,-791,1380,4455 } }, { "Nikon COOLPIX P7100", 0, 0, { 11053,-4269,-1024,-1976,10182,2088,-526,1263,4469 } }, { "Nikon COOLPIX P7700", 200, 0, { 10321,-3920,-931,-2750,11146,1824,-442,1545,5539 } }, { "Nikon 1 V2", 0, 0, { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, { "Nikon 1 J3", 0, 0, { 6588,-1305,-693,-3277,10987,2634,-355,2016,5106 } }, { "Nikon 1 ", 0, 0, { 8994,-2667,-865,-4594,12324,2552,-699,1786,6260 } }, { "Olympus C5050", 0, 0, { 10508,-3124,-1273,-6079,14294,1901,-1653,2306,6237 } }, { "Olympus C5060", 0, 0, { 10445,-3362,-1307,-7662,15690,2058,-1135,1176,7602 } }, { "Olympus C7070", 0, 0, { 10252,-3531,-1095,-7114,14850,2436,-1451,1723,6365 } }, { "Olympus C70", 0, 0, { 10793,-3791,-1146,-7498,15177,2488,-1390,1577,7321 } }, { "Olympus C80", 0, 0, { 8606,-2509,-1014,-8238,15714,2703,-942,979,7760 } }, { "Olympus E-10", 0, 0xffc, { 12745,-4500,-1416,-6062,14542,1580,-1934,2256,6603 } }, { "Olympus E-1", 0, 0, { 11846,-4767,-945,-7027,15878,1089,-2699,4122,8311 } }, { "Olympus E-20", 0, 0xffc, { 13173,-4732,-1499,-5807,14036,1895,-2045,2452,7142 } }, { "Olympus E-300", 0, 0, { 7828,-1761,-348,-5788,14071,1830,-2853,4518,6557 } }, { "Olympus E-330", 0, 0, { 8961,-2473,-1084,-7979,15990,2067,-2319,3035,8249 } }, { "Olympus E-30", 0, 0xfbc, { 8144,-1861,-1111,-7763,15894,1929,-1865,2542,7607 } }, { "Olympus E-3", 0, 0xf99, { 9487,-2875,-1115,-7533,15606,2010,-1618,2100,7389 } }, { "Olympus E-400", 0, 0, { 6169,-1483,-21,-7107,14761,2536,-2904,3580,8568 } }, { "Olympus E-410", 0, 0xf6a, { 8856,-2582,-1026,-7761,15766,2082,-2009,2575,7469 } }, { "Olympus E-420", 0, 0xfd7, { 8746,-2425,-1095,-7594,15612,2073,-1780,2309,7416 } }, { "Olympus E-450", 0, 0xfd2, { 8745,-2425,-1095,-7594,15613,2073,-1780,2309,7416 } }, { "Olympus E-500", 0, 0, { 8136,-1968,-299,-5481,13742,1871,-2556,4205,6630 } }, { "Olympus E-510", 0, 0xf6a, { 8785,-2529,-1033,-7639,15624,2112,-1783,2300,7817 } }, { "Olympus E-520", 0, 0xfd2, { 8344,-2322,-1020,-7596,15635,2048,-1748,2269,7287 } }, { "Olympus E-5", 0, 0xeec, { 11200,-3783,-1325,-4576,12593,2206,-695,1742,7504 } }, { "Olympus E-600", 0, 0xfaf, { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, { "Olympus E-620", 0, 0xfaf, { 8453,-2198,-1092,-7609,15681,2008,-1725,2337,7824 } }, { "Olympus E-P1", 0, 0xffd, { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, { "Olympus E-P2", 0, 0xffd, { 8343,-2050,-1021,-7715,15705,2103,-1831,2380,8235 } }, { "Olympus E-P3", 0, 0, { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, { "Olympus E-PL1s", 0, 0, { 11409,-3872,-1393,-4572,12757,2003,-709,1810,7415 } }, { "Olympus E-PL1", 0, 0, { 11408,-4289,-1215,-4286,12385,2118,-387,1467,7787 } }, { "Olympus E-PL2", 0, 0xcf3, { 15030,-5552,-1806,-3987,12387,1767,-592,1670,7023 } }, { "Olympus E-PL3", 0, 0, { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, { "Olympus E-PL5", 0, 0xfcb, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-PM1", 0, 0, { 7575,-2159,-571,-3722,11341,2725,-1434,2819,6271 } }, { "Olympus E-PM2", 0, 0, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus E-M5", 0, 0xfe1, { 8380,-2630,-639,-2887,10725,2496,-627,1427,5438 } }, { "Olympus SP350", 0, 0, { 12078,-4836,-1069,-6671,14306,2578,-786,939,7418 } }, { "Olympus SP3", 0, 0, { 11766,-4445,-1067,-6901,14421,2707,-1029,1217,7572 } }, { "Olympus SP500UZ", 0, 0xfff, { 9493,-3415,-666,-5211,12334,3260,-1548,2262,6482 } }, { "Olympus SP510UZ", 0, 0xffe, { 10593,-3607,-1010,-5881,13127,3084,-1200,1805,6721 } }, { "Olympus SP550UZ", 0, 0xffe, { 11597,-4006,-1049,-5432,12799,2957,-1029,1750,6516 } }, { "Olympus SP560UZ", 0, 0xff9, { 10915,-3677,-982,-5587,12986,2911,-1168,1968,6223 } }, { "Olympus SP570UZ", 0, 0, { 11522,-4044,-1146,-4736,12172,2904,-988,1829,6039 } }, { "Olympus XZ-10", 0, 0, { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, { "Olympus XZ-1", 0, 0, { 10901,-4095,-1074,-1141,9208,2293,-62,1417,5158 } }, { "Olympus XZ-2", 0, 0, { 9777,-3483,-925,-2886,11297,1800,-602,1663,5134 } }, { "OmniVision ov5647", 0, 0, /* DJC */ { 12782,-4059,-379,-478,9066,1413,1340,1513,5176 } }, { "Pentax *ist DL2", 0, 0, { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, { "Pentax *ist DL", 0, 0, { 10829,-2838,-1115,-8339,15817,2696,-837,680,11939 } }, { "Pentax *ist DS2", 0, 0, { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, { "Pentax *ist DS", 0, 0, { 10371,-2333,-1206,-8688,16231,2602,-1230,1116,11282 } }, { "Pentax *ist D", 0, 0, { 9651,-2059,-1189,-8881,16512,2487,-1460,1345,10687 } }, { "Pentax K10D", 0, 0, { 9566,-2863,-803,-7170,15172,2112,-818,803,9705 } }, { "Pentax K1", 0, 0, { 11095,-3157,-1324,-8377,15834,2720,-1108,947,11688 } }, { "Pentax K20D", 0, 0, { 9427,-2714,-868,-7493,16092,1373,-2199,3264,7180 } }, { "Pentax K200D", 0, 0, { 9186,-2678,-907,-8693,16517,2260,-1129,1094,8524 } }, { "Pentax K2000", 0, 0, { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, { "Pentax K-m", 0, 0, { 11057,-3604,-1155,-5152,13046,2329,-282,375,8104 } }, { "Pentax K-x", 0, 0, { 8843,-2837,-625,-5025,12644,2668,-411,1234,7410 } }, { "Pentax K-r", 0, 0, { 9895,-3077,-850,-5304,13035,2521,-883,1768,6936 } }, { "Pentax K-5 II", 0, 0, { 8170,-2725,-639,-4440,12017,2744,-771,1465,6599 } }, { "Pentax K-5", 0, 0, { 8713,-2833,-743,-4342,11900,2772,-722,1543,6247 } }, { "Pentax K-7", 0, 0, { 9142,-2947,-678,-8648,16967,1663,-2224,2898,8615 } }, { "Pentax 645D", 0, 0x3e00, { 10646,-3593,-1158,-3329,11699,1831,-667,2874,6287 } }, { "Panasonic DMC-FZ8", 0, 0xf7f, { 8986,-2755,-802,-6341,13575,3077,-1476,2144,6379 } }, { "Panasonic DMC-FZ18", 0, 0, { 9932,-3060,-935,-5809,13331,2753,-1267,2155,5575 } }, { "Panasonic DMC-FZ28", 15, 0xf96, { 10109,-3488,-993,-5412,12812,2916,-1305,2140,5543 } }, { "Panasonic DMC-FZ30", 0, 0xf94, { 10976,-4029,-1141,-7918,15491,2600,-1670,2071,8246 } }, { "Panasonic DMC-FZ3", 143, 0, { 9938,-2780,-890,-4604,12393,2480,-1117,2304,4620 } }, { "Panasonic DMC-FZ4", 143, 0, { 13639,-5535,-1371,-1698,9633,2430,316,1152,4108 } }, { "Panasonic DMC-FZ50", 0, 0, { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, { "Leica V-LUX1", 0, 0, { 7906,-2709,-594,-6231,13351,3220,-1922,2631,6537 } }, { "Panasonic DMC-L10", 15, 0xf96, { 8025,-1942,-1050,-7920,15904,2100,-2456,3005,7039 } }, { "Panasonic DMC-L1", 0, 0xf7f, { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, { "Leica DIGILUX 3", 0, 0xf7f, { 8054,-1885,-1025,-8349,16367,2040,-2805,3542,7629 } }, { "Panasonic DMC-LC1", 0, 0, { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, { "Leica DIGILUX 2", 0, 0, { 11340,-4069,-1275,-7555,15266,2448,-2960,3426,7685 } }, { "Panasonic DMC-LX1", 0, 0xf7f, { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, { "Leica D-LUX2", 0, 0xf7f, { 10704,-4187,-1230,-8314,15952,2501,-920,945,8927 } }, { "Panasonic DMC-LX2", 0, 0, { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, { "Leica D-LUX3", 0, 0, { 8048,-2810,-623,-6450,13519,3272,-1700,2146,7049 } }, { "Panasonic DMC-LX3", 15, 0, { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, { "Leica D-LUX 4", 15, 0, { 8128,-2668,-655,-6134,13307,3161,-1782,2568,6083 } }, { "Panasonic DMC-LX5", 143, 0, { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, { "Leica D-LUX 5", 143, 0, { 10909,-4295,-948,-1333,9306,2399,22,1738,4582 } }, { "Panasonic DMC-LX7", 143, 0, { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, { "Leica D-LUX 6", 143, 0, { 10148,-3743,-991,-2837,11366,1659,-701,1893,4899 } }, { "Panasonic DMC-FZ100", 143, 0xfff, { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, { "Leica V-LUX 2", 143, 0xfff, { 16197,-6146,-1761,-2393,10765,1869,366,2238,5248 } }, { "Panasonic DMC-FZ150", 143, 0xfff, { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, { "Leica V-LUX 3", 143, 0xfff, { 11904,-4541,-1189,-2355,10899,1662,-296,1586,4289 } }, { "Panasonic DMC-FZ200", 143, 0xfff, { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, { "Leica V-LUX 4", 143, 0xfff, { 8112,-2563,-740,-3730,11784,2197,-941,2075,4933 } }, { "Panasonic DMC-FX150", 15, 0xfff, { 9082,-2907,-925,-6119,13377,3058,-1797,2641,5609 } }, { "Panasonic DMC-G10", 0, 0, { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } }, { "Panasonic DMC-G1", 15, 0xf94, { 8199,-2065,-1056,-8124,16156,2033,-2458,3022,7220 } }, { "Panasonic DMC-G2", 15, 0xf3c, { 10113,-3400,-1114,-4765,12683,2317,-377,1437,6710 } }, { "Panasonic DMC-G3", 143, 0xfff, { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, { "Panasonic DMC-G5", 143, 0xfff, { 7798,-2562,-740,-3879,11584,2613,-1055,2248,5434 } }, { "Panasonic DMC-G6", 143, 0xfff, /* DJC */ { 6395,-2583,-40,-3677,9109,4569,-1502,2806,6431 } }, { "Panasonic DMC-GF1", 15, 0xf92, { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, { "Panasonic DMC-GF2", 143, 0xfff, { 7888,-1902,-1011,-8106,16085,2099,-2353,2866,7330 } }, { "Panasonic DMC-GF3", 143, 0xfff, { 9051,-2468,-1204,-5212,13276,2121,-1197,2510,6890 } }, { "Panasonic DMC-GF5", 143, 0xfff, { 8228,-2945,-660,-3938,11792,2430,-1094,2278,5793 } }, { "Panasonic DMC-GF6", 143, 0, { 8130,-2801,-946,-3520,11289,2552,-1314,2511,5791 } }, { "Panasonic DMC-GH1", 15, 0xf92, { 6299,-1466,-532,-6535,13852,2969,-2331,3112,5984 } }, { "Panasonic DMC-GH2", 15, 0xf95, { 7780,-2410,-806,-3913,11724,2484,-1018,2390,5298 } }, { "Panasonic DMC-GH3", 144, 0, { 6559,-1752,-491,-3672,11407,2586,-962,1875,5130 } }, { "Panasonic DMC-GX1", 143, 0, { 6763,-1919,-863,-3868,11515,2684,-1216,2387,5879 } }, { "Phase One H 20", 0, 0, /* DJC */ { 1313,1855,-109,-6715,15908,808,-327,1840,6020 } }, { "Phase One H 25", 0, 0, { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, { "Phase One P 2", 0, 0, { 2905,732,-237,-8134,16626,1476,-3038,4253,7517 } }, { "Phase One P 30", 0, 0, { 4516,-245,-37,-7020,14976,2173,-3206,4671,7087 } }, { "Phase One P 45", 0, 0, { 5053,-24,-117,-5684,14076,1702,-2619,4492,5849 } }, { "Phase One P40", 0, 0, { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, { "Phase One P65", 0, 0, { 8035,435,-962,-6001,13872,2320,-1159,3065,5434 } }, { "Red One", 704, 0xffff, /* DJC */ { 21014,-7891,-2613,-3056,12201,856,-2203,5125,8042 } }, { "Samsung EX1", 0, 0x3e00, { 8898,-2498,-994,-3144,11328,2066,-760,1381,4576 } }, { "Samsung EX2F", 0, 0x7ff, { 10648,-3897,-1055,-2022,10573,1668,-492,1611,4742 } }, { "Samsung NX300", 0, 0, { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, { "Samsung NX2000", 0, 0, { 7557,-2522,-739,-4679,12949,1894,-840,1777,5311 } }, { "Samsung NX2", 0, 0xfff, /* NX20, NX200, NX210 */ { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, { "Samsung NX1000", 0, 0, { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, { "Samsung NX1100", 0, 0, { 6933,-2268,-753,-4921,13387,1647,-803,1641,6096 } }, { "Samsung NX", 0, 0, /* NX5, NX10, NX11, NX100 */ { 10332,-3234,-1168,-6111,14639,1520,-1352,2647,8331 } }, { "Samsung WB2000", 0, 0xfff, { 12093,-3557,-1155,-1000,9534,1733,-22,1787,4576 } }, { "Samsung GX-1", 0, 0, { 10504,-2438,-1189,-8603,16207,2531,-1022,863,12242 } }, { "Samsung S85", 0, 0, /* DJC */ { 11885,-3968,-1473,-4214,12299,1916,-835,1655,5549 } }, { "Sinar", 0, 0, /* DJC */ { 16442,-2956,-2422,-2877,12128,750,-1136,6066,4559 } }, { "Sony DSC-F828", 0, 0, { 7924,-1910,-777,-8226,15459,2998,-1517,2199,6818,-7242,11401,3481 } }, { "Sony DSC-R1", 512, 0, { 8512,-2641,-694,-8042,15670,2526,-1821,2117,7414 } }, { "Sony DSC-V3", 0, 0, { 7511,-2571,-692,-7894,15088,3060,-948,1111,8128 } }, { "Sony DSC-RX100", 200, 0, { 8651,-2754,-1057,-3464,12207,1373,-568,1398,4434 } }, { "Sony DSC-RX1", 128, 0, { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, { "Sony DSLR-A100", 0, 0xfeb, { 9437,-2811,-774,-8405,16215,2290,-710,596,7181 } }, { "Sony DSLR-A290", 0, 0, { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, { "Sony DSLR-A2", 0, 0, { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, { "Sony DSLR-A300", 0, 0, { 9847,-3091,-928,-8485,16345,2225,-715,595,7103 } }, { "Sony DSLR-A330", 0, 0, { 9847,-3091,-929,-8485,16346,2225,-714,595,7103 } }, { "Sony DSLR-A350", 0, 0xffc, { 6038,-1484,-578,-9146,16746,2513,-875,746,7217 } }, { "Sony DSLR-A380", 0, 0, { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, { "Sony DSLR-A390", 0, 0, { 6038,-1484,-579,-9145,16746,2512,-875,746,7218 } }, { "Sony DSLR-A450", 128, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, { "Sony DSLR-A580", 128, 0xfeb, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, { "Sony DSLR-A5", 128, 0xfeb, { 4950,-580,-103,-5228,12542,3029,-709,1435,7371 } }, { "Sony DSLR-A700", 126, 0, { 5775,-805,-359,-8574,16295,2391,-1943,2341,7249 } }, { "Sony DSLR-A850", 128, 0, { 5413,-1162,-365,-5665,13098,2866,-608,1179,8440 } }, { "Sony DSLR-A900", 128, 0, { 5209,-1072,-397,-8845,16120,2919,-1618,1803,8654 } }, { "Sony NEX-5N", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony NEX-5R", 128, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-3N", 128, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-3", 138, 0, /* DJC */ { 6907,-1256,-645,-4940,12621,2320,-1710,2581,6230 } }, { "Sony NEX-5", 116, 0, /* DJC */ { 6807,-1350,-342,-4216,11649,2567,-1089,2001,6420 } }, { "Sony NEX-3", 128, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, { "Sony NEX-5", 128, 0, /* Adobe */ { 6549,-1550,-436,-4880,12435,2753,-854,1868,6976 } }, { "Sony NEX-6", 128, 0, { 6129,-1545,-418,-4930,12490,2743,-977,1693,6615 } }, { "Sony NEX-7", 128, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, { "Sony NEX", 128, 0, /* NEX-C3, NEX-F3 */ { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony SLT-A33", 128, 0, { 6069,-1221,-366,-5221,12779,2734,-1024,2066,6834 } }, { "Sony SLT-A35", 128, 0, { 5986,-1618,-415,-4557,11820,3120,-681,1404,6971 } }, { "Sony SLT-A37", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony SLT-A55", 128, 0, { 5932,-1492,-411,-4813,12285,2856,-741,1524,6739 } }, { "Sony SLT-A57", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony SLT-A58", 128, 0, { 5991,-1456,-455,-4764,12135,2980,-707,1425,6701 } }, { "Sony SLT-A65", 128, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, { "Sony SLT-A77", 128, 0, { 5491,-1192,-363,-4951,12342,2948,-911,1722,7192 } }, { "Sony SLT-A99", 128, 0, { 6344,-1612,-462,-4863,12477,2681,-865,1786,6899 } }, }; double cam_xyz[4][3]; char name[130]; int i, j; sprintf (name, "%s %s", make, model); for (i=0; i < sizeof table / sizeof *table; i++) if (!strncmp (name, table[i].prefix, strlen(table[i].prefix))) { if (table[i].black) black = (ushort) table[i].black; if (table[i].maximum) maximum = (ushort) table[i].maximum; if (table[i].trans[0]) { for (j=0; j < 12; j++) cam_xyz[0][j] = table[i].trans[j] / 10000.0; cam_xyz_coeff (cam_xyz); } break; } } void CLASS simple_coeff (int index) { static const float table[][12] = { /* index 0 -- all Foveon cameras */ { 1.4032,-0.2231,-0.1016,-0.5263,1.4816,0.017,-0.0112,0.0183,0.9113 }, /* index 1 -- Kodak DC20 and DC25 */ { 2.25,0.75,-1.75,-0.25,-0.25,0.75,0.75,-0.25,-0.25,-1.75,0.75,2.25 }, /* index 2 -- Logitech Fotoman Pixtura */ { 1.893,-0.418,-0.476,-0.495,1.773,-0.278,-1.017,-0.655,2.672 }, /* index 3 -- Nikon E880, E900, and E990 */ { -1.936280, 1.800443, -1.448486, 2.584324, 1.405365, -0.524955, -0.289090, 0.408680, -1.204965, 1.082304, 2.941367, -1.818705 } }; int i, c; for (raw_color = i=0; i < 3; i++) FORCC rgb_cam[i][c] = table[index][i*colors+c]; } short CLASS guess_byte_order (int words) { uchar test[4][2]; int t=2, msb; double diff, sum[2] = {0,0}; fread (test[0], 2, 2, ifp); for (words-=2; words--; ) { fread (test[t], 2, 1, ifp); for (msb=0; msb < 2; msb++) { diff = (test[t^2][msb] << 8 | test[t^2][!msb]) - (test[t ][msb] << 8 | test[t ][!msb]); sum[msb] += diff*diff; } t = (t+1) & 3; } return sum[0] < sum[1] ? 0x4d4d : 0x4949; } float CLASS find_green (int bps, int bite, int off0, int off1) { UINT64 bitbuf=0; int vbits, col, i, c; ushort img[2][2064]; double sum[]={0,0}; FORC(2) { fseek (ifp, c ? off1:off0, SEEK_SET); for (vbits=col=0; col < width; col++) { for (vbits -= bps; vbits < 0; vbits += bite) { bitbuf <<= bite; for (i=0; i < bite; i+=8) bitbuf |= (unsigned) (fgetc(ifp) << i); } img[c][col] = bitbuf << (64-bps-vbits) >> (64-bps); } } FORC(width-1) { sum[ c & 1] += ABS(img[0][c]-img[1][c+1]); sum[~c & 1] += ABS(img[1][c]-img[0][c+1]); } return 100 * log(sum[0]/sum[1]); } /* Identify which camera created this file, and set global variables accordingly. */ void CLASS identify() { static const short pana[][6] = { { 3130, 1743, 4, 0, -6, 0 }, { 3130, 2055, 4, 0, -6, 0 }, { 3130, 2319, 4, 0, -6, 0 }, { 3170, 2103, 18, 0,-42, 20 }, { 3170, 2367, 18, 13,-42,-21 }, { 3177, 2367, 0, 0, -1, 0 }, { 3304, 2458, 0, 0, -1, 0 }, { 3330, 2463, 9, 0, -5, 0 }, { 3330, 2479, 9, 0,-17, 4 }, { 3370, 1899, 15, 0,-44, 20 }, { 3370, 2235, 15, 0,-44, 20 }, { 3370, 2511, 15, 10,-44,-21 }, { 3690, 2751, 3, 0, -8, -3 }, { 3710, 2751, 0, 0, -3, 0 }, { 3724, 2450, 0, 0, 0, -2 }, { 3770, 2487, 17, 0,-44, 19 }, { 3770, 2799, 17, 15,-44,-19 }, { 3880, 2170, 6, 0, -6, 0 }, { 4060, 3018, 0, 0, 0, -2 }, { 4290, 2391, 3, 0, -8, -1 }, { 4330, 2439, 17, 15,-44,-19 }, { 4508, 2962, 0, 0, -3, -4 }, { 4508, 3330, 0, 0, -3, -6 }, }; static const ushort canon[][6] = { { 1944, 1416, 0, 0, 48, 0 }, { 2144, 1560, 4, 8, 52, 2 }, { 2224, 1456, 48, 6, 0, 2 }, { 2376, 1728, 12, 6, 52, 2 }, { 2672, 1968, 12, 6, 44, 2 }, { 3152, 2068, 64, 12, 0, 0 }, { 3160, 2344, 44, 12, 4, 4 }, { 3344, 2484, 4, 6, 52, 6 }, { 3516, 2328, 42, 14, 0, 0 }, { 3596, 2360, 74, 12, 0, 0 }, { 3744, 2784, 52, 12, 8, 12 }, { 3944, 2622, 30, 18, 6, 2 }, { 3948, 2622, 42, 18, 0, 2 }, { 3984, 2622, 76, 20, 0, 2 }, { 4104, 3048, 48, 12, 24, 12 }, { 4116, 2178, 4, 2, 0, 0 }, { 4152, 2772, 192, 12, 0, 0 }, { 4160, 3124, 104, 11, 8, 65 }, { 4176, 3062, 96, 17, 8, 0 }, { 4312, 2876, 22, 18, 0, 2 }, { 4352, 2874, 62, 18, 0, 0 }, { 4476, 2954, 90, 34, 0, 0 }, { 4480, 3348, 12, 10, 36, 12 }, { 4496, 3366, 80, 50, 12, 0 }, { 4832, 3204, 62, 26, 0, 0 }, { 4832, 3228, 62, 51, 0, 0 }, { 5108, 3349, 98, 13, 0, 0 }, { 5120, 3318, 142, 45, 62, 0 }, { 5280, 3528, 72, 52, 0, 0 }, { 5344, 3516, 142, 51, 0, 0 }, { 5344, 3584, 126,100, 0, 2 }, { 5360, 3516, 158, 51, 0, 0 }, { 5568, 3708, 72, 38, 0, 0 }, { 5712, 3774, 62, 20, 10, 2 }, { 5792, 3804, 158, 51, 0, 0 }, { 5920, 3950, 122, 80, 2, 0 }, }; static const struct { ushort id; char model[20]; } unique[] = { { 0x168, "EOS 10D" }, { 0x001, "EOS-1D" }, { 0x175, "EOS 20D" }, { 0x174, "EOS-1D Mark II" }, { 0x234, "EOS 30D" }, { 0x232, "EOS-1D Mark II N" }, { 0x190, "EOS 40D" }, { 0x169, "EOS-1D Mark III" }, { 0x261, "EOS 50D" }, { 0x281, "EOS-1D Mark IV" }, { 0x287, "EOS 60D" }, { 0x167, "EOS-1DS" }, { 0x170, "EOS 300D" }, { 0x188, "EOS-1Ds Mark II" }, { 0x176, "EOS 450D" }, { 0x215, "EOS-1Ds Mark III" }, { 0x189, "EOS 350D" }, { 0x324, "EOS-1D C" }, { 0x236, "EOS 400D" }, { 0x269, "EOS-1D X" }, { 0x252, "EOS 500D" }, { 0x213, "EOS 5D" }, { 0x270, "EOS 550D" }, { 0x218, "EOS 5D Mark II" }, { 0x286, "EOS 600D" }, { 0x285, "EOS 5D Mark III" }, { 0x301, "EOS 650D" }, { 0x302, "EOS 6D" }, { 0x326, "EOS 700D" }, { 0x250, "EOS 7D" }, { 0x254, "EOS 1000D" }, { 0x288, "EOS 1100D" }, { 0x346, "EOS 100D" }, }; static const struct { unsigned fsize; ushort rw, rh; uchar lm, tm, rm, bm, lf, cf, max, flags; char make[10], model[20]; ushort offset; } table[] = { { 786432,1024, 768, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-080C" }, { 1447680,1392,1040, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-145C" }, { 1920000,1600,1200, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-201C" }, { 5067304,2588,1958, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-510C" }, { 5067316,2588,1958, 0, 0, 0, 0, 0,0x94,0,0,"AVT","F-510C",12 }, { 10134608,2588,1958, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-510C" }, { 10134620,2588,1958, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-510C",12 }, { 16157136,3272,2469, 0, 0, 0, 0, 9,0x94,0,0,"AVT","F-810C" }, { 15980544,3264,2448, 0, 0, 0, 0, 8,0x61,0,1,"AgfaPhoto","DC-833m" }, { 2868726,1384,1036, 0, 0, 0, 0,64,0x49,0,8,"Baumer","TXG14",1078 }, { 5298000,2400,1766,12,12,44, 2,40,0x94,0,2,"Canon","PowerShot SD300" }, { 6553440,2664,1968, 4, 4,44, 4,40,0x94,0,2,"Canon","PowerShot A460" }, { 6573120,2672,1968,12, 8,44, 0,40,0x94,0,2,"Canon","PowerShot A610" }, { 6653280,2672,1992,10, 6,42, 2,40,0x94,0,2,"Canon","PowerShot A530" }, { 7710960,2888,2136,44, 8, 4, 0,40,0x94,0,2,"Canon","PowerShot S3 IS" }, { 9219600,3152,2340,36,12, 4, 0,40,0x94,0,2,"Canon","PowerShot A620" }, { 9243240,3152,2346,12, 7,44,13,40,0x49,0,2,"Canon","PowerShot A470" }, { 10341600,3336,2480, 6, 5,32, 3,40,0x94,0,2,"Canon","PowerShot A720 IS" }, { 10383120,3344,2484,12, 6,44, 6,40,0x94,0,2,"Canon","PowerShot A630" }, { 12945240,3736,2772,12, 6,52, 6,40,0x94,0,2,"Canon","PowerShot A640" }, { 15636240,4104,3048,48,12,24,12,40,0x94,0,2,"Canon","PowerShot A650" }, { 15467760,3720,2772, 6,12,30, 0,40,0x94,0,2,"Canon","PowerShot SX110 IS" }, { 15534576,3728,2778,12, 9,44, 9,40,0x94,0,2,"Canon","PowerShot SX120 IS" }, { 18653760,4080,3048,24,12,24,12,40,0x94,0,2,"Canon","PowerShot SX20 IS" }, { 19131120,4168,3060,92,16, 4, 1, 8,0x94,0,2,"Canon","PowerShot SX220 HS" }, { 21936096,4464,3276,25,10,73,12,40,0x16,0,2,"Canon","PowerShot SX30 IS" }, { 24724224,4704,3504, 8,16,56, 8,40,0x94,0,2,"Canon","PowerShot A3300 IS" }, { 1976352,1632,1211, 0, 2, 0, 1, 0,0x94,0,1,"Casio","QV-2000UX" }, { 3217760,2080,1547, 0, 0,10, 1, 0,0x94,0,1,"Casio","QV-3*00EX" }, { 6218368,2585,1924, 0, 0, 9, 0, 0,0x94,0,1,"Casio","QV-5700" }, { 7816704,2867,2181, 0, 0,34,36, 0,0x16,0,1,"Casio","EX-Z60" }, { 2937856,1621,1208, 0, 0, 1, 0, 0,0x94,7,13,"Casio","EX-S20" }, { 4948608,2090,1578, 0, 0,32,34, 0,0x94,7,1,"Casio","EX-S100" }, { 6054400,2346,1720, 2, 0,32, 0, 0,0x94,7,1,"Casio","QV-R41" }, { 7426656,2568,1928, 0, 0, 0, 0, 0,0x94,0,1,"Casio","EX-P505" }, { 7530816,2602,1929, 0, 0,22, 0, 0,0x94,7,1,"Casio","QV-R51" }, { 7542528,2602,1932, 0, 0,32, 0, 0,0x94,7,1,"Casio","EX-Z50" }, { 7562048,2602,1937, 0, 0,25, 0, 0,0x16,7,1,"Casio","EX-Z500" }, { 7753344,2602,1986, 0, 0,32,26, 0,0x94,7,1,"Casio","EX-Z55" }, { 9313536,2858,2172, 0, 0,14,30, 0,0x94,7,1,"Casio","EX-P600" }, { 10834368,3114,2319, 0, 0,27, 0, 0,0x94,0,1,"Casio","EX-Z750" }, { 10843712,3114,2321, 0, 0,25, 0, 0,0x94,0,1,"Casio","EX-Z75" }, { 10979200,3114,2350, 0, 0,32,32, 0,0x94,7,1,"Casio","EX-P700" }, { 12310144,3285,2498, 0, 0, 6,30, 0,0x94,0,1,"Casio","EX-Z850" }, { 12489984,3328,2502, 0, 0,47,35, 0,0x94,0,1,"Casio","EX-Z8" }, { 15499264,3754,2752, 0, 0,82, 0, 0,0x94,0,1,"Casio","EX-Z1050" }, { 18702336,4096,3044, 0, 0,24, 0,80,0x94,7,1,"Casio","EX-ZR100" }, { 7684000,2260,1700, 0, 0, 0, 0,13,0x94,0,1,"Casio","QV-4000" }, { 787456,1024, 769, 0, 1, 0, 0, 0,0x49,0,0,"Creative","PC-CAM 600" }, { 3840000,1600,1200, 0, 0, 0, 0,65,0x49,0,0,"Foculus","531C" }, { 307200, 640, 480, 0, 0, 0, 0, 0,0x94,0,0,"Generic","640x480" }, { 62464, 256, 244, 1, 1, 6, 1, 0,0x8d,0,0,"Kodak","DC20" }, { 124928, 512, 244, 1, 1,10, 1, 0,0x8d,0,0,"Kodak","DC20" }, { 1652736,1536,1076, 0,52, 0, 0, 0,0x61,0,0,"Kodak","DCS200" }, { 4159302,2338,1779, 1,33, 1, 2, 0,0x94,0,0,"Kodak","C330" }, { 4162462,2338,1779, 1,33, 1, 2, 0,0x94,0,0,"Kodak","C330",3160 }, { 6163328,2864,2152, 0, 0, 0, 0, 0,0x94,0,0,"Kodak","C603" }, { 6166488,2864,2152, 0, 0, 0, 0, 0,0x94,0,0,"Kodak","C603",3160 }, { 460800, 640, 480, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","C603" }, { 9116448,2848,2134, 0, 0, 0, 0, 0,0x00,0,0,"Kodak","C603" }, { 614400, 640, 480, 0, 3, 0, 0,64,0x94,0,0,"Kodak","KAI-0340" }, { 3884928,1608,1207, 0, 0, 0, 0,96,0x16,0,0,"Micron","2010",3212 }, { 1138688,1534, 986, 0, 0, 0, 0, 0,0x61,0,0,"Minolta","RD175",513 }, { 1581060,1305, 969, 0, 0,18, 6, 6,0x1e,4,1,"Nikon","E900" }, { 2465792,1638,1204, 0, 0,22, 1, 6,0x4b,5,1,"Nikon","E950" }, { 2940928,1616,1213, 0, 0, 0, 7,30,0x94,0,1,"Nikon","E2100" }, { 4771840,2064,1541, 0, 0, 0, 1, 6,0xe1,0,1,"Nikon","E990" }, { 4775936,2064,1542, 0, 0, 0, 0,30,0x94,0,1,"Nikon","E3700" }, { 5865472,2288,1709, 0, 0, 0, 1, 6,0xb4,0,1,"Nikon","E4500" }, { 5869568,2288,1710, 0, 0, 0, 0, 6,0x16,0,1,"Nikon","E4300" }, { 7438336,2576,1925, 0, 0, 0, 1, 6,0xb4,0,1,"Nikon","E5000" }, { 8998912,2832,2118, 0, 0, 0, 0,30,0x94,7,1,"Nikon","COOLPIX S6" }, { 5939200,2304,1718, 0, 0, 0, 0,30,0x16,0,0,"Olympus","C770UZ" }, { 3178560,2064,1540, 0, 0, 0, 0, 0,0x94,0,1,"Pentax","Optio S" }, { 4841984,2090,1544, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S" }, { 6114240,2346,1737, 0, 0,22, 0, 0,0x94,7,1,"Pentax","Optio S4" }, { 10702848,3072,2322, 0, 0, 0,21,30,0x94,0,1,"Pentax","Optio 750Z" }, { 13248000,2208,3000, 0, 0, 0, 0,13,0x61,0,0,"Pixelink","A782" }, { 6291456,2048,1536, 0, 0, 0, 0,96,0x61,0,0,"RoverShot","3320AF" }, { 311696, 644, 484, 0, 0, 0, 0, 0,0x16,0,8,"ST Micro","STV680 VGA" }, { 16098048,3288,2448, 0, 0,24, 0, 9,0x94,0,1,"Samsung","S85" }, { 16215552,3312,2448, 0, 0,48, 0, 9,0x94,0,1,"Samsung","S85" }, { 20487168,3648,2808, 0, 0, 0, 0,13,0x94,5,1,"Samsung","WB550" }, { 24000000,4000,3000, 0, 0, 0, 0,13,0x94,5,1,"Samsung","WB550" }, { 12582980,3072,2048, 0, 0, 0, 0,33,0x61,0,0,"Sinar","3072x2048",68 }, { 33292868,4080,4080, 0, 0, 0, 0,33,0x61,0,0,"Sinar","4080x4080",68 }, { 44390468,4080,5440, 0, 0, 0, 0,33,0x61,0,0,"Sinar","4080x5440",68 }, { 1409024,1376,1024, 0, 0, 1, 0, 0,0x49,0,0,"Sony","XCD-SX910CR" }, { 2818048,1376,1024, 0, 0, 1, 0,97,0x49,0,0,"Sony","XCD-SX910CR" }, }; static const char *corp[] = { "AgfaPhoto", "Canon", "Casio", "Epson", "Fujifilm", "Mamiya", "Minolta", "Motorola", "Kodak", "Konica", "Leica", "Nikon", "Nokia", "Olympus", "Pentax", "Phase One", "Ricoh", "Samsung", "Sigma", "Sinar", "Sony" }; char head[32], *cp; int hlen, flen, fsize, zero_fsize=1, i, c; struct jhead jh; tiff_flip = flip = filters = UINT_MAX; /* unknown */ raw_height = raw_width = fuji_width = fuji_layout = cr2_slice[0] = 0; maximum = height = width = top_margin = left_margin = 0; cdesc[0] = desc[0] = artist[0] = make[0] = model[0] = model2[0] = 0; iso_speed = shutter = aperture = focal_len = unique_id = 0; tiff_nifds = 0; memset (tiff_ifd, 0, sizeof tiff_ifd); memset (gpsdata, 0, sizeof gpsdata); memset (cblack, 0, sizeof cblack); memset (white, 0, sizeof white); memset (mask, 0, sizeof mask); thumb_offset = thumb_length = thumb_width = thumb_height = 0; load_raw = thumb_load_raw = 0; write_thumb = &CLASS jpeg_thumb; data_offset = meta_length = tiff_bps = tiff_compress = 0; kodak_cbpp = zero_after_ff = dng_version = load_flags = 0; timestamp = shot_order = tiff_samples = black = is_foveon = 0; mix_green = profile_length = data_error = zero_is_bad = 0; pixel_aspect = is_raw = raw_color = 1; tile_width = tile_length = 0; for (i=0; i < 4; i++) { cam_mul[i] = i == 1; pre_mul[i] = i < 3; FORC3 cmatrix[c][i] = 0; FORC3 rgb_cam[c][i] = c == i; } colors = 3; for (i=0; i < 0x10000; i++) curve[i] = i; order = get2(); hlen = get4(); fseek (ifp, 0, SEEK_SET); fread (head, 1, 32, ifp); fseek (ifp, 0, SEEK_END); flen = fsize = ftell(ifp); if ((cp = (char *) memmem (head, 32, "MMMM", 4)) || (cp = (char *) memmem (head, 32, "IIII", 4))) { parse_phase_one (cp-head); if (cp-head && parse_tiff(0)) apply_tiff(); } else if (order == 0x4949 || order == 0x4d4d) { if (!memcmp (head+6,"HEAPCCDR",8)) { data_offset = hlen; parse_ciff (hlen, flen-hlen, 0); load_raw = &CLASS canon_load_raw; } else if (parse_tiff(0)) apply_tiff(); } else if (!memcmp (head,"\xff\xd8\xff\xe1",4) && !memcmp (head+6,"Exif",4)) { fseek (ifp, 4, SEEK_SET); data_offset = 4 + get2(); fseek (ifp, data_offset, SEEK_SET); if (fgetc(ifp) != 0xff) parse_tiff(12); thumb_offset = 0; } else if (!memcmp (head+25,"ARECOYK",7)) { strcpy (make, "Contax"); strcpy (model,"N Digital"); fseek (ifp, 33, SEEK_SET); get_timestamp(1); fseek (ifp, 60, SEEK_SET); FORC4 cam_mul[c ^ (c >> 1)] = get4(); } else if (!strcmp (head, "PXN")) { strcpy (make, "Logitech"); strcpy (model,"Fotoman Pixtura"); } else if (!strcmp (head, "qktk")) { strcpy (make, "Apple"); strcpy (model,"QuickTake 100"); load_raw = &CLASS quicktake_100_load_raw; } else if (!strcmp (head, "qktn")) { strcpy (make, "Apple"); strcpy (model,"QuickTake 150"); load_raw = &CLASS kodak_radc_load_raw; } else if (!memcmp (head,"FUJIFILM",8)) { fseek (ifp, 84, SEEK_SET); thumb_offset = get4(); thumb_length = get4(); fseek (ifp, 92, SEEK_SET); parse_fuji (get4()); if (thumb_offset > 120) { fseek (ifp, 120, SEEK_SET); is_raw += (i = get4()) && 1; if (is_raw == 2 && shot_select) parse_fuji (i); } load_raw = &CLASS unpacked_load_raw; fseek (ifp, 100+28*(shot_select > 0), SEEK_SET); parse_tiff (data_offset = get4()); parse_tiff (thumb_offset+12); apply_tiff(); } else if (!memcmp (head,"RIFF",4)) { fseek (ifp, 0, SEEK_SET); parse_riff(); } else if (!memcmp (head,"\0\001\0\001\0@",6)) { fseek (ifp, 6, SEEK_SET); fread (make, 1, 8, ifp); fread (model, 1, 8, ifp); fread (model2, 1, 16, ifp); data_offset = get2(); get2(); raw_width = get2(); raw_height = get2(); load_raw = &CLASS nokia_load_raw; filters = 0x61616161; } else if (!memcmp (head,"NOKIARAW",8)) { strcpy (make, "NOKIA"); strcpy (model, "X2"); order = 0x4949; fseek (ifp, 300, SEEK_SET); data_offset = get4(); i = get4(); width = get2(); height = get2(); data_offset += i - width * 5 / 4 * height; load_raw = &CLASS nokia_load_raw; filters = 0x61616161; } else if (!memcmp (head,"ARRI",4)) { order = 0x4949; fseek (ifp, 20, SEEK_SET); width = get4(); height = get4(); strcpy (make, "ARRI"); fseek (ifp, 668, SEEK_SET); fread (model, 1, 64, ifp); data_offset = 4096; load_raw = &CLASS packed_load_raw; load_flags = 88; filters = 0x61616161; } else if (!memcmp (head,"XPDS",4)) { order = 0x4949; fseek (ifp, 0x800, SEEK_SET); fread (make, 1, 41, ifp); raw_height = get2(); raw_width = get2(); fseek (ifp, 56, SEEK_CUR); fread (model, 1, 30, ifp); data_offset = 0x10000; load_raw = &CLASS canon_rmf_load_raw; } else if (!memcmp (head+4,"RED1",4)) { strcpy (make, "Red"); strcpy (model,"One"); parse_redcine(); load_raw = &CLASS redcine_load_raw; gamma_curve (1/2.4, 12.92, 1, 4095); filters = 0x49494949; } else if (!memcmp (head,"DSC-Image",9)) parse_rollei(); else if (!memcmp (head,"PWAD",4)) parse_sinar_ia(); else if (!memcmp (head,"\0MRM",4)) parse_minolta(0); else if (!memcmp (head,"FOVb",4)) parse_foveon(); else if (!memcmp (head,"CI",2)) parse_cine(); else for (zero_fsize=i=0; i < sizeof table / sizeof *table; i++) if (fsize == table[i].fsize) { strcpy (make, table[i].make ); strcpy (model, table[i].model); flip = table[i].flags >> 2; zero_is_bad = table[i].flags & 2; if (table[i].flags & 1) parse_external_jpeg(); data_offset = table[i].offset; raw_width = table[i].rw; raw_height = table[i].rh; left_margin = table[i].lm; top_margin = table[i].tm; width = raw_width - left_margin - table[i].rm; height = raw_height - top_margin - table[i].bm; filters = 0x1010101 * table[i].cf; colors = 4 - !((filters & filters >> 1) & 0x5555); load_flags = table[i].lf; switch (tiff_bps = (fsize-data_offset)*8 / (raw_width*raw_height)) { case 6: load_raw = &CLASS minolta_rd175_load_raw; break; case 8: load_raw = &CLASS eight_bit_load_raw; break; case 10: case 12: load_flags |= 128; load_raw = &CLASS packed_load_raw; break; case 16: order = 0x4949 | 0x404 * (load_flags & 1); tiff_bps -= load_flags >> 4; tiff_bps -= load_flags = load_flags >> 1 & 7; load_raw = &CLASS unpacked_load_raw; } maximum = (1 << tiff_bps) - (1 << table[i].max); } if (zero_fsize) fsize = 0; if (make[0] == 0) parse_smal (0, flen); if (make[0] == 0) { parse_jpeg(0); if (!strncmp(model,"ov",2) && !fseek (ifp, -6404096, SEEK_END) && fread (head, 1, 32, ifp) && !strcmp(head,"BRCMn")) { strcpy (make, "OmniVision"); data_offset = ftell(ifp) + 0x8000-32; width = raw_width; raw_width = 2611; load_raw = &CLASS nokia_load_raw; filters = 0x16161616; } else is_raw = 0; } for (i=0; i < sizeof corp / sizeof *corp; i++) if (strcasestr (make, corp[i])) /* Simplify company names */ strcpy (make, corp[i]); if ((!strcmp(make,"Kodak") || !strcmp(make,"Leica")) && ((cp = strcasestr(model," DIGITAL CAMERA")) || (cp = strstr(model,"FILE VERSION")))) *cp = 0; cp = make + strlen(make); /* Remove trailing spaces */ while (*--cp == ' ') *cp = 0; cp = model + strlen(model); while (*--cp == ' ') *cp = 0; i = strlen(make); /* Remove make from model */ if (!strncasecmp (model, make, i) && model[i++] == ' ') memmove (model, model+i, 64-i); if (!strncmp (model,"FinePix ",8)) strcpy (model, model+8); if (!strncmp (model,"Digital Camera ",15)) strcpy (model, model+15); desc[511] = artist[63] = make[63] = model[63] = model2[63] = 0; if (!is_raw) goto notraw; if (!height) height = raw_height; if (!width) width = raw_width; if (height == 2624 && width == 3936) /* Pentax K10D and Samsung GX10 */ { height = 2616; width = 3896; } if (height == 3136 && width == 4864) /* Pentax K20D and Samsung GX20 */ { height = 3124; width = 4688; filters = 0x16161616; } if (width == 4352 && (!strcmp(model,"K-r") || !strcmp(model,"K-x"))) { width = 4309; filters = 0x16161616; } if (width >= 4960 && !strncmp(model,"K-5",3)) { left_margin = 10; width = 4950; filters = 0x16161616; } if (width == 4736 && !strcmp(model,"K-7")) { height = 3122; width = 4684; filters = 0x16161616; top_margin = 2; } if (width == 7424 && !strcmp(model,"645D")) { height = 5502; width = 7328; filters = 0x61616161; top_margin = 29; left_margin = 48; } if (height == 3014 && width == 4096) /* Ricoh GX200 */ width = 4014; if (dng_version) { if (filters == UINT_MAX) filters = 0; if (filters) is_raw = tiff_samples; else colors = tiff_samples; switch (tiff_compress) { case 1: load_raw = &CLASS packed_dng_load_raw; break; case 7: load_raw = &CLASS lossless_dng_load_raw; break; case 34892: load_raw = &CLASS lossy_dng_load_raw; break; default: load_raw = 0; } goto dng_skip; } if (!strcmp(make,"Canon") && !fsize && tiff_bps != 15) { if (!load_raw) load_raw = &CLASS lossless_jpeg_load_raw; for (i=0; i < sizeof canon / sizeof *canon; i++) if (raw_width == canon[i][0] && raw_height == canon[i][1]) { width = raw_width - (left_margin = canon[i][2]); height = raw_height - (top_margin = canon[i][3]); width -= canon[i][4]; height -= canon[i][5]; } if ((unique_id | 0x20000) == 0x2720000) { left_margin = 8; top_margin = 16; } } for (i=0; i < sizeof unique / sizeof *unique; i++) if (unique_id == 0x80000000 + unique[i].id) adobe_coeff ("Canon", unique[i].model); if (!strcmp(make,"Nikon")) { if (!load_raw) load_raw = &CLASS packed_load_raw; if (model[0] == 'E') load_flags |= !data_offset << 2 | 2; } /* Set parameters based on camera name (for non-DNG files). */ if (!strcmp(model,"KAI-0340") && find_green (16, 16, 3840, 5120) < 25) { height = 480; top_margin = filters = 0; strcpy (model,"C603"); } if (is_foveon) { if (height*2 < width) pixel_aspect = 0.5; if (height > width) pixel_aspect = 2; filters = 0; simple_coeff(0); } else if (!strcmp(make,"Canon") && tiff_bps == 15) { switch (width) { case 3344: width -= 66; case 3872: width -= 6; } if (height > width) SWAP(height,width); filters = 0; tiff_samples = colors = 3; load_raw = &CLASS canon_sraw_load_raw; } else if (!strcmp(model,"PowerShot 600")) { height = 613; width = 854; raw_width = 896; colors = 4; filters = 0xe1e4e1e4; load_raw = &CLASS canon_600_load_raw; } else if (!strcmp(model,"PowerShot A5") || !strcmp(model,"PowerShot A5 Zoom")) { height = 773; width = 960; raw_width = 992; pixel_aspect = 256/235.0; filters = 0x1e4e1e4e; goto canon_a5; } else if (!strcmp(model,"PowerShot A50")) { height = 968; width = 1290; raw_width = 1320; filters = 0x1b4e4b1e; goto canon_a5; } else if (!strcmp(model,"PowerShot Pro70")) { height = 1024; width = 1552; filters = 0x1e4b4e1b; canon_a5: colors = 4; tiff_bps = 10; load_raw = &CLASS packed_load_raw; load_flags = 40; } else if (!strcmp(model,"PowerShot Pro90 IS") || !strcmp(model,"PowerShot G1")) { colors = 4; filters = 0xb4b4b4b4; } else if (!strcmp(model,"PowerShot A610")) { if (canon_s2is()) strcpy (model+10, "S2 IS"); } else if (!strcmp(model,"PowerShot SX220 HS")) { mask[0][0] = top_margin = 16; mask[0][2] = top_margin + height; mask[0][3] = left_margin = 92; } else if (!strcmp(model,"PowerShot SX50 HS")) { mask[0][0] = top_margin = 17; mask[0][2] = raw_height; mask[0][3] = 80; filters = 0x49494949; } else if (!strcmp(model,"PowerShot G10")) { filters = 0x49494949; } else if (!strcmp(model,"EOS D2000C")) { filters = 0x61616161; black = curve[200]; } else if (!strcmp(model,"D1")) { cam_mul[0] *= 256/527.0; cam_mul[2] *= 256/317.0; } else if (!strcmp(model,"D1X")) { width -= 4; pixel_aspect = 0.5; } else if (!strcmp(model,"D40X") || !strcmp(model,"D60") || !strcmp(model,"D80") || !strcmp(model,"D3000")) { height -= 3; width -= 4; } else if (!strcmp(model,"D3") || !strcmp(model,"D3S") || !strcmp(model,"D700")) { width -= 4; left_margin = 2; } else if (!strcmp(model,"D3100")) { width -= 28; left_margin = 6; } else if (!strcmp(model,"D5000") || !strcmp(model,"D90")) { width -= 42; } else if (!strcmp(model,"D5100") || !strcmp(model,"D7000") || !strcmp(model,"COOLPIX A")) { width -= 44; } else if (!strcmp(model,"D3200") || !strcmp(model,"D600") || !strncmp(model,"D800",4)) { width -= 46; } else if (!strcmp(model,"D4")) { width -= 52; left_margin = 2; } else if (!strncmp(model,"D40",3) || !strncmp(model,"D50",3) || !strncmp(model,"D70",3)) { width--; } else if (!strcmp(model,"D100")) { if (load_flags) raw_width = (width += 3) + 3; } else if (!strcmp(model,"D200")) { left_margin = 1; width -= 4; filters = 0x94949494; } else if (!strncmp(model,"D2H",3)) { left_margin = 6; width -= 14; } else if (!strncmp(model,"D2X",3)) { if (width == 3264) width -= 32; else width -= 8; } else if (!strncmp(model,"D300",4)) { width -= 32; } else if (!strcmp(make,"Nikon") && raw_width == 4032) { adobe_coeff ("Nikon","COOLPIX P7700"); } else if (!strncmp(model,"COOLPIX P",9)) { load_flags = 24; filters = 0x94949494; if (model[9] == '7' && iso_speed >= 400) black = 255; } else if (!strncmp(model,"1 ",2)) { height -= 2; } else if (fsize == 1581060) { simple_coeff(3); pre_mul[0] = 1.2085; pre_mul[1] = 1.0943; pre_mul[3] = 1.1103; } else if (fsize == 3178560) { cam_mul[0] *= 4; cam_mul[2] *= 4; } else if (fsize == 4771840) { if (!timestamp && nikon_e995()) strcpy (model, "E995"); if (strcmp(model,"E995")) { filters = 0xb4b4b4b4; simple_coeff(3); pre_mul[0] = 1.196; pre_mul[1] = 1.246; pre_mul[2] = 1.018; } } else if (fsize == 2940928) { if (!timestamp && !nikon_e2100()) strcpy (model,"E2500"); if (!strcmp(model,"E2500")) { height -= 2; load_flags = 6; colors = 4; filters = 0x4b4b4b4b; } } else if (fsize == 4775936) { if (!timestamp) nikon_3700(); if (model[0] == 'E' && atoi(model+1) < 3700) filters = 0x49494949; if (!strcmp(model,"Optio 33WR")) { flip = 1; filters = 0x16161616; } if (make[0] == 'O') { i = find_green (12, 32, 1188864, 3576832); c = find_green (12, 32, 2383920, 2387016); if (abs(i) < abs(c)) { SWAP(i,c); load_flags = 24; } if (i < 0) filters = 0x61616161; } } else if (fsize == 5869568) { if (!timestamp && minolta_z2()) { strcpy (make, "Minolta"); strcpy (model,"DiMAGE Z2"); } load_flags = 6 + 24*(make[0] == 'M'); } else if (fsize == 6291456) { fseek (ifp, 0x300000, SEEK_SET); if ((order = guess_byte_order(0x10000)) == 0x4d4d) { height -= (top_margin = 16); width -= (left_margin = 28); maximum = 0xf5c0; strcpy (make, "ISG"); model[0] = 0; } } else if (!strcmp(make,"Fujifilm")) { if (!strcmp(model+7,"S2Pro")) { strcpy (model,"S2Pro"); height = 2144; width = 2880; flip = 6; } else if (load_raw != &CLASS packed_load_raw) maximum = (is_raw == 2 && shot_select) ? 0x2f00 : 0x3e00; top_margin = (raw_height - height) >> 2 << 1; left_margin = (raw_width - width ) >> 2 << 1; if (width == 2848 || width == 3664) filters = 0x16161616; if (width == 4032 || width == 4952) left_margin = 0; if (width == 3328 && (width -= 66)) left_margin = 34; if (width == 4936) left_margin = 4; if (!strcmp(model,"HS50EXR")) { width += 2; left_margin = 0; filters = 0x16161616; } if (fuji_layout) raw_width *= is_raw; } else if (!strcmp(model,"KD-400Z")) { height = 1712; width = 2312; raw_width = 2336; goto konica_400z; } else if (!strcmp(model,"KD-510Z")) { goto konica_510z; } else if (!strcasecmp(make,"Minolta")) { if (!load_raw && (maximum = 0xfff)) load_raw = &CLASS unpacked_load_raw; if (!strncmp(model,"DiMAGE A",8)) { if (!strcmp(model,"DiMAGE A200")) filters = 0x49494949; tiff_bps = 12; load_raw = &CLASS packed_load_raw; } else if (!strncmp(model,"ALPHA",5) || !strncmp(model,"DYNAX",5) || !strncmp(model,"MAXXUM",6)) { sprintf (model+20, "DYNAX %-10s", model+6+(model[0]=='M')); adobe_coeff (make, model+20); load_raw = &CLASS packed_load_raw; } else if (!strncmp(model,"DiMAGE G",8)) { if (model[8] == '4') { height = 1716; width = 2304; } else if (model[8] == '5') { konica_510z: height = 1956; width = 2607; raw_width = 2624; } else if (model[8] == '6') { height = 2136; width = 2848; } data_offset += 14; filters = 0x61616161; konica_400z: load_raw = &CLASS unpacked_load_raw; maximum = 0x3df; order = 0x4d4d; } } else if (!strcmp(model,"*ist D")) { load_raw = &CLASS unpacked_load_raw; data_error = -1; } else if (!strcmp(model,"*ist DS")) { height -= 2; } else if (!strcmp(make,"Samsung") && raw_width == 4704) { height -= top_margin = 8; width -= 2 * (left_margin = 8); load_flags = 32; } else if (!strcmp(make,"Samsung") && raw_height == 3714) { height -= 18; width = 5536; filters = 0x49494949; } else if (!strcmp(make,"Samsung") && raw_width == 5632) { order = 0x4949; height = 3694; top_margin = 2; width = 5574 - (left_margin = 32 + tiff_bps); if (tiff_bps == 12) load_flags = 80; } else if (!strcmp(model,"EX1")) { order = 0x4949; height -= 20; top_margin = 2; if ((width -= 6) > 3682) { height -= 10; width -= 46; top_margin = 8; } } else if (!strcmp(model,"WB2000")) { order = 0x4949; height -= 3; top_margin = 2; if ((width -= 10) > 3718) { height -= 28; width -= 56; top_margin = 8; } } else if (strstr(model,"WB550")) { strcpy (model, "WB550"); } else if (!strcmp(model,"EX2F")) { height = 3045; width = 4070; top_margin = 3; order = 0x4949; filters = 0x49494949; load_raw = &CLASS unpacked_load_raw; } else if (!strcmp(model,"STV680 VGA")) { black = 16; } else if (!strcmp(model,"N95")) { height = raw_height - (top_margin = 2); } else if (!strcmp(model,"640x480")) { gamma_curve (0.45, 4.5, 1, 255); } else if (!strcmp(make,"Hasselblad")) { if (load_raw == &CLASS lossless_jpeg_load_raw) load_raw = &CLASS hasselblad_load_raw; if (raw_width == 7262) { height = 5444; width = 7248; top_margin = 4; left_margin = 7; filters = 0x61616161; } else if (raw_width == 7410) { height = 5502; width = 7328; top_margin = 4; left_margin = 41; filters = 0x61616161; } else if (raw_width == 9044) { height = 6716; width = 8964; top_margin = 8; left_margin = 40; black += load_flags = 256; maximum = 0x8101; } else if (raw_width == 4090) { strcpy (model, "V96C"); height -= (top_margin = 6); width -= (left_margin = 3) + 7; filters = 0x61616161; } } else if (!strcmp(make,"Sinar")) { if (!load_raw) load_raw = &CLASS unpacked_load_raw; maximum = 0x3fff; } else if (!strcmp(make,"Leaf")) { maximum = 0x3fff; fseek (ifp, data_offset, SEEK_SET); if (ljpeg_start (&jh, 1) && jh.bits == 15) maximum = 0x1fff; if (tiff_samples > 1) filters = 0; if (tiff_samples > 1 || tile_length < raw_height) { load_raw = &CLASS leaf_hdr_load_raw; raw_width = tile_width; } if ((width | height) == 2048) { if (tiff_samples == 1) { filters = 1; strcpy (cdesc, "RBTG"); strcpy (model, "CatchLight"); top_margin = 8; left_margin = 18; height = 2032; width = 2016; } else { strcpy (model, "DCB2"); top_margin = 10; left_margin = 16; height = 2028; width = 2022; } } else if (width+height == 3144+2060) { if (!model[0]) strcpy (model, "Cantare"); if (width > height) { top_margin = 6; left_margin = 32; height = 2048; width = 3072; filters = 0x61616161; } else { left_margin = 6; top_margin = 32; width = 2048; height = 3072; filters = 0x16161616; } if (!cam_mul[0] || model[0] == 'V') filters = 0; else is_raw = tiff_samples; } else if (width == 2116) { strcpy (model, "Valeo 6"); height -= 2 * (top_margin = 30); width -= 2 * (left_margin = 55); filters = 0x49494949; } else if (width == 3171) { strcpy (model, "Valeo 6"); height -= 2 * (top_margin = 24); width -= 2 * (left_margin = 24); filters = 0x16161616; } } else if (!strcmp(make,"Leica") || !strcmp(make,"Panasonic")) { if ((flen - data_offset) / (raw_width*8/7) == raw_height) load_raw = &CLASS panasonic_load_raw; if (!load_raw) { load_raw = &CLASS unpacked_load_raw; load_flags = 4; } zero_is_bad = 1; if ((height += 12) > raw_height) height = raw_height; for (i=0; i < sizeof pana / sizeof *pana; i++) if (raw_width == pana[i][0] && raw_height == pana[i][1]) { left_margin = pana[i][2]; top_margin = pana[i][3]; width += pana[i][4]; height += pana[i][5]; } filters = 0x01010101 * (uchar) "\x94\x61\x49\x16" [((filters-1) ^ (left_margin & 1) ^ (top_margin << 1)) & 3]; } else if (!strcmp(model,"C770UZ")) { height = 1718; width = 2304; filters = 0x16161616; load_raw = &CLASS packed_load_raw; load_flags = 30; } else if (!strcmp(make,"Olympus")) { height += height & 1; if (exif_cfa) filters = exif_cfa; if (width == 4100) width -= 4; if (width == 4080) width -= 24; if (load_raw == &CLASS unpacked_load_raw) load_flags = 4; tiff_bps = 12; if (!strcmp(model,"E-300") || !strcmp(model,"E-500")) { width -= 20; if (load_raw == &CLASS unpacked_load_raw) { maximum = 0xfc3; memset (cblack, 0, sizeof cblack); } } else if (!strcmp(model,"E-330")) { width -= 30; if (load_raw == &CLASS unpacked_load_raw) maximum = 0xf79; } else if (!strcmp(model,"SP550UZ")) { thumb_length = flen - (thumb_offset = 0xa39800); thumb_height = 480; thumb_width = 640; } } else if (!strcmp(model,"N Digital")) { height = 2047; width = 3072; filters = 0x61616161; data_offset = 0x1a00; load_raw = &CLASS packed_load_raw; } else if (!strcmp(model,"DSC-F828")) { width = 3288; left_margin = 5; mask[1][3] = -17; data_offset = 862144; load_raw = &CLASS sony_load_raw; filters = 0x9c9c9c9c; colors = 4; strcpy (cdesc, "RGBE"); } else if (!strcmp(model,"DSC-V3")) { width = 3109; left_margin = 59; mask[0][1] = 9; data_offset = 787392; load_raw = &CLASS sony_load_raw; } else if (!strcmp(make,"Sony") && raw_width == 3984) { adobe_coeff ("Sony","DSC-R1"); width = 3925; order = 0x4d4d; } else if (!strcmp(make,"Sony") && raw_width == 5504) { width -= 8; } else if (!strcmp(make,"Sony") && raw_width == 6048) { width -= 24; } else if (!strcmp(model,"DSLR-A100")) { if (width == 3880) { height--; width = ++raw_width; } else { order = 0x4d4d; load_flags = 2; } filters = 0x61616161; } else if (!strcmp(model,"DSLR-A350")) { height -= 4; } else if (!strcmp(model,"PIXL")) { height -= top_margin = 4; width -= left_margin = 32; gamma_curve (0, 7, 1, 255); } else if (!strcmp(model,"C603") || !strcmp(model,"C330")) { order = 0x4949; if (filters && data_offset) { fseek (ifp, 168, SEEK_SET); read_shorts (curve, 256); } else gamma_curve (0, 3.875, 1, 255); load_raw = filters ? &CLASS eight_bit_load_raw : &CLASS kodak_yrgb_load_raw; } else if (!strncasecmp(model,"EasyShare",9)) { data_offset = data_offset < 0x15000 ? 0x15000 : 0x17000; load_raw = &CLASS packed_load_raw; } else if (!strcasecmp(make,"Kodak")) { if (filters == UINT_MAX) filters = 0x61616161; if (!strncmp(model,"NC2000",6)) { width -= 4; left_margin = 2; } else if (!strcmp(model,"EOSDCS3B")) { width -= 4; left_margin = 2; } else if (!strcmp(model,"EOSDCS1")) { width -= 4; left_margin = 2; } else if (!strcmp(model,"DCS420")) { width -= 4; left_margin = 2; } else if (!strncmp(model,"DCS460 ",7)) { model[6] = 0; width -= 4; left_margin = 2; } else if (!strcmp(model,"DCS460A")) { width -= 4; left_margin = 2; colors = 1; filters = 0; } else if (!strcmp(model,"DCS660M")) { black = 214; colors = 1; filters = 0; } else if (!strcmp(model,"DCS760M")) { colors = 1; filters = 0; } if (!strcmp(model+4,"20X")) strcpy (cdesc, "MYCY"); if (strstr(model,"DC25")) { strcpy (model, "DC25"); data_offset = 15424; } if (!strncmp(model,"DC2",3)) { raw_height = 2 + (height = 242); if (flen < 100000) { raw_width = 256; width = 249; pixel_aspect = (4.0*height) / (3.0*width); } else { raw_width = 512; width = 501; pixel_aspect = (493.0*height) / (373.0*width); } top_margin = left_margin = 1; colors = 4; filters = 0x8d8d8d8d; simple_coeff(1); pre_mul[1] = 1.179; pre_mul[2] = 1.209; pre_mul[3] = 1.036; load_raw = &CLASS eight_bit_load_raw; } else if (!strcmp(model,"40")) { strcpy (model, "DC40"); height = 512; width = 768; data_offset = 1152; load_raw = &CLASS kodak_radc_load_raw; } else if (strstr(model,"DC50")) { strcpy (model, "DC50"); height = 512; width = 768; data_offset = 19712; load_raw = &CLASS kodak_radc_load_raw; } else if (strstr(model,"DC120")) { strcpy (model, "DC120"); height = 976; width = 848; pixel_aspect = height/0.75/width; load_raw = tiff_compress == 7 ? &CLASS kodak_jpeg_load_raw : &CLASS kodak_dc120_load_raw; } else if (!strcmp(model,"DCS200")) { thumb_height = 128; thumb_width = 192; thumb_offset = 6144; thumb_misc = 360; write_thumb = &CLASS layer_thumb; black = 17; } } else if (!strcmp(model,"Fotoman Pixtura")) { height = 512; width = 768; data_offset = 3632; load_raw = &CLASS kodak_radc_load_raw; filters = 0x61616161; simple_coeff(2); } else if (!strncmp(model,"QuickTake",9)) { if (head[5]) strcpy (model+10, "200"); fseek (ifp, 544, SEEK_SET); height = get2(); width = get2(); data_offset = (get4(),get2()) == 30 ? 738:736; if (height > width) { SWAP(height,width); fseek (ifp, data_offset-6, SEEK_SET); flip = ~get2() & 3 ? 5:6; } filters = 0x61616161; } else if (!strcmp(make,"Rollei") && !load_raw) { switch (raw_width) { case 1316: height = 1030; width = 1300; top_margin = 1; left_margin = 6; break; case 2568: height = 1960; width = 2560; top_margin = 2; left_margin = 8; } filters = 0x16161616; load_raw = &CLASS rollei_load_raw; } if (!model[0]) sprintf (model, "%dx%d", width, height); if (filters == UINT_MAX) filters = 0x94949494; if (raw_color) adobe_coeff (make, model); if (load_raw == &CLASS kodak_radc_load_raw) if (raw_color) adobe_coeff ("Apple","Quicktake"); if (thumb_offset && !thumb_height) { fseek (ifp, thumb_offset, SEEK_SET); if (ljpeg_start (&jh, 1)) { thumb_width = jh.wide; thumb_height = jh.high; } } dng_skip: if (fuji_width) { fuji_width = width >> !fuji_layout; if (~fuji_width & 1) filters = 0x49494949; width = (height >> fuji_layout) + fuji_width; height = width - 1; pixel_aspect = 1; } else { if (raw_height < height) raw_height = height; if (raw_width < width ) raw_width = width; } if (!tiff_bps) tiff_bps = 12; if (!maximum) maximum = (1 << tiff_bps) - 1; if (!load_raw || height < 22 || width < 22 || tiff_bps > 16 || tiff_samples > 4 || colors > 4) is_raw = 0; #ifdef NO_JASPER if (load_raw == &CLASS redcine_load_raw) { fprintf (stderr,_("%s: You must link dcraw with %s!!\n"), ifname, "libjasper"); is_raw = 0; } #endif #ifdef NO_JPEG if (load_raw == &CLASS kodak_jpeg_load_raw || load_raw == &CLASS lossy_dng_load_raw) { fprintf (stderr,_("%s: You must link dcraw with %s!!\n"), ifname, "libjpeg"); is_raw = 0; } #endif if (!cdesc[0]) strcpy (cdesc, colors == 3 ? "RGBG":"GMCY"); if (!raw_height) raw_height = height; if (!raw_width ) raw_width = width; if (filters > 999 && colors == 3) filters |= ((filters >> 2 & 0x22222222) | (filters << 2 & 0x88888888)) & filters << 1; notraw: if (flip == UINT_MAX) flip = tiff_flip; if (flip == UINT_MAX) flip = 0; } #ifndef NO_LCMS void CLASS apply_profile (const char *input, const char *output) { char *prof; cmsHPROFILE hInProfile=0, hOutProfile=0; cmsHTRANSFORM hTransform; FILE *fp; unsigned size; cmsErrorAction (LCMS_ERROR_SHOW); if (strcmp (input, "embed")) hInProfile = cmsOpenProfileFromFile (input, "r"); else if (profile_length) { prof = (char *) malloc (profile_length); merror (prof, "apply_profile()"); fseek (ifp, profile_offset, SEEK_SET); fread (prof, 1, profile_length, ifp); hInProfile = cmsOpenProfileFromMem (prof, profile_length); free (prof); } else fprintf (stderr,_("%s has no embedded profile.\n"), ifname); if (!hInProfile) return; if (!output) hOutProfile = cmsCreate_sRGBProfile(); else if ((fp = fopen (output, "rb"))) { fread (&size, 4, 1, fp); fseek (fp, 0, SEEK_SET); oprof = (unsigned *) malloc (size = ntohl(size)); merror (oprof, "apply_profile()"); fread (oprof, 1, size, fp); fclose (fp); if (!(hOutProfile = cmsOpenProfileFromMem (oprof, size))) { free (oprof); oprof = 0; } } else fprintf (stderr,_("Cannot open file %s!\n"), output); if (!hOutProfile) goto quit; if (verbose) fprintf (stderr,_("Applying color profile...\n")); hTransform = cmsCreateTransform (hInProfile, TYPE_RGBA_16, hOutProfile, TYPE_RGBA_16, INTENT_PERCEPTUAL, 0); cmsDoTransform (hTransform, image, image, width*height); raw_color = 1; /* Don't use rgb_cam with a profile */ cmsDeleteTransform (hTransform); cmsCloseProfile (hOutProfile); quit: cmsCloseProfile (hInProfile); } #endif void CLASS convert_to_rgb() { int row, col, c, i, j, k; ushort *img; float out[3], out_cam[3][4]; double num, inverse[3][3]; static const double xyzd50_srgb[3][3] = { { 0.436083, 0.385083, 0.143055 }, { 0.222507, 0.716888, 0.060608 }, { 0.013930, 0.097097, 0.714022 } }; static const double rgb_rgb[3][3] = { { 1,0,0 }, { 0,1,0 }, { 0,0,1 } }; static const double adobe_rgb[3][3] = { { 0.715146, 0.284856, 0.000000 }, { 0.000000, 1.000000, 0.000000 }, { 0.000000, 0.041166, 0.958839 } }; static const double wide_rgb[3][3] = { { 0.593087, 0.404710, 0.002206 }, { 0.095413, 0.843149, 0.061439 }, { 0.011621, 0.069091, 0.919288 } }; static const double prophoto_rgb[3][3] = { { 0.529317, 0.330092, 0.140588 }, { 0.098368, 0.873465, 0.028169 }, { 0.016879, 0.117663, 0.865457 } }; static const double (*out_rgb[])[3] = { rgb_rgb, adobe_rgb, wide_rgb, prophoto_rgb, xyz_rgb }; static const char *name[] = { "sRGB", "Adobe RGB (1998)", "WideGamut D65", "ProPhoto D65", "XYZ" }; static const unsigned phead[] = { 1024, 0, 0x2100000, 0x6d6e7472, 0x52474220, 0x58595a20, 0, 0, 0, 0x61637370, 0, 0, 0x6e6f6e65, 0, 0, 0, 0, 0xf6d6, 0x10000, 0xd32d }; unsigned pbody[] = { 10, 0x63707274, 0, 36, /* cprt */ 0x64657363, 0, 40, /* desc */ 0x77747074, 0, 20, /* wtpt */ 0x626b7074, 0, 20, /* bkpt */ 0x72545243, 0, 14, /* rTRC */ 0x67545243, 0, 14, /* gTRC */ 0x62545243, 0, 14, /* bTRC */ 0x7258595a, 0, 20, /* rXYZ */ 0x6758595a, 0, 20, /* gXYZ */ 0x6258595a, 0, 20 }; /* bXYZ */ static const unsigned pwhite[] = { 0xf351, 0x10000, 0x116cc }; unsigned pcurve[] = { 0x63757276, 0, 1, 0x1000000 }; gamma_curve (gamm[0], gamm[1], 0, 0); memcpy (out_cam, rgb_cam, sizeof out_cam); raw_color |= colors == 1 || document_mode || output_color < 1 || output_color > 5; if (!raw_color) { oprof = (unsigned *) calloc (phead[0], 1); merror (oprof, "convert_to_rgb()"); memcpy (oprof, phead, sizeof phead); if (output_color == 5) oprof[4] = oprof[5]; oprof[0] = 132 + 12*pbody[0]; for (i=0; i < pbody[0]; i++) { oprof[oprof[0]/4] = i ? (i > 1 ? 0x58595a20 : 0x64657363) : 0x74657874; pbody[i*3+2] = oprof[0]; oprof[0] += (pbody[i*3+3] + 3) & -4; } memcpy (oprof+32, pbody, sizeof pbody); oprof[pbody[5]/4+2] = strlen(name[output_color-1]) + 1; memcpy ((char *)oprof+pbody[8]+8, pwhite, sizeof pwhite); pcurve[3] = (short)(256/gamm[5]+0.5) << 16; for (i=4; i < 7; i++) memcpy ((char *)oprof+pbody[i*3+2], pcurve, sizeof pcurve); pseudoinverse ((double (*)[3]) out_rgb[output_color-1], inverse, 3); for (i=0; i < 3; i++) for (j=0; j < 3; j++) { for (num = k=0; k < 3; k++) num += xyzd50_srgb[i][k] * inverse[j][k]; oprof[pbody[j*3+23]/4+i+2] = num * 0x10000 + 0.5; } for (i=0; i < phead[0]/4; i++) oprof[i] = htonl(oprof[i]); strcpy ((char *)oprof+pbody[2]+8, "auto-generated by dcraw"); strcpy ((char *)oprof+pbody[5]+12, name[output_color-1]); for (i=0; i < 3; i++) for (j=0; j < colors; j++) for (out_cam[i][j] = k=0; k < 3; k++) out_cam[i][j] += out_rgb[output_color-1][i][k] * rgb_cam[k][j]; } if (verbose) fprintf (stderr, raw_color ? _("Building histograms...\n") : _("Converting to %s colorspace...\n"), name[output_color-1]); memset (histogram, 0, sizeof histogram); for (img=image[0], row=0; row < height; row++) for (col=0; col < width; col++, img+=4) { if (!raw_color) { out[0] = out[1] = out[2] = 0; FORCC { out[0] += out_cam[0][c] * img[c]; out[1] += out_cam[1][c] * img[c]; out[2] += out_cam[2][c] * img[c]; } FORC3 img[c] = CLIP((int) out[c]); } else if (document_mode) img[0] = img[fcol(row,col)]; FORCC histogram[c][img[c] >> 3]++; } if (colors == 4 && output_color) colors = 3; if (document_mode && filters) colors = 1; } void CLASS fuji_rotate() { int i, row, col; double step; float r, c, fr, fc; unsigned ur, uc; ushort wide, high, (*img)[4], (*pix)[4]; if (!fuji_width) return; if (verbose) fprintf (stderr,_("Rotating image 45 degrees...\n")); fuji_width = (fuji_width - 1 + shrink) >> shrink; step = sqrt(0.5); wide = fuji_width / step; high = (height - fuji_width) / step; img = (ushort (*)[4]) calloc (high, wide*sizeof *img); merror (img, "fuji_rotate()"); for (row=0; row < high; row++) for (col=0; col < wide; col++) { ur = r = fuji_width + (row-col)*step; uc = c = (row+col)*step; if (ur > height-2 || uc > width-2) continue; fr = r - ur; fc = c - uc; pix = image + ur*width + uc; for (i=0; i < colors; i++) img[row*wide+col][i] = (pix[ 0][i]*(1-fc) + pix[ 1][i]*fc) * (1-fr) + (pix[width][i]*(1-fc) + pix[width+1][i]*fc) * fr; } free (image); width = wide; height = high; image = img; fuji_width = 0; } void CLASS stretch() { ushort newdim, (*img)[4], *pix0, *pix1; int row, col, c; double rc, frac; if (pixel_aspect == 1) return; if (verbose) fprintf (stderr,_("Stretching the image...\n")); if (pixel_aspect < 1) { newdim = height / pixel_aspect + 0.5; img = (ushort (*)[4]) calloc (width, newdim*sizeof *img); merror (img, "stretch()"); for (rc=row=0; row < newdim; row++, rc+=pixel_aspect) { frac = rc - (c = rc); pix0 = pix1 = image[c*width]; if (c+1 < height) pix1 += width*4; for (col=0; col < width; col++, pix0+=4, pix1+=4) FORCC img[row*width+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; } height = newdim; } else { newdim = width * pixel_aspect + 0.5; img = (ushort (*)[4]) calloc (height, newdim*sizeof *img); merror (img, "stretch()"); for (rc=col=0; col < newdim; col++, rc+=1/pixel_aspect) { frac = rc - (c = rc); pix0 = pix1 = image[c]; if (c+1 < width) pix1 += 4; for (row=0; row < height; row++, pix0+=width*4, pix1+=width*4) FORCC img[row*newdim+col][c] = pix0[c]*(1-frac) + pix1[c]*frac + 0.5; } width = newdim; } free (image); image = img; } int CLASS flip_index (int row, int col) { if (flip & 4) SWAP(row,col); if (flip & 2) row = iheight - 1 - row; if (flip & 1) col = iwidth - 1 - col; return row * iwidth + col; } struct tiff_tag { ushort tag, type; int count; union { char c[4]; short s[2]; int i; } val; }; struct tiff_hdr { ushort order, magic; int ifd; ushort pad, ntag; struct tiff_tag tag[23]; int nextifd; ushort pad2, nexif; struct tiff_tag exif[4]; ushort pad3, ngps; struct tiff_tag gpst[10]; short bps[4]; int rat[10]; unsigned gps[26]; char desc[512], make[64], model[64], soft[32], date[20], artist[64]; }; void CLASS tiff_set (ushort *ntag, ushort tag, ushort type, int count, int val) { struct tiff_tag *tt; int c; tt = (struct tiff_tag *)(ntag+1) + (*ntag)++; tt->tag = tag; tt->type = type; tt->count = count; if (type < 3 && count <= 4) FORC(4) tt->val.c[c] = val >> (c << 3); else if (type == 3 && count <= 2) FORC(2) tt->val.s[c] = val >> (c << 4); else tt->val.i = val; } #define TOFF(ptr) ((char *)(&(ptr)) - (char *)th) void CLASS tiff_head (struct tiff_hdr *th, int full) { int c, psize=0; struct tm *t; memset (th, 0, sizeof *th); th->order = htonl(0x4d4d4949) >> 16; th->magic = 42; th->ifd = 10; if (full) { tiff_set (&th->ntag, 254, 4, 1, 0); tiff_set (&th->ntag, 256, 4, 1, width); tiff_set (&th->ntag, 257, 4, 1, height); tiff_set (&th->ntag, 258, 3, colors, output_bps); if (colors > 2) th->tag[th->ntag-1].val.i = TOFF(th->bps); FORC4 th->bps[c] = output_bps; tiff_set (&th->ntag, 259, 3, 1, 1); tiff_set (&th->ntag, 262, 3, 1, 1 + (colors > 1)); } tiff_set (&th->ntag, 270, 2, 512, TOFF(th->desc)); tiff_set (&th->ntag, 271, 2, 64, TOFF(th->make)); tiff_set (&th->ntag, 272, 2, 64, TOFF(th->model)); if (full) { if (oprof) psize = ntohl(oprof[0]); tiff_set (&th->ntag, 273, 4, 1, sizeof *th + psize); tiff_set (&th->ntag, 277, 3, 1, colors); tiff_set (&th->ntag, 278, 4, 1, height); tiff_set (&th->ntag, 279, 4, 1, height*width*colors*output_bps/8); } else tiff_set (&th->ntag, 274, 3, 1, "12435867"[flip]-'0'); tiff_set (&th->ntag, 282, 5, 1, TOFF(th->rat[0])); tiff_set (&th->ntag, 283, 5, 1, TOFF(th->rat[2])); tiff_set (&th->ntag, 284, 3, 1, 1); tiff_set (&th->ntag, 296, 3, 1, 2); tiff_set (&th->ntag, 305, 2, 32, TOFF(th->soft)); tiff_set (&th->ntag, 306, 2, 20, TOFF(th->date)); tiff_set (&th->ntag, 315, 2, 64, TOFF(th->artist)); tiff_set (&th->ntag, 34665, 4, 1, TOFF(th->nexif)); if (psize) tiff_set (&th->ntag, 34675, 7, psize, sizeof *th); tiff_set (&th->nexif, 33434, 5, 1, TOFF(th->rat[4])); tiff_set (&th->nexif, 33437, 5, 1, TOFF(th->rat[6])); tiff_set (&th->nexif, 34855, 3, 1, iso_speed); tiff_set (&th->nexif, 37386, 5, 1, TOFF(th->rat[8])); if (gpsdata[1]) { tiff_set (&th->ntag, 34853, 4, 1, TOFF(th->ngps)); tiff_set (&th->ngps, 0, 1, 4, 0x202); tiff_set (&th->ngps, 1, 2, 2, gpsdata[29]); tiff_set (&th->ngps, 2, 5, 3, TOFF(th->gps[0])); tiff_set (&th->ngps, 3, 2, 2, gpsdata[30]); tiff_set (&th->ngps, 4, 5, 3, TOFF(th->gps[6])); tiff_set (&th->ngps, 5, 1, 1, gpsdata[31]); tiff_set (&th->ngps, 6, 5, 1, TOFF(th->gps[18])); tiff_set (&th->ngps, 7, 5, 3, TOFF(th->gps[12])); tiff_set (&th->ngps, 18, 2, 12, TOFF(th->gps[20])); tiff_set (&th->ngps, 29, 2, 12, TOFF(th->gps[23])); memcpy (th->gps, gpsdata, sizeof th->gps); } th->rat[0] = th->rat[2] = 300; th->rat[1] = th->rat[3] = 1; FORC(6) th->rat[4+c] = 1000000; th->rat[4] *= shutter; th->rat[6] *= aperture; th->rat[8] *= focal_len; strncpy (th->desc, desc, 512); strncpy (th->make, make, 64); strncpy (th->model, model, 64); strcpy (th->soft, "dcraw v"DCRAW_VERSION); t = localtime (×tamp); sprintf (th->date, "%04d:%02d:%02d %02d:%02d:%02d", t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec); strncpy (th->artist, artist, 64); } void CLASS jpeg_thumb() { char *thumb; ushort exif[5]; struct tiff_hdr th; thumb = (char *) malloc (thumb_length); merror (thumb, "jpeg_thumb()"); fread (thumb, 1, thumb_length, ifp); fputc (0xff, ofp); fputc (0xd8, ofp); if (strcmp (thumb+6, "Exif")) { memcpy (exif, "\xff\xe1 Exif\0\0", 10); exif[1] = htons (8 + sizeof th); fwrite (exif, 1, sizeof exif, ofp); tiff_head (&th, 0); fwrite (&th, 1, sizeof th, ofp); } fwrite (thumb+2, 1, thumb_length-2, ofp); free (thumb); } #if 0 void CLASS write_ppm_tiff() { struct tiff_hdr th; uchar *ppm; ushort *ppm2; int c, row, col, soff, rstep, cstep; int perc, val, total, white=0x2000; perc = width * height * 0.01; /* 99th percentile white level */ if (fuji_width) perc /= 2; if (!((highlight & ~2) || no_auto_bright)) for (white=c=0; c < colors; c++) { for (val=0x2000, total=0; --val > 32; ) if ((total += histogram[c][val]) > perc) break; if (white < val) white = val; } gamma_curve (gamm[0], gamm[1], 2, (white << 3)/bright); iheight = height; iwidth = width; if (flip & 4) SWAP(height,width); ppm = (uchar *) calloc (width, colors*output_bps/8); ppm2 = (ushort *) ppm; merror (ppm, "write_ppm_tiff()"); if (output_tiff) { tiff_head (&th, 1); fwrite (&th, sizeof th, 1, ofp); if (oprof) fwrite (oprof, ntohl(oprof[0]), 1, ofp); } else if (colors > 3) fprintf (ofp, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH %d\nMAXVAL %d\nTUPLTYPE %s\nENDHDR\n", width, height, colors, (1 << output_bps)-1, cdesc); else fprintf (ofp, "P%d\n%d %d\n%d\n", colors/2+5, width, height, (1 << output_bps)-1); soff = flip_index (0, 0); cstep = flip_index (0, 1) - soff; rstep = flip_index (1, 0) - flip_index (0, width); for (row=0; row < height; row++, soff += rstep) { for (col=0; col < width; col++, soff += cstep) if (output_bps == 8) FORCC ppm [col*colors+c] = curve[image[soff][c]] >> 8; else FORCC ppm2[col*colors+c] = curve[image[soff][c]]; if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa) swab (ppm2, ppm2, width*colors*2); fwrite (ppm, colors*output_bps/8, width, ofp); } free (ppm); } int CLASS main (int argc, const char **argv) { int arg, status=0, quality, i, c; int timestamp_only=0, thumbnail_only=0, identify_only=0; int user_qual=-1, user_black=-1, user_sat=-1, user_flip=-1; int use_fuji_rotate=1, write_to_stdout=0, read_from_stdin=0; const char *sp, *bpfile=0, *dark_frame=0, *write_ext; char opm, opt, *ofname, *cp; struct utimbuf ut; #ifndef NO_LCMS const char *cam_profile=0, *out_profile=0; #endif #ifndef LOCALTIME putenv ((char *) "TZ=UTC"); #endif #ifdef LOCALEDIR setlocale (LC_CTYPE, ""); setlocale (LC_MESSAGES, ""); bindtextdomain ("dcraw", LOCALEDIR); textdomain ("dcraw"); #endif if (argc == 1) { printf(_("\nRaw photo decoder \"dcraw\" v%s"), DCRAW_VERSION); printf(_("\nby Dave Coffin, dcoffin a cybercom o net\n")); printf(_("\nUsage: %s [OPTION]... [FILE]...\n\n"), argv[0]); puts(_("-v Print verbose messages")); puts(_("-c Write image data to standard output")); puts(_("-e Extract embedded thumbnail image")); puts(_("-i Identify files without decoding them")); puts(_("-i -v Identify files and show metadata")); puts(_("-z Change file dates to camera timestamp")); puts(_("-w Use camera white balance, if possible")); puts(_("-a Average the whole image for white balance")); puts(_("-A <x y w h> Average a grey box for white balance")); puts(_("-r <r g b g> Set custom white balance")); puts(_("+M/-M Use/don't use an embedded color matrix")); puts(_("-C <r b> Correct chromatic aberration")); puts(_("-P <file> Fix the dead pixels listed in this file")); puts(_("-K <file> Subtract dark frame (16-bit raw PGM)")); puts(_("-k <num> Set the darkness level")); puts(_("-S <num> Set the saturation level")); puts(_("-n <num> Set threshold for wavelet denoising")); puts(_("-H [0-9] Highlight mode (0=clip, 1=unclip, 2=blend, 3+=rebuild)")); puts(_("-t [0-7] Flip image (0=none, 3=180, 5=90CCW, 6=90CW)")); puts(_("-o [0-5] Output colorspace (raw,sRGB,Adobe,Wide,ProPhoto,XYZ)")); #ifndef NO_LCMS puts(_("-o <file> Apply output ICC profile from file")); puts(_("-p <file> Apply camera ICC profile from file or \"embed\"")); #endif puts(_("-d Document mode (no color, no interpolation)")); puts(_("-D Document mode without scaling (totally raw)")); puts(_("-j Don't stretch or rotate raw pixels")); puts(_("-W Don't automatically brighten the image")); puts(_("-b <num> Adjust brightness (default = 1.0)")); puts(_("-g <p ts> Set custom gamma curve (default = 2.222 4.5)")); puts(_("-q [0-3] Set the interpolation quality")); puts(_("-h Half-size color image (twice as fast as \"-q 0\")")); puts(_("-f Interpolate RGGB as four colors")); puts(_("-m <num> Apply a 3x3 median filter to R-G and B-G")); puts(_("-s [0..N-1] Select one raw image or \"all\" from each file")); puts(_("-6 Write 16-bit instead of 8-bit")); puts(_("-4 Linear 16-bit, same as \"-6 -W -g 1 1\"")); puts(_("-T Write TIFF instead of PPM")); puts(""); return 1; } argv[argc] = ""; for (arg=1; (((opm = argv[arg][0]) - 2) | 2) == '+'; ) { opt = argv[arg++][1]; if ((cp = (char *) strchr (sp="nbrkStqmHACg", opt))) for (i=0; i < "114111111422"[cp-sp]-'0'; i++) if (!isdigit(argv[arg+i][0])) { fprintf (stderr,_("Non-numeric argument to \"-%c\"\n"), opt); return 1; } switch (opt) { case 'n': threshold = atof(argv[arg++]); break; case 'b': bright = atof(argv[arg++]); break; case 'r': FORC4 user_mul[c] = atof(argv[arg++]); break; case 'C': aber[0] = 1 / atof(argv[arg++]); aber[2] = 1 / atof(argv[arg++]); break; case 'g': gamm[0] = atof(argv[arg++]); gamm[1] = atof(argv[arg++]); if (gamm[0]) gamm[0] = 1/gamm[0]; break; case 'k': user_black = atoi(argv[arg++]); break; case 'S': user_sat = atoi(argv[arg++]); break; case 't': user_flip = atoi(argv[arg++]); break; case 'q': user_qual = atoi(argv[arg++]); break; case 'm': med_passes = atoi(argv[arg++]); break; case 'H': highlight = atoi(argv[arg++]); break; case 's': shot_select = abs(atoi(argv[arg])); multi_out = !strcmp(argv[arg++],"all"); break; case 'o': if (isdigit(argv[arg][0]) && !argv[arg][1]) output_color = atoi(argv[arg++]); #ifndef NO_LCMS else out_profile = argv[arg++]; break; case 'p': cam_profile = argv[arg++]; #endif break; case 'P': bpfile = argv[arg++]; break; case 'K': dark_frame = argv[arg++]; break; case 'z': timestamp_only = 1; break; case 'e': thumbnail_only = 1; break; case 'i': identify_only = 1; break; case 'c': write_to_stdout = 1; break; case 'v': verbose = 1; break; case 'h': half_size = 1; break; case 'f': four_color_rgb = 1; break; case 'A': FORC4 greybox[c] = atoi(argv[arg++]); case 'a': use_auto_wb = 1; break; case 'w': use_camera_wb = 1; break; case 'M': use_camera_matrix = (opm == '+'); break; case 'I': read_from_stdin = 1; break; case 'E': document_mode++; case 'D': document_mode++; case 'd': document_mode++; case 'j': use_fuji_rotate = 0; break; case 'W': no_auto_bright = 1; break; case 'T': output_tiff = 1; break; case '4': gamm[0] = gamm[1] = no_auto_bright = 1; case '6': output_bps = 16; break; default: fprintf (stderr,_("Unknown option \"-%c\".\n"), opt); return 1; } } if (use_camera_matrix < 0) use_camera_matrix = use_camera_wb; if (arg == argc) { fprintf (stderr,_("No files to process.\n")); return 1; } if (write_to_stdout) { if (isatty(1)) { fprintf (stderr,_("Will not write an image to the terminal!\n")); return 1; } #if defined(WIN32) || defined(DJGPP) || defined(__CYGWIN__) if (setmode(1,O_BINARY) < 0) { perror ("setmode()"); return 1; } #endif } for ( ; arg < argc; arg++) { status = 1; raw_image = 0; image = 0; oprof = 0; meta_data = ofname = 0; ofp = stdout; if (setjmp (failure)) { if (fileno(ifp) > 2) fclose(ifp); if (fileno(ofp) > 2) fclose(ofp); status = 1; goto cleanup; } ifname = argv[arg]; if (!(ifp = fopen (ifname, "rb"))) { perror (ifname); continue; } status = (identify(),!is_raw); if (user_flip >= 0) flip = user_flip; switch ((flip+3600) % 360) { case 270: flip = 5; break; case 180: flip = 3; break; case 90: flip = 6; } if (timestamp_only) { if ((status = !timestamp)) fprintf (stderr,_("%s has no timestamp.\n"), ifname); else if (identify_only) printf ("%10ld%10d %s\n", (long) timestamp, shot_order, ifname); else { if (verbose) fprintf (stderr,_("%s time set to %d.\n"), ifname, (int) timestamp); ut.actime = ut.modtime = timestamp; utime (ifname, &ut); } goto next; } write_fun = &CLASS write_ppm_tiff; if (thumbnail_only) { if ((status = !thumb_offset)) { fprintf (stderr,_("%s has no thumbnail.\n"), ifname); goto next; } else if (thumb_load_raw) { load_raw = thumb_load_raw; data_offset = thumb_offset; height = thumb_height; width = thumb_width; filters = 0; } else { fseek (ifp, thumb_offset, SEEK_SET); write_fun = write_thumb; goto thumbnail; } } if (load_raw == &CLASS kodak_ycbcr_load_raw) { height += height & 1; width += width & 1; } if (identify_only && verbose && make[0]) { printf (_("\nFilename: %s\n"), ifname); printf (_("Timestamp: %s"), ctime(×tamp)); printf (_("Camera: %s %s\n"), make, model); if (artist[0]) printf (_("Owner: %s\n"), artist); if (dng_version) { printf (_("DNG Version: ")); for (i=24; i >= 0; i -= 8) printf ("%d%c", dng_version >> i & 255, i ? '.':'\n'); } printf (_("ISO speed: %d\n"), (int) iso_speed); printf (_("Shutter: ")); if (shutter > 0 && shutter < 1) shutter = (printf ("1/"), 1 / shutter); printf (_("%0.1f sec\n"), shutter); printf (_("Aperture: f/%0.1f\n"), aperture); printf (_("Focal length: %0.1f mm\n"), focal_len); printf (_("Embedded ICC profile: %s\n"), profile_length ? _("yes"):_("no")); printf (_("Number of raw images: %d\n"), is_raw); if (pixel_aspect != 1) printf (_("Pixel Aspect Ratio: %0.6f\n"), pixel_aspect); if (thumb_offset) printf (_("Thumb size: %4d x %d\n"), thumb_width, thumb_height); printf (_("Full size: %4d x %d\n"), raw_width, raw_height); } else if (!is_raw) fprintf (stderr,_("Cannot decode file %s\n"), ifname); if (!is_raw) goto next; shrink = filters && (half_size || (!identify_only && (threshold || aber[0] != 1 || aber[2] != 1))); iheight = (height + shrink) >> shrink; iwidth = (width + shrink) >> shrink; if (identify_only) { if (verbose) { if (document_mode == 3) { top_margin = left_margin = fuji_width = 0; height = raw_height; width = raw_width; } iheight = (height + shrink) >> shrink; iwidth = (width + shrink) >> shrink; if (use_fuji_rotate) { if (fuji_width) { fuji_width = (fuji_width - 1 + shrink) >> shrink; iwidth = fuji_width / sqrt(0.5); iheight = (iheight - fuji_width) / sqrt(0.5); } else { if (pixel_aspect < 1) iheight = iheight / pixel_aspect + 0.5; if (pixel_aspect > 1) iwidth = iwidth * pixel_aspect + 0.5; } } if (flip & 4) SWAP(iheight,iwidth); printf (_("Image size: %4d x %d\n"), width, height); printf (_("Output size: %4d x %d\n"), iwidth, iheight); printf (_("Raw colors: %d"), colors); if (filters) { printf (_("\nFilter pattern: ")); for (i=0; i < 16; i++) putchar (cdesc[fcol(i >> 1,i & 1)]); } printf (_("\nDaylight multipliers:")); FORCC printf (" %f", pre_mul[c]); if (cam_mul[0] > 0) { printf (_("\nCamera multipliers:")); FORC4 printf (" %f", cam_mul[c]); } putchar ('\n'); } else printf (_("%s is a %s %s image.\n"), ifname, make, model); next: fclose(ifp); continue; } if (use_camera_matrix && cmatrix[0][0] > 0.25) { memcpy (rgb_cam, cmatrix, sizeof cmatrix); raw_color = 0; } if (meta_length) { meta_data = (char *) malloc (meta_length); merror (meta_data, "main()"); } if (filters || colors == 1) { raw_image = (ushort *) calloc ((raw_height+7), raw_width*2); merror (raw_image, "main()"); } else { image = (ushort (*)[4]) calloc (iheight, iwidth*sizeof *image); merror (image, "main()"); } if (verbose) fprintf (stderr,_("Loading %s %s image from %s ...\n"), make, model, ifname); if (shot_select >= is_raw) fprintf (stderr,_("%s: \"-s %d\" requests a nonexistent image!\n"), ifname, shot_select); fseeko (ifp, data_offset, SEEK_SET); if (raw_image && read_from_stdin) fread (raw_image, 2, raw_height*raw_width, stdin); else (*load_raw)(); if (document_mode == 3) { top_margin = left_margin = fuji_width = 0; height = raw_height; width = raw_width; } iheight = (height + shrink) >> shrink; iwidth = (width + shrink) >> shrink; if (raw_image) { image = (ushort (*)[4]) calloc (iheight, iwidth*sizeof *image); merror (image, "main()"); crop_masked_pixels(); free (raw_image); } if (zero_is_bad) remove_zeroes(); bad_pixels (bpfile); if (dark_frame) subtract (dark_frame); quality = 2 + !fuji_width; if (user_qual >= 0) quality = user_qual; i = cblack[3]; FORC3 if (i > cblack[c]) i = cblack[c]; FORC4 cblack[c] -= i; black += i; if (user_black >= 0) black = user_black; FORC4 cblack[c] += black; if (user_sat > 0) maximum = user_sat; #ifdef COLORCHECK colorcheck(); #endif if (is_foveon) { if (document_mode || load_raw == &CLASS foveon_dp_load_raw) { for (i=0; i < height*width*4; i++) if ((short) image[0][i] < 0) image[0][i] = 0; } else foveon_interpolate(); } else if (document_mode < 2) scale_colors(); pre_interpolate(); if (filters && !document_mode) { if (quality == 0) lin_interpolate(); else if (quality == 1 || colors > 3) vng_interpolate(); else if (quality == 2 && filters > 1000) ppg_interpolate(); else if (filters == 9) xtrans_interpolate (quality*2-3); else ahd_interpolate(); } if (mix_green) for (colors=3, i=0; i < height*width; i++) image[i][1] = (image[i][1] + image[i][3]) >> 1; if (!is_foveon && colors == 3) median_filter(); if (!is_foveon && highlight == 2) blend_highlights(); if (!is_foveon && highlight > 2) recover_highlights(); if (use_fuji_rotate) fuji_rotate(); #ifndef NO_LCMS if (cam_profile) apply_profile (cam_profile, out_profile); #endif convert_to_rgb(); if (use_fuji_rotate) stretch(); thumbnail: if (write_fun == &CLASS jpeg_thumb) write_ext = ".jpg"; else if (output_tiff && write_fun == &CLASS write_ppm_tiff) write_ext = ".tiff"; else write_ext = ".pgm\0.ppm\0.ppm\0.pam" + colors*5-5; ofname = (char *) malloc (strlen(ifname) + 64); merror (ofname, "main()"); if (write_to_stdout) strcpy (ofname,_("standard output")); else { strcpy (ofname, ifname); if ((cp = strrchr (ofname, '.'))) *cp = 0; if (multi_out) sprintf (ofname+strlen(ofname), "_%0*d", snprintf(0,0,"%d",is_raw-1), shot_select); if (thumbnail_only) strcat (ofname, ".thumb"); strcat (ofname, write_ext); ofp = fopen (ofname, "wb"); if (!ofp) { status = 1; perror (ofname); goto cleanup; } } if (verbose) fprintf (stderr,_("Writing data to %s ...\n"), ofname); (*write_fun)(); fclose(ifp); if (ofp != stdout) fclose(ofp); cleanup: if (meta_data) free (meta_data); if (ofname) free (ofname); if (oprof) free (oprof); if (image) free (image); if (multi_out) { if (++shot_select < is_raw) arg--; else shot_select = 0; } } return status; } #endif } // end of namespace �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/gif.cc���������������������������������������������������������������������0000644�0000764�0000764�00000015000�11343547354�014702� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2009 René Rebe * * 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 <gif_lib.h> #include "gif.hh" #include "Colorspace.hh" #include <iostream> /* The way Interlaced image should. */ static const int InterlacedOffset[] = { 0, 4, 2, 1 }; /* be read - offsets and jumps... */ static const int InterlacedJumps[] = { 8, 8, 4, 2 }; static int GIFInputFunc (GifFileType* t, GifByteType* mem, int len) { std::istream* stream = (std::istream*)t->UserData; size_t nbytes = stream->tellg(); stream->read((char*)mem, len); nbytes = (size_t)stream->tellg() - nbytes; return nbytes; } static int GIFOutputFunc (GifFileType* t, const GifByteType* mem, int len) { std::ostream* stream = (std::ostream*)t->UserData; stream->write ((char*)mem, len); return len; } int GIFCodec::readImage (std::istream* stream, Image& image, const std::string& decompres) { { // quick magic check char buf [3]; stream->read (buf, sizeof (buf)); stream->seekg (0); if (buf[0] != 'G' || buf[1] != 'I' || buf[2] != 'F') return false; } GifFileType* GifFile; GifRecordType RecordType; GifByteType* Extension; ColorMapObject *ColorMap = NULL; int ExtCode; if ((GifFile = DGifOpen (stream, &GIFInputFunc)) == NULL) { PrintGifError(); return false; } image.spp = 1; image.bps = 8; image.setResolution(0, 0); image.resize (GifFile->SWidth,GifFile->SHeight); /* Scan the content of the GIF file and load the image(s) in: */ do { if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) { PrintGifError(); return false; } int Row, Col, Width, Height; switch (RecordType) { case IMAGE_DESC_RECORD_TYPE: if (DGifGetImageDesc(GifFile) == GIF_ERROR) { PrintGifError(); return false; } Row = GifFile->Image.Top; /* Image Position relative to Screen. */ Col = GifFile->Image.Left; Width = GifFile->Image.Width; Height = GifFile->Image.Height; if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth || GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) { std::cerr << "Image not in screen dimension, aborted." << std::endl; return false; } if (GifFile->Image.Interlace) { /* Need to perform 4 passes on the images: */ for (int i = 0; i < 4; ++i) for (int j = Row + InterlacedOffset[i]; j < Row + Height; j += InterlacedJumps[i]) { if (DGifGetLine(GifFile, &image.getRawData()[j*image.stride()+Col], Width) == GIF_ERROR) { PrintGifError(); return false; } } } else { for (int i = 0; i < Height; ++i) { if (DGifGetLine(GifFile, &image.getRawData()[Row++ * image.stride()+Col], Width) == GIF_ERROR) { PrintGifError(); return false; } } } break; case EXTENSION_RECORD_TYPE: /* Skip any extension blocks in file: */ if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) { PrintGifError(); return false; } while (Extension != NULL) { if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) { PrintGifError(); return false; } } break; case TERMINATE_RECORD_TYPE: break; default: /* Should be traps by DGifGetRecordType. */ break; } } while (RecordType != TERMINATE_RECORD_TYPE); ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap : GifFile->SColorMap); uint16_t rmap [ColorMap->ColorCount]; uint16_t gmap [ColorMap->ColorCount]; uint16_t bmap [ColorMap->ColorCount]; for (int i = 0; i < ColorMap->ColorCount; ++i) { rmap[i] = ColorMap->Colors[i].Red << 8; gmap[i] = ColorMap->Colors[i].Green << 8; bmap[i] = ColorMap->Colors[i].Blue << 8; } // convert colormap to our 16bit "TIFF"format colorspace_de_palette (image, ColorMap->ColorCount, rmap, gmap, bmap); EGifCloseFile(GifFile); return true; } bool GIFCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { GifFileType* GifFile; GifByteType* Ptr; if ((GifFile = EGifOpen (stream, &GIFOutputFunc)) == NULL) { std::cerr << "Error preparing GIF file for writing." << std::endl; return false; } int ColorMapSize = 256; // later use our own colormap generation ColorMapObject* OutputColorMap = MakeMapObject(ColorMapSize, NULL); if (!OutputColorMap) return false; GifByteType* OutputBuffer = (GifByteType*) malloc(image.w * image.h * sizeof(GifByteType)); if (!OutputBuffer) return false; GifByteType *RedBuffer = new GifByteType [image.w*image.h], *GreenBuffer = new GifByteType [image.w*image.h], *BlueBuffer = new GifByteType [image.w*image.h]; GifByteType *rptr = RedBuffer, *gptr = GreenBuffer, *bptr = BlueBuffer; for (Image::iterator it = image.begin(); it != image.end(); ++it) { uint16_t r = 0, g = 0, b = 0; *it; it.getRGB (&r, &g, &b); *rptr++ = r; *gptr++ = g; *bptr++ = b; } if (QuantizeBuffer(image.w, image.h, &ColorMapSize, RedBuffer, GreenBuffer, BlueBuffer, OutputBuffer, OutputColorMap->Colors) == GIF_ERROR) { return false; } std::cerr << "Writing uncompressed GIF file with " << (int)ColorMapSize << " colors." << std::endl; if (EGifPutScreenDesc(GifFile, image.w, image.h, ColorMapSize, 0, OutputColorMap) == GIF_ERROR || EGifPutImageDesc(GifFile, 0, 0, image.w, image.h, FALSE, NULL) == GIF_ERROR) { std::cerr << "Error writing GIF header." << std::endl; return false; } Ptr = OutputBuffer; for (int i = 0; i < image.h; ++i) { if (EGifPutLine(GifFile, Ptr, image.w) == GIF_ERROR) { std::cerr << "Error writing GIF header." << std::endl; return false; } Ptr += image.w; } free (OutputBuffer); delete (RedBuffer); delete (GreenBuffer); delete (BlueBuffer); EGifCloseFile(GifFile); return true; } GIFCodec gif_loader; exact-image-0.9.1/codecs/xpm.cc���������������������������������������������������������������������0000644�0000764�0000764�00000014471�11737001650�014743� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2009 René Rebe * * 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 <ctype.h> #include <iostream> #include <string> #include <sstream> #include <vector> #include "xpm.hh" #include "Colorspace.hh" // Format: // // /* XPM */" // static char * XFACE[] = { // "48 48 2 1", // "a c #ffffff", // "b c #000000", // "abaabaababaaabaabababaabaabaababaabaaababaabaaab" // ... uint8_t parse_hex (std::istream* stream) { uint8_t x = 0; char c = tolower (stream->get()); if (c >= '0' && c <= '9') x = (x << 4) | (c - '0'); else x = (x << 4) | (c - 'a' + 10); c = tolower (stream->get()); if (c >= '0' && c <= '9') x = (x << 4) | (c - '0'); else x = (x << 4) | (c - 'a' + 10); return x; } void skip_comments (std::istream* stream) { if (stream->peek() == '/') { stream->get(); if (stream->peek() == '*') { // std::cerr << "comment" << std::endl; do { char c = stream->get(); // std::cerr << c; if (c == '*' && stream->peek() == '/') { stream->get(); break; } } while (*stream); while (*stream && stream->peek() == '\n') stream->get(); // std::cerr << std::endl; } else stream->putback('/'); } } int XPMCodec::readImage (std::istream* stream, Image& image, const std::string& decompres) { // check signature std::string line; std::getline (*stream, line); if (line != "/* XPM */") { stream->seekg (0); return false; } // TODO: wirte a more sophisticated parser here // drop the C declaration std::getline (*stream, line); skip_comments (stream); // dimensions and #colors if (stream->peek() == '"') stream->get(); int colors, cpp; // chars per pixel *stream >> image.w >> image.h >> colors >> cpp; std::getline (*stream, line); if (false) std::cerr << "XPM: " << image.w << "x" << image.h << ", colors: " << colors << ", chars per pix: " << cpp << std::endl; uint16_t* rmap = new uint16_t [colors]; uint16_t* gmap = new uint16_t [colors]; uint16_t* bmap = new uint16_t [colors]; std::vector<std::string> cmap; skip_comments (stream); // read color definitions for (int c = 0; c < colors; ++c) { std::string name, type; // std::cerr << "Reading color: " << c << std::endl; if (stream->peek() == '"') stream->get(); for (int i = 0; i < cpp; ++i) name.push_back (stream->get()); *stream >> type; // Type: c -> colour, m -> monochrome, g -> grayscale, and s -> symbolic if (type != "c") { std::cerr << "XPM color type: " << type << " not yet implemented." << std::endl; return false; } while (stream->peek() == ' ') stream->get(); if (stream->peek() == '#') { stream->get(); rmap[c] = parse_hex (stream) << 8; gmap[c] = parse_hex (stream) << 8; bmap[c] = parse_hex (stream) << 8; std::getline (*stream, line); } else { rmap[c] = gmap[c] = bmap[c] = 0; std::getline (*stream, line); if (line != "None\",") std::cerr << "Unrecognized color: " << line << std::endl; } // symbol -> index map cmap.push_back (name); //std::cerr << cmap[c] << ": " << rmap[c] << " " << gmap[c] << " " << bmap[c] << std::endl; } image.bps = 8; // for now, later this could be optimized image.spp = 3; // for now, later this could be optimized image.resize (image.w, image.h); image.setResolution(0, 0); skip_comments (stream); // read in the pixel data uint8_t* dst = image.getRawData(); int c = 0; std::string last = ""; for (int y = 0; y < image.h; ++y) { if (stream->peek() == '"') stream->get(); for (int x = 0; x < image.w; ++x) { std::string str; for (int i = 0; i < cpp; ++i) str.append (1, (char)stream->get()); if (str != last) { // TODO: make this a hash lookup ... std::vector<std::string>::iterator it = find (cmap.begin(), cmap.end(), str); if (it == cmap.end()) std::cerr << "Not in color map: '" << str << "'!" << std::endl; else { c = (it - cmap.begin()); last = str; } } *++dst = c; } std::getline (*stream, line); } colorspace_de_palette (image, colors, rmap, gmap, bmap); delete (rmap); delete (gmap); delete (bmap); rmap = gmap = bmap = 0; return true; } std::string symbol (int i) { std::string s; s.append (1, (char) ('a' + i)); return s; } std::string put_hex (unsigned char hi) { std::string s; unsigned char lo = hi & 0xF; hi >>= 4; if (hi < 10) s.append (1, (char)'0' + hi); else s.append (1, (char)'A' + hi - 10); if (lo < 10) s.append (1, (char)'0' + lo); else s.append (1, (char)'A' + lo - 10); return s; } bool XPMCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { // TODO: count colors later if (image.spp > 1) { std::cerr << "Too many colors for XPM." << std::endl; return false; } int colors = (1 << image.bps); *stream << "/* XPM */\n" << "static char * ExactImage[] = {\n" << "\"" << image.w << " " << image.h << " " << colors << " " << 1 /* cpp */ << "\",\n"; // write colors for (int c = 0; c < colors; ++c) { int l = c * 255 / (colors-1); *stream << "\"" << symbol (c) << "\t" << "c #" << put_hex(l) << put_hex(l) << put_hex(l) << "\",\n"; } // write pixels Image::iterator it = image.begin (); for (int y = 0; y < image.h; ++y) { *stream << "\""; for (int x = 0; x < image.w; ++x) { *it; *stream << symbol (it.getL() >> (8 - image.bps) ); ++it; } *stream << "\"" << (y < image.h-1 ? ",\n" : "};\n"); } return true; } XPMCodec xpm_loader; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/pcx.cc���������������������������������������������������������������������0000644�0000764�0000764�00000017436�12422531462�014736� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * C++ PCX library. * Copyright (C) 2008 - 2014 René Rebe, ExactCODE GmbH Germany * * 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 <iostream> #include <string.h> #include <ctype.h> #include "pcx.hh" #include "Colorspace.hh" #include "Endianess.hh" #include "inttypes.h" using Exact::EndianessConverter; using Exact::LittleEndianTraits; #ifdef _MSC_VER #pragma pack(push, 1) #endif typedef struct { uint8_t Manufacturer; uint8_t Version; uint8_t Encoding; uint8_t BitsPerPixel; EndianessConverter<uint16_t,LittleEndianTraits> WindowXmin; EndianessConverter<uint16_t,LittleEndianTraits> WindowYmin; EndianessConverter<uint16_t,LittleEndianTraits> WindowXmax; EndianessConverter<uint16_t,LittleEndianTraits> WindowYmax; EndianessConverter<uint16_t,LittleEndianTraits> HDpi; EndianessConverter<uint16_t,LittleEndianTraits> VDpi; uint8_t Colormap[16][3]; uint8_t Reserved; uint8_t NPlanes; EndianessConverter<uint16_t,LittleEndianTraits> BytesPerLine; // 0: udef, 1: color, 2: grayscale EndianessConverter<uint16_t,LittleEndianTraits> PaletteInfo; EndianessConverter<uint16_t,LittleEndianTraits> HScreenSize; EndianessConverter<uint16_t,LittleEndianTraits> VScreenSize; uint8_t Filler[54]; } #ifdef __GNUC__ __attribute__((packed)) #endif PCXHeader; #ifdef _MSC_VER #pragma pack(pop) #endif int PCXCodec::readImage(std::istream* stream, Image& image, const std::string& decompres) { if (stream->peek() != 0x0a) return false; stream->get(); if ((unsigned)stream->peek() > 5) { stream->unget(); return false; } stream->unget(); PCXHeader header; if (!stream->read((char*)&header, sizeof(header))) return false; switch (header.BitsPerPixel) { case 1: case 8: case 16: case 24: case 32: break; default: std::cerr << "PCX invalid bit-depth: " << header.BitsPerPixel << std::endl; goto no_pcx; }; switch (header.NPlanes) { case 1: case 3: case 4: break; default: std::cerr << "PCX invalid plane count: " << header.NPlanes << std::endl; goto no_pcx; }; image.bps = header.BitsPerPixel; image.spp = header.NPlanes; if (image.spp == 4 && image.bps == 1) image.spp = 1, image.bps = 4; image.setResolution(header.HDpi, header.VDpi); image.resize(header.WindowXmax - header.WindowXmin + 1, header.WindowYmax - header.WindowYmin + 1); //std::cerr << image.w << "x" << image.h << std::endl; //std::cerr << "BytesPerLine: " << (int)header.BytesPerLine << std::endl; /*std::cerr << "Version: " << (int)header.Version << ", PaletteInfo: " << header.PaletteInfo << ", BitsPerPixel: " << (int)header.BitsPerPixel << ", NPlanes: " << (int)header.NPlanes << ", Encoding: " << (int)header.Encoding << std::endl;*/ // TODO: more buffer checks { const bool plane_packing = header.NPlanes > 1; uint8_t* scanline = (plane_packing ? new uint8_t[header.BytesPerLine * header.NPlanes] : image.getRawData()); for (int y = 0; y < image.h; ++y) { for (int i = 0; i < header.BytesPerLine * header.NPlanes;) { uint8_t n = 1, v = stream->get(); if ((header.Encoding == 1) && (v & 0xC0) == 0xC0) { n = v ^ 0xC0; v = stream->get(); } while (n-- > 0 && i < header.BytesPerLine * header.NPlanes) { scanline[i++] = v; } } if (plane_packing) // re-pack planes { const unsigned bits = header.BitsPerPixel; const unsigned planes = header.NPlanes; uint8_t* dst = image.getRawData() + image.stride() * y; // TODO: share all bit packers in common code struct BitPacker { uint8_t* ptr; int p; const uint8_t bits, mask; const bool msb_first; BitPacker(uint8_t* _ptr, int _bits, bool _msb_first = true) : ptr(_ptr), p(_msb_first ? 8 - _bits : 0), bits(_bits), mask((1 << _bits) - 1), msb_first(_msb_first) { } void push(uint8_t v) { if (!msb_first) { *ptr = (*ptr & ~(mask << p)) | ((v & mask) << p); p += bits; if (p >= 8) p = 0, ++ptr; } else { *ptr = (*ptr & ~(mask << p)) | ((v & mask) << p); p -= bits; if (p < 0) p = 8 - bits, ++ptr; } } }; BitPacker packer(dst, bits == 8 ? bits : bits * planes); for (int i = 0; i < image.w; ++i) { uint8_t v = 0, mask = (1 << bits) - 1; unsigned b = 0; for (unsigned p = 0; p < planes; ++p) { uint8_t* src = scanline + p * header.BytesPerLine; int idx = i * bits / 8; int bit = i * bits % 8; bit = 8 - bits - bit; v |= ((src[idx] >> bit) & mask) << b; b += bits; if (b >= (bits == 8 ? bits : bits * planes)) { packer.push(v); b = v = 0; } } } } else // in-memory write { scanline += image.stride(); } } if (plane_packing) delete[] scanline; } if (image.spp == 1) { uint16_t rmap[256], gmap[256], bmap[256]; const uint8_t colormap_magic = stream->get(); if (colormap_magic == 0x0c) { //std::cerr << "reading colormap" << std::endl; for (int i = 0; i < 256; ++i) { uint8_t entry[3]; stream->read((char*)entry, sizeof(entry)); rmap[i] = entry[0] * 0xffff / 0xff; gmap[i] = entry[1] * 0xffff / 0xff; bmap[i] = entry[2] * 0xffff / 0xff; } if (!stream->good()) { std::cerr << "error reading PCX colormap" << std::endl; return false; } colorspace_de_palette (image, 256, rmap, gmap, bmap); } else if (header.PaletteInfo == 1 || header.PaletteInfo == 2) { const int ncolors = 1 << image.bps; for (int i = 0; i < ncolors; ++i) { rmap[i] = header.Colormap[i][0] * 0xffff / 0xff; gmap[i] = header.Colormap[i][1] * 0xffff / 0xff; bmap[i] = header.Colormap[i][2] * 0xffff / 0xff; } colorspace_de_palette(image, ncolors, rmap, gmap, bmap); } } return true; no_pcx: stream->seekg(0); return false; } bool PCXCodec::writeImage(std::ostream* stream, Image& image, int quality, const std::string& compress) { PCXHeader header; header.Manufacturer = 10; header.Version = 5; // TODO: save older versions if not RGB header.Encoding = 0; // 1: RLE header.NPlanes = image.spp; header.BytesPerLine = image.stride() / image.spp; header.BitsPerPixel = image.bps; header.PaletteInfo = 0; switch (header.BitsPerPixel) { case 1: case 8: case 16: case 24: case 32: break; default: std::cerr << "unsupported PCX bit-depth" << std::endl; return false; }; header.HDpi = image.resolutionX(); header.VDpi = image.resolutionY(); header.WindowXmin = 0; header.WindowYmin = 0; header.WindowXmax = image.width() - 1; header.WindowYmax = image.height() - 1; stream->write((char*)&header, sizeof(header)); // write "un"compressed image data // TODO: RLE compress for (int y = 0; y < image.h; ++y) { for (int plane = 0; plane < image.spp; ++plane) { uint8_t* data = image.getRawData() + image.stride() * y + plane; for (int x = 0; x < image.w; ++x) { stream->write((char*)data, 1); data += image.spp; } } } return true; } PCXCodec pcx_codec; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/agg_svg_exception.hh�������������������������������������������������������0000644�0000764�0000764�00000003327�10776625145�017657� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // SVG exception // //---------------------------------------------------------------------------- #ifndef AGG_SVG_EXCEPTION_INCLUDED #define AGG_SVG_EXCEPTION_INCLUDED #include <stdio.h> #include <string.h> #include <stdarg.h> namespace agg { namespace svg { class exception { public: ~exception() { delete [] m_msg; } exception() : m_msg(0) {} exception(const char* fmt, ...) : m_msg(0) { if(fmt) { m_msg = new char [4096]; va_list arg; va_start(arg, fmt); vsprintf(m_msg, fmt, arg); va_end(arg); } } exception(const exception& exc) : m_msg(exc.m_msg ? new char[strlen(exc.m_msg) + 1] : 0) { if(m_msg) strcpy(m_msg, exc.m_msg); } const char* msg() const { return m_msg; } private: char* m_msg; }; } } #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/jpeg2000.hh����������������������������������������������������������������0000644�0000764�0000764�00000002064�11343547354�015404� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2008 René Rebe * * 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 "Codecs.hh" class JPEG2000Codec : public ImageCodec { public: JPEG2000Codec () { registerCodec ("jp2", this); }; virtual std::string getID () { return "JPEG2000"; }; virtual int readImage (std::istream* stream, Image& im, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& im, int quality, const std::string& compress); }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/bmp.hh���������������������������������������������������������������������0000644�0000764�0000764�00000002326�12422527572�014733� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2014 René Rebe * * 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 "Codecs.hh" struct BMPFileHeader; // just fwd. class BMPCodec : public ImageCodec { public: BMPCodec () { registerCodec ("bmp", this); }; virtual std::string getID () { return "BMP"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompress); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); static int readImageWithoutFileHeader (std::istream* stream, Image& image, const std::string& decompress = "", BMPFileHeader* header = 0); }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/eps.cc���������������������������������������������������������������������0000644�0000764�0000764�00000003032�11343547354�014726� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (c) 2008 Valentin Ziegler <valentin@exactcode.de> * Copyright (c) 2008 Susanne Klaus <susanne@exactcode.de> * Copyright (c) 2009 Rene Rebe <rene@exactcode.de> * * 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 "eps.hh" #include "ps.hh" int EPSCodec::readImage (std::istream* stream, Image& image, const std::string& decompres) { return false; } bool EPSCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { // TODO: yres might be different double dpi = image.resolutionX() ? image.resolutionX() : 72; double scale = 72 / dpi; //postscript native resolution is 72dpi. *stream << "%!PS-Adobe-3.0 EPSF-3.0\n" "%%BoundingBox: 0 0 " << scale*(double)image.w << " " << scale*(double)image.h << "\n" "0 dict begin" << std::endl; PSCodec::encodeImage (stream, image, scale, quality, compress); *stream << "showpage\nend" << std::endl; return true; } EPSCodec eps_loader; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/ps.cc����������������������������������������������������������������������0000644�0000764�0000764�00000006571�11343547354�014574� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (c) 2008 Valentin Ziegler <valentin@exactcode.de> * Copyright (c) 2008 Susanne Klaus <susanne@exactcode.de> * Copyright (c) 2009 Rene Rebe <rene@exactcode.de> * * 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 "ps.hh" #include "Encodings.hh" #if WITHLIBJPEG == 1 #include "jpeg.hh" #endif int PSCodec::readImage (std::istream* stream, Image& image, const std::string& decompres) { return false; } bool PSCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { const int w = image.w; const int h = image.h; // TODO: yres might be different double dpi = image.resolutionX() ? image.resolutionY() : 72; double scale = 72 / dpi; //postscript native resolution is 72dpi. const char* creatorName = "ExactImage"; *stream << "%!PS-Adobe-3.0\n" "%%Creator:" << creatorName << "\n" "%%DocumentData: Clean7Bit\n" "%%LanguageLevel: 2\n" "%%BoundingBox: 0 0 " << scale*(double)w << " " << scale*(double)h << "\n" "%%EndComments\n" "%%BeginProlog\n" "0 dict begin\n" "%%EndProlog\n" "%%BeginPage\n" << std::endl; encodeImage (stream, image, scale, quality, compress); *stream << "%%EndPage\nshowpage\nend" << std::endl; return true; } void PSCodec::encodeImage (std::ostream* stream, Image& image, double scale, int quality, const std::string& compress) { const int w = image.w; const int h = image.h; std::string encoding = "ASCII85Decode"; if (!compress.empty()) { std::string c (compress); std::transform (c.begin(), c.end(), c.begin(), tolower); if (c == "encodeascii85") encoding = "ASCII85Decode"; else if (c == "encodehex") encoding = "ASCIIHexDecode"; else if (c == "encodejpeg") encoding = "DCTDecode"; else std::cerr << "PDFCodec: Unrecognized encoding option '" << compress << "'" << std::endl; } const char* decodeName = "Decode [0 1 0 1 0 1]"; const char* deviceName = "DeviceRGB"; if (image.spp == 1) { deviceName = "DeviceGray"; decodeName = "Decode [0 1]"; } *stream << "/" << deviceName << " setcolorspace\n" "<<\n" " /ImageType 1\n" " /Width " << w << " /Height " << h << "\n" " /BitsPerComponent " << image.bps << "\n" " /" << decodeName << "\n" " /ImageMatrix [\n" " " << 1.0 / scale << " 0.0\n" " 0.0 " << -1.0 / scale << "\n" " 0.0 " << h << "\n" " ]\n" " /DataSource currentfile /" << encoding << " filter\n" ">> image" << std::endl; const int bytes = image.stride() * h; uint8_t* data = image.getRawData(); if (encoding == "ASCII85Decode") EncodeASCII85(*stream, data, bytes); else if (encoding == "ASCIIHexDecode") EncodeHex(*stream, data, bytes); #if WITHLIBJPEG == 1 else { JPEGCodec codec; codec.writeImage (stream, image, quality, compress); } #endif stream->put('\n'); } PSCodec ps_loader; ���������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/jpeg2000.cc����������������������������������������������������������������0000644�0000764�0000764�00000021036�11343547354�015372� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2005 - 2008 René Rebe * * 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 <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <sstream> #include <jasper/jasper.h> #include <jasper/jas_image.h> #include "utils.hh" #include "jpeg2000.hh" static void add_color_prof(jas_image_t* image) { /* Create a color profile if needed. */ if (!jas_clrspc_isunknown(image->clrspc_) && !jas_clrspc_isgeneric(image->clrspc_) && !image->cmprof_) { if (!(image->cmprof_ = jas_cmprof_createfromclrspc(jas_image_clrspc(image)))) { std::cerr << "error: cannot create the colorspace" << std::endl; return; } } } static jas_stream_t* jas_stream_create() { jas_stream_t* stream; if (!(stream = (jas_stream_t*) jas_malloc(sizeof(jas_stream_t)))) { return 0; } stream->openmode_ = 0; stream->bufmode_ = 0; stream->flags_ = 0; stream->bufbase_ = 0; stream->bufstart_ = 0; stream->bufsize_ = 0; stream->ptr_ = 0; stream->cnt_ = 0; stream->ops_ = 0; stream->obj_ = 0; stream->rwcnt_ = 0; stream->rwlimit_ = -1; return stream; } static int cpp_jas_read (jas_stream_obj_t* obj, char* buf, int cnt) { std::istream* stream = (std::istream*) obj; stream->read (buf, cnt); return cnt; } static int cpp_jas_write (jas_stream_obj_t* obj, char* buf, int cnt) { std::ostream* stream = (std::ostream*) obj; stream->write (buf, cnt); return cnt; } static long cpp_jas_seek (jas_stream_obj_t* obj, long offset, int origin) { std::cerr << __FUNCTION__ << " implement me ,-)" << std::endl; /* std::istream* stream = (std::istream*) obj; stream->read (buf, cnt); return cnt; */ return 0; } static int cpp_jas_close (jas_stream_obj_t* obj) { // NOP, nothing to do return 0; } static jas_stream_ops_t cpp_jas_stream_ops = { cpp_jas_read, cpp_jas_write, cpp_jas_seek, cpp_jas_close }; static void jas_stream_initbuf (jas_stream_t* stream) { stream->bufbase_ = (uint8_t*) jas_malloc (JAS_STREAM_BUFSIZE + JAS_STREAM_MAXPUTBACK); if (stream->bufbase_) { stream->bufmode_ |= JAS_STREAM_FREEBUF; stream->bufsize_ = JAS_STREAM_BUFSIZE; } else { stream->bufbase_ = stream->tinybuf_; stream->bufsize_ = 1; } stream->bufstart_ = &stream->bufbase_ [JAS_STREAM_MAXPUTBACK]; stream->ptr_ = stream->bufstart_; stream->cnt_ = 0; stream->bufmode_ |= JAS_STREAM_BUFMODEMASK; } int JPEG2000Codec::readImage (std::istream* stream, Image& im, const std::string& decompres) { { // quick magic check char buf [6]; stream->read (buf, sizeof (buf)); stream->seekg (0); if (buf[4] != 'j' || buf[5] != 'P') return false; } jas_image_t* image; jas_stream_t* in; if (!(in = jas_stream_create ())) { std::cerr << "error: cannot create stream" << std::endl; return false; } // fill stream details in->openmode_ = JAS_STREAM_BINARY | JAS_STREAM_READ; in->obj_ = stream; in->ops_ = &cpp_jas_stream_ops; jas_stream_initbuf (in); if (!(image = jp2_decode(in, 0))) { std::cerr << "error: cannot load image data" << std::endl; return false; } add_color_prof(image); jas_stream_close (in); im.w = jas_image_width (image); im.h = jas_image_height (image); #define PRINT(a,b) case a: std::cout << "Clrspc: " << a << ", " << b << std::endl; break; switch (jas_image_clrspc(image)) { PRINT(JAS_CLRSPC_UNKNOWN, "UNKNOWN") PRINT(JAS_CLRSPC_CIEXYZ, "CIEXYZ") PRINT(JAS_CLRSPC_CIELAB, "CIELAB") PRINT(JAS_CLRSPC_SGRAY, "SGRAY") PRINT(JAS_CLRSPC_SRGB, "SRGB") PRINT(JAS_CLRSPC_SYCBCR, "SYCBCR") PRINT(JAS_CLRSPC_GENGRAY, "GENRGB") PRINT(JAS_CLRSPC_GENRGB, "GENRGB") PRINT(JAS_CLRSPC_GENYCBCR, "GENYCBCR") default: std::cerr << "Yet unknown colorspace ..." << std::endl; } // convert colorspace switch (jas_image_clrspc(image)) { case JAS_CLRSPC_SGRAY: case JAS_CLRSPC_SRGB: case JAS_CLRSPC_GENGRAY: case JAS_CLRSPC_GENRGB: break; default: { jas_image_t *newimage; jas_cmprof_t *outprof; std::cerr << "forcing conversion to sRGB" << std::endl; if (!(outprof = jas_cmprof_createfromclrspc(JAS_CLRSPC_SRGB))) { std::cerr << "cannot create sRGB profile" << std::endl; return 0; } std::cerr << "in space: " << jas_image_cmprof(image) << std::endl; if (!(newimage = jas_image_chclrspc(image, outprof, JAS_CMXFORM_INTENT_PER))) { std::cerr << "cannot convert to sRGB" << std::endl; return 0; } jas_image_destroy(image); jas_cmprof_destroy(outprof); image = newimage; std::cerr << "converted to sRGB" << std::endl; } } im.spp = jas_image_numcmpts(image); im.bps = jas_image_cmptprec(image, 0/*component*/); if (im.bps != 1 && im.bps != 8) // we do not support the others, yet im.bps = 8; std::cerr << "Components: " << jas_image_numcmpts(image) << ", precision: " << jas_image_cmptprec(image, 0) << std::endl; im.resize (im.w, im.h); uint8_t* data = im.getRawData (); uint8_t* data_ptr = data; jas_matrix_t *jasdata[3]; for (int k = 0; k < im.spp; ++k) { if (!(jasdata[k] = jas_matrix_create(im.h, im.w))) { std::cerr << "internal error" << std::endl;; return 0; } if (jas_image_readcmpt(image, k, 0, 0, im.w, im.h, jasdata[k])) { std::cerr << "cannot read component data " << k << std::endl; return 0; } } int v [3]; for (int y = 0; y < im.h; ++y) { for (int x = 0; x < im.w; ++x) { for (int k = 0; k < im.spp; ++k) { v[k] = jas_matrix_get (jasdata[k], y, x); // if the precision of the component is not supported, scale it int prec = jas_image_cmptprec(image, k); if (prec < 8) v[k] <<= 8 - prec; else v[k] >>= prec - 8; } for (int k = 0; k < im.spp; ++k) *data_ptr++ = v[k]; } } jas_image_destroy (image); return true; } bool JPEG2000Codec::writeImage (std::ostream* stream, Image& im, int quality, const std::string& compress) { jas_image_t* image; jas_stream_t* out; if (!(out = jas_stream_create ())) { std::cerr << "error: cannot create stream" << std::endl; return false; } // fill stream details out->openmode_ = JAS_STREAM_BINARY | JAS_STREAM_WRITE; out->obj_ = stream; out->ops_ = &cpp_jas_stream_ops; jas_stream_initbuf (out); jas_image_cmptparm_t compparms[3]; for (int i = 0; i < im.spp; ++i) { compparms[i].tlx = 0; compparms[i].tly = 0; compparms[i].hstep = 1; compparms[i].vstep = 1; compparms[i].width = im.w; compparms[i].height = im.h; compparms[i].prec = im.bps; compparms[i].sgnd = false; } if (!(image = jas_image_create(im.spp, compparms, im.spp==3?JAS_CLRSPC_SRGB:JAS_CLRSPC_SGRAY))) { std::cerr << "error creating jasper image" << std::endl; } jas_matrix_t *jasdata[3]; for (int i = 0; i < im.spp; ++i) { if (!(jasdata[i] = jas_matrix_create(im.h, im.w))) { std::cerr << "internal error" << std::endl; return false; } } uint8_t* it = im.getRawData(); for (int y = 0; y < im.h; ++y) { for (int x = 0; x < im.w; ++x) { for (int k = 0; k < im.spp; ++k) jas_matrix_set(jasdata[k], y, x, *it++); } } for (int i = 0; i < im.spp; ++i) { int ct = JAS_IMAGE_CT_GRAY_Y; if (im.spp > 1) switch (i) { case 0: ct = JAS_IMAGE_CT_RGB_R; break; case 1: ct = JAS_IMAGE_CT_RGB_G; break; case 2: ct = JAS_IMAGE_CT_RGB_B; break; } jas_image_setcmpttype (image, i, ct ); if (jas_image_writecmpt(image, i, 0, 0, im.w, im.h, jasdata[i])) { std::cerr << "error writing converted data into jasper" << std::endl; return false; } } std::stringstream opts; opts << "rate=" << (double)quality / 100; jp2_encode(image, out, (char*)opts.str().c_str()); jas_image_destroy (image); jas_stream_close (out); return true; } JPEG2000Codec jpeg2000_loader; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/openexr.cc�����������������������������������������������������������������0000644�0000764�0000764�00000011331�11343547354�015620� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2008 René Rebe * * 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 <stdio.h> #include <stdlib.h> #include <string.h> #include <ImfIO.h> #include <ImfInputFile.h> #include <ImfOutputFile.h> #include <ImfRgbaFile.h> #include <ImfArray.h> #include <IexThrowErrnoExc.h> #include <algorithm> #include "openexr.hh" #include "Colorspace.hh" using namespace Imf; using namespace Imath; using std::cout; using std::endl; class STDIStream : public IStream { public: STDIStream (std::istream* stream, const char fileName[]) : IStream (fileName), _stream (stream) { } virtual bool read (char c[], int n) { try { _stream->read (c, n); } catch (...) { if (!*_stream) Iex::throwErrnoExc(); else throw Iex::InputExc ("Unexpected end of file."); } return _stream->eof(); } virtual Int64 tellg () { return _stream->tellg (); } virtual void seekg (Int64 pos) { _stream->clear (); _stream->seekg (pos); } virtual void clear () { _stream->clear (); } private: std::istream* _stream; }; class STDOStream : public OStream { public: STDOStream (std::ostream* stream, const char fileName[]) : OStream (fileName), _stream (stream) { } virtual void write (const char c[], int n) { try { _stream->write (c, n); } catch (...) { if (!*_stream) Iex::throwErrnoExc(); else throw Iex::InputExc ("Unexpected end of file."); } } virtual Int64 tellp () { return _stream->tellp (); } virtual void seekp (Int64 pos) { _stream->clear (); _stream->seekp (pos); } virtual void clear () { _stream->clear (); } private: std::ostream* _stream; }; int OpenEXRCodec::readImage (std::istream* stream, Image& image, const std::string& decompres) { STDIStream istream (stream, ""); { // quick magic check char buf [3]; stream->read (buf, sizeof (buf)); stream->seekg (0); // inaccurate, but enough for now if (buf[0] != 'v' || buf[1] != '/' || buf[2] != '1') return false; } try { RgbaInputFile exrfile (istream); Box2i dw = exrfile.dataWindow (); image.spp = 4; image.bps = 16; image.resize (dw.max.x - dw.min.x + 1, dw.max.y - dw.min.y + 1); Array2D<Rgba> pixels (1, image.w); // working data uint16_t* it = (uint16_t*) image.getRawData(); for (int y = 0; y < image.h; ++y) { exrfile.setFrameBuffer (&pixels[0][0] - y * image.w, 1, image.w); exrfile.readPixels (y, y); for (int x = 0; x < image.w; ++x) { double r = pixels[0][x].r; double g = pixels[0][x].g; double b = pixels[0][x].b; double a = pixels[0][x].a; r = std::min (std::max (r,0.0),1.0) * 0xFFFF; g = std::min (std::max (g,0.0),1.0) * 0xFFFF; b = std::min (std::max (b,0.0),1.0) * 0xFFFF; a = std::min (std::max (a,0.0),1.0) * 0xFFFF; *it++ = (int) r; *it++ = (int)g; *it++ = (int)b; *it++ = (int)a; } } return true; } catch (...) { return false; } } bool OpenEXRCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { RgbaChannels type; switch (image.spp) { case 1: type = WRITE_Y; break; case 2: type = WRITE_YA; break; case 3: type = WRITE_RGB; break; case 4: type = WRITE_RGBA; break; break; default: std::cerr << "Unsupported image format." << std::endl; return false; } Box2i displayWindow (V2i (0, 0), V2i (image.w - 1, image.h - 1)); STDOStream ostream (stream, ""); Header header (image.w, image.h); RgbaOutputFile exrfile (ostream, header, type); Array2D<Rgba> pixels (1, image.w); // working data uint16_t* it = (uint16_t*) image.getRawData(); for (int y = 0; y < image.h; ++y) { exrfile.setFrameBuffer (&pixels[0][0] - y * image.w, 1, image.w); for (int x = 0; x < image.w; ++x) { pixels[0][x].r = (double)*it++ / 0xFFFF; pixels[0][x].g = (double)*it++ / 0xFFFF; pixels[0][x].b = (double)*it++ / 0xFFFF; pixels[0][x].a = (double)*it++ / 0xFFFF; } exrfile.writePixels (1); } return true; } OpenEXRCodec openexr_loader; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/jpeg.hh��������������������������������������������������������������������0000644�0000764�0000764�00000004243�11343547354�015103� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2008 René Rebe * (C) 2006, 2007 Archivista GmbH, CH-8042 Zuerich * * 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. */ extern "C" { #include <jpeglib.h> #include <jerror.h> #include "transupp.h" } #include <sstream> #include "Codecs.hh" class JPEGCodec : public ImageCodec { public: JPEGCodec () { registerCodec ("jpeg", this); registerCodec ("jpg", this); }; // freestanding JPEGCodec (Image* _image); virtual std::string getID () { return "JPEG"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); // on-demand decoding virtual /*bool*/ void decodeNow (Image* image); // optional optimizing and/or lossless implementations virtual bool flipX (Image& image); virtual bool flipY (Image& image); virtual bool rotate (Image& image, double angle); virtual bool crop (Image& image, unsigned int x, unsigned int y, unsigned int w, unsigned int h); virtual bool toGray (Image& image); virtual bool scale (Image& image, double xscale, double yscale); private: void parseExif (Image& image); void decodeNow (Image* image, int factor); // internals and helper bool readMeta (std::istream* stream, Image& image); bool doTransform (JXFORM_CODE code, Image& image, std::ostream* stream = 0, bool to_gray = false, bool crop = false, unsigned int x = 0, unsigned int y = 0, unsigned int w = 0, unsigned int h = 0); std::stringstream private_copy; }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/agg_svg_path_tokenizer.hh��������������������������������������������������0000644�0000764�0000764�00000007221�11027657673�020705� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������//---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.3 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- // // SVG path tokenizer. // //---------------------------------------------------------------------------- #ifndef AGG_SVG_PATH_TOKENIZER_INCLUDED #define AGG_SVG_PATH_TOKENIZER_INCLUDED #include "agg_svg_exception.hh" namespace agg { namespace svg { // SVG path tokenizer. // Example: // // agg::svg::path_tokenizer tok; // // tok.set_str("M-122.304 84.285L-122.304 84.285 122.203 86.179 "); // while(tok.next()) // { // printf("command='%c' number=%f\n", // tok.last_command(), // tok.last_number()); // } // // The tokenizer does all the routine job of parsing the SVG paths. // It doesn't recognize any graphical primitives, it even doesn't know // anything about pairs of coordinates (X,Y). The purpose of this class // is to tokenize the numeric values and commands. SVG paths can // have single numeric values for Horizontal or Vertical line_to commands // as well as more than two coordinates (4 or 6) for Bezier curves // depending on the semantics of the command. // The behaviour is as follows: // // Each call to next() returns true if there's new command or new numeric // value or false when the path ends. How to interpret the result // depends on the sematics of the command. For example, command "C" // (cubic Bezier curve) implies 6 floating point numbers preceded by this // command. If the command assumes no arguments (like z or Z) the // the last_number() values won't change, that is, last_number() always // returns the last recognized numeric value, so does last_command(). //=============================================================== class path_tokenizer { public: path_tokenizer(); void set_path_str(const char* str); bool next(); double next(char cmd); char last_command() const { return m_last_command; } double last_number() const { return m_last_number; } private: static void init_char_mask(char* mask, const char* char_set); bool contains(const char* mask, unsigned c) const { return (mask[(c >> 3) & (256/8-1)] & (1 << (c & 7))) != 0; } bool is_command(unsigned c) const { return contains(m_commands_mask, c); } bool is_numeric(unsigned c) const { return contains(m_numeric_mask, c); } bool is_separator(unsigned c) const { return contains(m_separators_mask, c); } bool parse_number(); char m_separators_mask[256/8]; char m_commands_mask[256/8]; char m_numeric_mask[256/8]; const char* m_path; double m_last_number; char m_last_command; static const char s_commands[]; static const char s_numeric[]; static const char s_separators[]; }; } //namespace svg } //namespace agg #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/dcraw.hh�������������������������������������������������������������������0000644�0000764�0000764�00000003310�12201145213�015226� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2013 René Rebe * * 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 "Codecs.hh" class DCRAWCodec : public ImageCodec { public: DCRAWCodec () { registerCodec ("dcraw", this); // primary entry registerCodec ("arw", this); // Sony RAW registerCodec ("crw", this); // Canon registerCodec ("cr2", this); registerCodec ("mrw", this); // Mniolta registerCodec ("nef", this); // Nikon registerCodec ("orf", this); // Olympus registerCodec ("raf", this); // Fuji registerCodec ("pef", this); // Pentax registerCodec ("x3f", this); // Sigma registerCodec ("dcr", this); // Kodak registerCodec ("kdc", this); registerCodec ("raw", this); // Panasonic, Casio, Leica registerCodec ("rw2", this); // Panasonic registerCodec ("srf", this); // Sony registerCodec ("sr2", this); // Sony2 }; virtual std::string getID () { return "DCRAW"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/pnm.hh���������������������������������������������������������������������0000644�0000764�0000764�00000002224�11455333500�014733� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2010 René Rebe * * 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 "Codecs.hh" class PNMCodec : public ImageCodec { public: PNMCodec () { registerCodec ("pnm", this); registerCodec ("ppm", this); registerCodec ("pgm", this); registerCodec ("pbm", this); }; virtual std::string getID () { return "PNM"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); }; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/png.hh���������������������������������������������������������������������0000644�0000764�0000764�00000002045�11343547354�014740� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2008 René Rebe * * 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 "Codecs.hh" class PNGCodec : public ImageCodec { public: PNGCodec () { registerCodec ("png", this); }; virtual std::string getID () { return "PNG"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/transupp.h�����������������������������������������������������������������0000644�0000764�0000764�00000021057�10711335714�015655� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * transupp.h * * Copyright (C) 1997-2001, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file contains declarations for image transformation routines and * other utility code used by the jpegtran sample application. These are * NOT part of the core JPEG library. But we keep these routines separate * from jpegtran.c to ease the task of maintaining jpegtran-like programs * that have other user interfaces. * * NOTE: all the routines declared here have very specific requirements * about when they are to be executed during the reading and writing of the * source and destination files. See the comments in transupp.c, or see * jpegtran.c for an example of correct usage. */ /* If you happen not to want the image transform support, disable it here */ #ifndef TRANSFORMS_SUPPORTED #define TRANSFORMS_SUPPORTED 1 /* 0 disables transform code */ #endif /* * Although rotating and flipping data expressed as DCT coefficients is not * hard, there is an asymmetry in the JPEG format specification for images * whose dimensions aren't multiples of the iMCU size. The right and bottom * image edges are padded out to the next iMCU boundary with junk data; but * no padding is possible at the top and left edges. If we were to flip * the whole image including the pad data, then pad garbage would become * visible at the top and/or left, and real pixels would disappear into the * pad margins --- perhaps permanently, since encoders & decoders may not * bother to preserve DCT blocks that appear to be completely outside the * nominal image area. So, we have to exclude any partial iMCUs from the * basic transformation. * * Transpose is the only transformation that can handle partial iMCUs at the * right and bottom edges completely cleanly. flip_h can flip partial iMCUs * at the bottom, but leaves any partial iMCUs at the right edge untouched. * Similarly flip_v leaves any partial iMCUs at the bottom edge untouched. * The other transforms are defined as combinations of these basic transforms * and process edge blocks in a way that preserves the equivalence. * * The "trim" option causes untransformable partial iMCUs to be dropped; * this is not strictly lossless, but it usually gives the best-looking * result for odd-size images. Note that when this option is active, * the expected mathematical equivalences between the transforms may not hold. * (For example, -rot 270 -trim trims only the bottom edge, but -rot 90 -trim * followed by -rot 180 -trim trims both edges.) * * We also offer a lossless-crop option, which discards data outside a given * image region but losslessly preserves what is inside. Like the rotate and * flip transforms, lossless crop is restricted by the JPEG format: the upper * left corner of the selected region must fall on an iMCU boundary. If this * does not hold for the given crop parameters, we silently move the upper left * corner up and/or left to make it so, simultaneously increasing the region * dimensions to keep the lower right crop corner unchanged. (Thus, the * output image covers at least the requested region, but may cover more.) * * If both crop and a rotate/flip transform are requested, the crop is applied * last --- that is, the crop region is specified in terms of the destination * image. * * We also offer a "force to grayscale" option, which simply discards the * chrominance channels of a YCbCr image. This is lossless in the sense that * the luminance channel is preserved exactly. It's not the same kind of * thing as the rotate/flip transformations, but it's convenient to handle it * as part of this package, mainly because the transformation routines have to * be aware of the option to know how many components to work on. */ /* Short forms of external names for systems with brain-damaged linkers. */ #ifdef NEED_SHORT_EXTERNAL_NAMES #define jtransform_parse_crop_spec jTrParCrop #define jtransform_request_workspace jTrRequest #define jtransform_adjust_parameters jTrAdjust #define jtransform_execute_transform jTrExec #define jtransform_perfect_transform jTrPerfect #define jcopy_markers_setup jCMrkSetup #define jcopy_markers_execute jCMrkExec #endif /* NEED_SHORT_EXTERNAL_NAMES */ /* * Codes for supported types of image transformations. */ typedef enum { JXFORM_NONE, /* no transformation */ JXFORM_FLIP_H, /* horizontal flip */ JXFORM_FLIP_V, /* vertical flip */ JXFORM_TRANSPOSE, /* transpose across UL-to-LR axis */ JXFORM_TRANSVERSE, /* transpose across UR-to-LL axis */ JXFORM_ROT_90, /* 90-degree clockwise rotation */ JXFORM_ROT_180, /* 180-degree rotation */ JXFORM_ROT_270 /* 270-degree clockwise (or 90 ccw) */ } JXFORM_CODE; /* * Codes for crop parameters, which can individually be unspecified, * positive, or negative. (Negative width or height makes no sense, though.) */ typedef enum { JCROP_UNSET, JCROP_POS, JCROP_NEG } JCROP_CODE; /* * Transform parameters struct. * NB: application must not change any elements of this struct after * calling jtransform_request_workspace. */ typedef struct { /* Options: set by caller */ JXFORM_CODE transform; /* image transform operator */ boolean perfect; /* if TRUE, fail if partial MCUs are requested */ boolean trim; /* if TRUE, trim partial MCUs as needed */ boolean force_grayscale; /* if TRUE, convert color image to grayscale */ boolean crop; /* if TRUE, crop source image */ /* Crop parameters: application need not set these unless crop is TRUE. * These can be filled in by jtransform_parse_crop_spec(). */ JDIMENSION crop_width; /* Width of selected region */ JCROP_CODE crop_width_set; JDIMENSION crop_height; /* Height of selected region */ JCROP_CODE crop_height_set; JDIMENSION crop_xoffset; /* X offset of selected region */ JCROP_CODE crop_xoffset_set; /* (negative measures from right edge) */ JDIMENSION crop_yoffset; /* Y offset of selected region */ JCROP_CODE crop_yoffset_set; /* (negative measures from bottom edge) */ /* Internal workspace: caller should not touch these */ int num_components; /* # of components in workspace */ jvirt_barray_ptr * workspace_coef_arrays; /* workspace for transformations */ JDIMENSION output_width; /* cropped destination dimensions */ JDIMENSION output_height; JDIMENSION x_crop_offset; /* destination crop offsets measured in iMCUs */ JDIMENSION y_crop_offset; int max_h_samp_factor; /* destination iMCU size */ int max_v_samp_factor; } jpeg_transform_info; #if TRANSFORMS_SUPPORTED /* Parse a crop specification (written in X11 geometry style) */ EXTERN(boolean) jtransform_parse_crop_spec JPP((jpeg_transform_info *info, const char *spec)); /* Request any required workspace */ EXTERN(void) jtransform_request_workspace JPP((j_decompress_ptr srcinfo, jpeg_transform_info *info)); /* Adjust output image parameters */ EXTERN(jvirt_barray_ptr *) jtransform_adjust_parameters JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info)); /* Execute the actual transformation, if any */ EXTERN(void) jtransform_execute_transform JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, jvirt_barray_ptr *src_coef_arrays, jpeg_transform_info *info)); /* Determine whether lossless transformation is perfectly * possible for a specified image and transformation. */ EXTERN(boolean) jtransform_perfect_transform JPP((JDIMENSION image_width, JDIMENSION image_height, int MCU_width, int MCU_height, JXFORM_CODE transform)); /* jtransform_execute_transform used to be called * jtransform_execute_transformation, but some compilers complain about * routine names that long. This macro is here to avoid breaking any * old source code that uses the original name... */ #define jtransform_execute_transformation jtransform_execute_transform #endif /* TRANSFORMS_SUPPORTED */ /* * Support for copying optional markers from source to destination file. */ typedef enum { JCOPYOPT_NONE, /* copy no optional markers */ JCOPYOPT_COMMENTS, /* copy only comment (COM) markers */ JCOPYOPT_ALL /* copy all optional markers */ } JCOPY_OPTION; #define JCOPYOPT_DEFAULT JCOPYOPT_COMMENTS /* recommended default */ /* Setup decompression object to save desired markers in memory */ EXTERN(void) jcopy_markers_setup JPP((j_decompress_ptr srcinfo, JCOPY_OPTION option)); /* Copy markers saved in the given source object to the destination object */ EXTERN(void) jcopy_markers_execute JPP((j_decompress_ptr srcinfo, j_compress_ptr dstinfo, JCOPY_OPTION option)); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/jpeg.cc��������������������������������������������������������������������0000644�0000764�0000764�00000066125�12455537722�015103� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2015 René Rebe * (C) 2006, 2007 Archivista GmbH, CH-8042 Zuerich * * 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 <stdio.h> #include <stdlib.h> #include <string.h> #include <string> #include <iostream> #include <fstream> #include <setjmp.h> // optional error recovery #include "jpeg.hh" #include "crop.hh" #include "scale.hh" #include "rotate.hh" #include "Endianess.hh" /* * ERROR HANDLING: * * The JPEG library's standard error handler (jerror.c) is divided into * several "methods" which you can override individually. This lets you * adjust the behavior without duplicating a lot of code, which you might * have to update with each future release. * * Our example here shows how to override the "error_exit" method so that * control is returned to the library's caller when a fatal error occurs, * rather than calling exit() as the standard error_exit method does. * * We use C's setjmp/longjmp facility to return control. This means that the * routine which calls the JPEG library must first execute a setjmp() call to * establish the return point. We want the replacement error_exit to do a * longjmp(). But we need to make the setjmp buffer accessible to the * error_exit routine. To do this, we make a private extension of the * standard JPEG error handler object. * * Here's the extended error handler struct: */ struct my_error_mgr { struct jpeg_error_mgr pub; /* "public" fields */ jmp_buf setjmp_buffer; /* for return to caller */ }; typedef struct my_error_mgr* my_error_ptr; /* * Here's the routine that will replace the standard error_exit method: */ METHODDEF(void) my_error_exit (j_common_ptr cinfo) { /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ my_error_ptr myerr = (my_error_ptr) cinfo->err; /* Always display the message. */ /* We could postpone this until after returning, if we chose. */ (*cinfo->err->output_message) (cinfo); /* Return control to the setjmp point */ longjmp(myerr->setjmp_buffer, 1); } void jpeg_compress_set_density (jpeg_compress_struct* dstinfo, const Image& image) { dstinfo->JFIF_minor_version = 2; // emit JFIF 1.02 extension markers ... if (image.resolutionX() == 0 || image.resolutionY() == 0) { dstinfo->density_unit = 0; /* unknown */ dstinfo->X_density = dstinfo->Y_density = 0; } else { dstinfo->density_unit = 1; /* 1 for dots/inch */ dstinfo->X_density = image.resolutionX(); dstinfo->Y_density = image.resolutionY(); } } /* *** source manager *** */ typedef struct { struct jpeg_source_mgr pub; /* public fields */ std::istream* stream; JOCTET* buffer; /* start of buffer */ bool start_of_file; /* have we gotten any data yet? */ } cpp_src_mgr; #define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ static void init_source (j_decompress_ptr cinfo) { cpp_src_mgr* src = (cpp_src_mgr*) cinfo->src; src->start_of_file = true; } boolean fill_input_buffer (j_decompress_ptr cinfo) { cpp_src_mgr* src = (cpp_src_mgr*) cinfo->src; size_t nbytes = src->stream->tellg (); src->stream->read ((char*)src->buffer, INPUT_BUF_SIZE); // if only a partial buffer was read, reset the state to be able // to get the new file position if (!*src->stream) src->stream->clear(); nbytes = (size_t)src->stream->tellg () - nbytes; if (nbytes <= 0) { if (src->start_of_file) /* Treat empty input file as fatal error */ ERREXIT(cinfo, JERR_INPUT_EMPTY); WARNMS(cinfo, JWRN_JPEG_EOF); /* Insert a fake EOI marker */ src->buffer[0] = (JOCTET) 0xFF; src->buffer[1] = (JOCTET) JPEG_EOI; nbytes = 2; } src->pub.next_input_byte = src->buffer; src->pub.bytes_in_buffer = nbytes; src->start_of_file = FALSE; return (boolean)TRUE; } void skip_input_data (j_decompress_ptr cinfo, long num_bytes) { cpp_src_mgr* src = (cpp_src_mgr*) cinfo->src; if (num_bytes > 0) { while (num_bytes > (long) src->pub.bytes_in_buffer) { num_bytes -= (long) src->pub.bytes_in_buffer; (void) fill_input_buffer(cinfo); /* note we assume that fill_input_buffer will never return FALSE, * so suspension need not be handled. */ } src->pub.next_input_byte += (size_t) num_bytes; src->pub.bytes_in_buffer -= (size_t) num_bytes; } } void term_source (j_decompress_ptr cinfo) { /* no work necessary here */ free (((cpp_src_mgr*)cinfo->src)->buffer); free (cinfo->src); } void cpp_stream_src (j_decompress_ptr cinfo, std::istream* stream) { cpp_src_mgr* src; if (cinfo->src == NULL) { /* first time for this JPEG object? */ cinfo->src = (jpeg_source_mgr*) malloc (sizeof(cpp_src_mgr)); src = (cpp_src_mgr*) cinfo->src; src->buffer = (JOCTET*) malloc (INPUT_BUF_SIZE * sizeof(JOCTET)); } src = (cpp_src_mgr*) cinfo->src; src->pub.init_source = init_source; src->pub.fill_input_buffer = fill_input_buffer; src->pub.skip_input_data = skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ src->pub.term_source = term_source; src->stream = stream; src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ src->pub.next_input_byte = NULL; /* until buffer loaded */ } /* *** destination manager *** */ typedef struct { struct jpeg_destination_mgr pub; /* public fields */ std::ostream* stream; /* target stream */ JOCTET* buffer; /* start of buffer */ } cpp_dest_mgr; #define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ void init_destination (j_compress_ptr cinfo) { cpp_dest_mgr* dest = (cpp_dest_mgr*) cinfo->dest; /* Allocate the output buffer --- it will be released when done with image */ dest->buffer = (JOCTET*) (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, OUTPUT_BUF_SIZE * sizeof(JOCTET)); dest->pub.next_output_byte = dest->buffer; dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; } boolean empty_output_buffer (j_compress_ptr cinfo) { cpp_dest_mgr* dest = (cpp_dest_mgr*) cinfo->dest; dest->stream->write ((char*)dest->buffer, OUTPUT_BUF_SIZE); if (!*dest->stream) ERREXIT(cinfo, JERR_FILE_WRITE); dest->pub.next_output_byte = dest->buffer; dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; return (boolean)TRUE; } void term_destination (j_compress_ptr cinfo) { cpp_dest_mgr* dest = (cpp_dest_mgr*) cinfo->dest; size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; /* Write any data remaining in the buffer */ if (datacount > 0) { dest->stream->write ((char*)dest->buffer, datacount); if (!*dest->stream) ERREXIT(cinfo, JERR_FILE_WRITE); } dest->stream->flush (); /* Make sure we wrote the output file OK */ if (!*dest->stream) ERREXIT(cinfo, JERR_FILE_WRITE); free (cinfo->dest); } void cpp_stream_dest (j_compress_ptr cinfo, std::ostream* stream) { cpp_dest_mgr* dest; /* first time for this JPEG object? */ if (cinfo->dest == NULL) { cinfo->dest = (struct jpeg_destination_mgr *) malloc (sizeof(cpp_dest_mgr)); } dest = (cpp_dest_mgr*) cinfo->dest; dest->pub.init_destination = init_destination; dest->pub.empty_output_buffer = empty_output_buffer; dest->pub.term_destination = term_destination; dest->stream = stream; } /* *** back on-topic *** */ JPEGCodec::JPEGCodec (Image* _image) : ImageCodec (_image) { } int JPEGCodec::readImage (std::istream* stream, Image& image, const std::string& decompres) { if (stream->peek () != 0xFF) return false; stream->get (); // consume silently if (stream->peek () != 0xD8) return false; if (0) { // TODO: differentiate JFIF vs. Exif? // quick magic check char buf [10]; stream->read (buf, sizeof (buf)); stream->seekg (0); if (buf[6] != 'J' || buf[7] != 'F' || buf[8] != 'I' || buf[9] != 'F') return false; } if (!readMeta (stream, image)) return false; // on-demand compression image.setRawData (0); // freestanding instance JPEGCodec* codec = new JPEGCodec(&image); image.setCodec(codec); // private copy for deferred decoding //private_copy.str().resize(stream->tellg()); stream->clear (); stream->seekg (0); *stream >> codec->private_copy.rdbuf(); // parse Exif data, might contain non-identifiy orientation transform codec->parseExif(image); return true; } bool JPEGCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { std::string c (compress); std::transform (c.begin(), c.end(), c.begin(), tolower); // if the instance is freestanding it can only be called by the mux // if the cache is valid if (_image && c != "recompress") { // if meta information was modified re-encode the stream if (image.isMetaModified()) { std::cerr << "Re-encoding DCT coefficients (due meta changes)." << std::endl; doTransform (JXFORM_NONE, image, stream); } else { std::cerr << "Writing unmodified DCT buffer." << std::endl; *stream << private_copy.str(); } return true; } // really encode struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW buffer[1]; // pointer to JSAMPLE row[s] // Initialize the JPEG compression object with default error handling. cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); cpp_stream_dest (&cinfo, stream); cinfo.in_color_space = JCS_UNKNOWN; if (image.bps == 8 && image.spp == 3) cinfo.in_color_space = JCS_RGB; else if (image.bps == 8 && image.spp == 1) cinfo.in_color_space = JCS_GRAYSCALE; else if (image.bps == 8 && image.spp == 4) cinfo.in_color_space = JCS_CMYK; if (cinfo.in_color_space == JCS_UNKNOWN) { if (image.bps < 8) std::cerr << "JPEGCodec: JPEG can not hold less than 8 bit-per-channel." << std::endl; else std::cerr << "Unhandled bps/spp combination." << std::endl; jpeg_destroy_compress(&cinfo); return false; } cinfo.image_width = image.w; cinfo.image_height = image.h; cinfo.input_components = image.spp; cinfo.data_precision = image.bps; // defaults depending on in_color_space jpeg_set_defaults(&cinfo); jpeg_compress_set_density (&cinfo, image); jpeg_set_quality(&cinfo, quality, (boolean)FALSE); // do not limit to baseline-JPEG values // Start compressor jpeg_start_compress(&cinfo, (boolean)TRUE); // Process data while (cinfo.next_scanline < cinfo.image_height) { buffer[0] = (JSAMPLE*) image.getRawData() + cinfo.next_scanline*image.stride(); (void) jpeg_write_scanlines(&cinfo, buffer, 1); } // Finish compression and release memory jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); if (jerr.num_warnings) std::cerr << jerr.num_warnings << " Warnings." << std::endl; return true; } template<typename T> T readExif(const void* raw_ptr, const bool big_endian) { const T v = *(const T*)raw_ptr; using namespace Exact; if (big_endian) return ByteSwap<BigEndianTraits, NativeEndianTraits, T>::Swap(v); else return ByteSwap<LittleEndianTraits, NativeEndianTraits, T>::Swap(v); } void JPEGCodec::parseExif (Image& image) { // for now we're only interested in the orientation tag // TODO: parse, provide and re-write the whole meta data const std::string& exif_data_p = private_copy.str(); const uint8_t* exif_data = (uint8_t*)exif_data_p.c_str(); // check for JPEG SOI + Exif APP1 if (exif_data[0] != 0xFF || exif_data[1] != 0xD8) return; // check "Exif" header for (int offset = 2; offset <= 20; offset = 20) { if (exif_data[offset+0] == 0xFF && exif_data[offset+1] == 0xE1 && exif_data[offset+4] == 'E' && exif_data[offset+5] == 'x' && exif_data[offset+6] == 'i' && exif_data[offset+7] == 'f' && exif_data[offset+8] == 0 && exif_data[offset+9] == 0) { exif_data += offset; break; } if (offset == 20) return; } // Get the marker parameter length count uint16_t length = readExif<uint16_t>(exif_data + 2, true); // always big-endian if (length > exif_data_p.size()) { std::cerr << "Exif header length limitted" << std::endl; length = exif_data_p.size(); } // length includes itself, so must be at least 2 + Exif data length must be at least 6 if (length < 8) return; length -= 8; if (length < 12) return; // length of an IFD entry exif_data += 10; // honor byte order bool big_endian; if (exif_data[0] == 0x49 && exif_data[1] == 0x49) big_endian = false; else if (exif_data[0] == 0x4D && exif_data[1] == 0x4D) big_endian = true; else return; // Check tag mark if (big_endian) { if (exif_data[2] != 0 || exif_data[3] != 0x2A) return; } else { if (exif_data[3] != 0 || exif_data[2] != 0x2A) return; } // get first IFD offset (offset to IFD0) unsigned offset = readExif<uint32_t>(exif_data + 4, big_endian); if (offset > length - 2) return; // check end of data segment // get the number of directory entries contained in this IFD unsigned number_of_tags = readExif<uint16_t>(exif_data + offset, big_endian); if (number_of_tags == 0) return; offset += 2; // search for orientation tag in IFD0 uint16_t orientation = 0, unit = 0; uint32_t xres = 0, yres = 0; for (; number_of_tags > 0; --number_of_tags, offset += 12) { if (offset > length - 12) break; // check end of data segment // get tag number uint16_t tag = readExif<uint16_t>(exif_data + offset, big_endian); uint16_t type = readExif<uint16_t>(exif_data + offset + 2, big_endian); uint32_t count = readExif<uint32_t>(exif_data + offset + 4, big_endian); uint32_t value = readExif<uint32_t>(exif_data + offset + 8, big_endian); //std::cerr << std::hex << tag << std::dec << " " << type << " " << count << " " << value << std::endl; // global range check if ((type == 5 || type == 10) && (value + 4 >= length) || // RATIONAL (type == 2 && count > 4 && value + count >= length)) // ASCII, could be short { std::cerr << "Exif tag index out of range, skipped." << std::endl; continue; } if (tag == 0x011a) // xres { uint32_t x = readExif<uint32_t>(exif_data + value, big_endian); //y = readExif<uint32_t>(exif_data + value + 4, big_endian); xres = x; } else if (tag == 0x011b) // yres { uint32_t x = readExif<uint32_t>(exif_data + value, big_endian); //y = readExif<uint32_t>(exif_data + value + 4, big_endian); yres = x; } else if (tag == 0x0128) // unit { uint16_t u = readExif<uint16_t>(exif_data + offset + 8, big_endian); if (unit != 0) std::cerr << "Exif unit already set?" << std::endl; if (u == 2 || u == 3) // inch, cm unit = u; else std::cerr << "Exif unit invalid: " << u << std::endl; } if (tag == 0x0112) // orientation tag { uint16_t o = readExif<uint16_t>(exif_data + offset + 8, big_endian); if (orientation != 0) std::cerr << "Exif orientation already set?" << std::endl; if (o <= 8) orientation = o; else std::cerr << "Exif orientation invalid: " << o << std::endl; } } if (xres || yres) { if (unit == 0) unit = 2; // inches if (xres == 0) xres = yres; // if one is zero, set it, too else if (yres == 0) yres = xres; if (unit == 3) { // scale cm to inch xres = xres * 254 / 100; yres = yres * 254 / 100; } // was already set? if (image.resolutionX() == 0 && image.resolutionY() == 0) { image.setResolution(xres, yres); } else { if (image.resolutionX() != xres || image.resolutionY() != yres) std::cerr << "Exif resolution differs from codec: " << xres << "x" << yres << " vs. " << image.resolutionX() << "x" << image.resolutionY() << std::endl; } } exif_rotate(image, orientation); } // on-demand decoding /*bool*/ void JPEGCodec::decodeNow (Image* image) { // std::cerr << "JPEGCodec::decodeNow" << std::endl; // decode without scaling decodeNow (image, 1); } /*bool*/ void JPEGCodec::decodeNow (Image* image, int factor) { struct jpeg_decompress_struct* cinfo = new jpeg_decompress_struct; struct my_error_mgr jerr; // Step 1: allocate and initialize JPEG decompression object // We set up the normal JPEG error routines, then override error_exit. cinfo->err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; // Establish the setjmp return context for my_error_exit to use. if (setjmp(jerr.setjmp_buffer)) { // If we get here, the JPEG code has signaled an error. // We need to clean up the JPEG object, close the input file, and return. jpeg_destroy_decompress (cinfo); return; } jpeg_create_decompress (cinfo); // Step 2: specify data source (eg, a file) private_copy.seekg (0); cpp_stream_src (cinfo, &private_copy); // Step 3: read file parameters with jpeg_read_header() jpeg_read_header(cinfo, (boolean)TRUE); // Step 4: set parameters for decompression cinfo->buffered_image = (boolean)TRUE; // select buffered-image mode // TODO: set scaling if (factor != 1) { cinfo->scale_num = 1; cinfo->scale_denom = factor; cinfo->dct_method = JDCT_IFAST; } // Step 5: Start decompressor jpeg_start_decompress (cinfo); image->w = cinfo->output_width; image->h = cinfo->output_height; // JSAMPLEs per row in output buffer int row_stride = cinfo->output_width * cinfo->output_components; image->resize (image->w, image->h); // Step 6: jpeg_read_scanlines(...) uint8_t* data = image->getRawData (); JSAMPROW buffer[1]; // pointer to JSAMPLE row[s] while (! jpeg_input_complete(cinfo)) { jpeg_start_output(cinfo, cinfo->input_scan_number); while (cinfo->output_scanline < cinfo->output_height) { // jpeg_read_scanlines expects an array of pointers to scanlines. // Here the array is only one element long, but you could ask for // more than one scanline at a time if that's more convenient. buffer[0] = (JSAMPLE*) data+ (cinfo->output_scanline*row_stride); jpeg_read_scanlines(cinfo, buffer, 1); } jpeg_finish_output(cinfo); } jpeg_finish_decompress(cinfo); jpeg_destroy_decompress(cinfo); delete (cinfo); // shadow data is still valid for more transformations image->setCodec (this); } // in any case (we do not want artefacts): transformoption.trim = TRUE; bool JPEGCodec::flipX (Image& image) { return doTransform (JXFORM_FLIP_H, image); } bool JPEGCodec::flipY (Image& image) { return doTransform (JXFORM_FLIP_V, image); } bool JPEGCodec::rotate (Image& image, double angle) { // so rotate if the first fraction is zero switch ((int)(angle * 10)) { case 900: return doTransform (JXFORM_ROT_90, image); case 1800: return doTransform (JXFORM_ROT_180, image); case 2700: return doTransform (JXFORM_ROT_270, image); default: ; // no acceleration, fall thru } return false; } bool JPEGCodec::crop (Image& image, unsigned int x, unsigned int y, unsigned int w, unsigned int h) { doTransform (JXFORM_NONE, image, 0 /* stream */, false /* to gray */, true /* crop */, x, y, w, h); // reminder of 8x8 JPEG block crop x %= 8; y %= 8; if (x || y) { // invalidate, otherwise the ::crop() does call us again image.setRawData(); // global crop, not our method ::crop(image, x, y, w, h); } return true; } bool JPEGCodec::toGray (Image& image) { return doTransform (JXFORM_NONE, image, 0 /* stream */, true /* to gray */); } bool JPEGCodec::scale (Image& image, double xscale, double yscale) { // we only support fast downscaling if (xscale > 1.0 || yscale > 1.0) return false; // let the generic scaler handle this int w_final = (int)(xscale * image.w); int h_final = (int)(xscale * image.h); std::cerr << "Scaling by partially loading DCT coefficients." << std::endl; // compute downscale factor int scale = (int) (xscale > yscale ? 1./xscale : 1./yscale); if (scale > 8) scale = 8; else if (scale < 1) scale = 1; // we get values in the range [1,8] here, but libjpeg only // supports [1,2,4,8] - others are rounded down decodeNow (&image, scale); // due downscaling the private copy is no longer valid image.setRawData (); // TODO: test if we can just read the coefficients // we only have scaled in the range [1,2,4,8] and need to do the rest // manually xscale = (double)w_final / image.w; yscale = (double)h_final / image.h; if (xscale != 1.0 || yscale != 1.0) box_scale (image, xscale, yscale); return true; } bool JPEGCodec::readMeta (std::istream* stream, Image& image) { stream->seekg (0); struct jpeg_decompress_struct* cinfo = new jpeg_decompress_struct; struct my_error_mgr jerr; // Step 1: allocate and initialize JPEG decompression object // We set up the normal JPEG error routines, then override error_exit. cinfo->err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; // Establish the setjmp return context for my_error_exit to use. if (setjmp(jerr.setjmp_buffer)) { // If we get here, the JPEG code has signaled an error. // We need to clean up the JPEG object, close the input file, and return. jpeg_destroy_decompress (cinfo); free (cinfo); return false; } jpeg_create_decompress (cinfo); // Step 2: specify data source (eg, a file) cpp_stream_src (cinfo, stream); // Step 3: read file parameters with jpeg_read_header() jpeg_read_header(cinfo, (boolean)TRUE); // Step 4: set parameters for decompression cinfo->buffered_image = (boolean)TRUE; /* select buffered-image mode */ // Step 5: Start decompressor jpeg_start_decompress (cinfo); image.w = cinfo->output_width; image.h = cinfo->output_height; image.spp = cinfo->output_components; image.bps = 8; // These three values are not used by the JPEG code, merely copied // into the JFIF APP0 marker. JFIF code for pixel size units. switch (cinfo->density_unit) { case 1: // dots/inch image.setResolution(cinfo->X_density, cinfo->Y_density); break; case 2: // dots/cm image.setResolution(cinfo->X_density * 254 / 100, cinfo->Y_density * 254 / 100); break; default: // 0 for unknown, ratio may still be defined image.setResolution(0, 0); } // This is an important step since it will release a good deal of memory. jpeg_finish_decompress(cinfo); jpeg_destroy_decompress(cinfo); delete (cinfo); return true; } bool JPEGCodec::doTransform (JXFORM_CODE code, Image& image, std::ostream* s, bool to_gray, bool crop, unsigned int x, unsigned int y, unsigned int w, unsigned int h) { jpeg_transform_info transformoption = {}; // image transformation options jpeg_decompress_struct srcinfo; jpeg_compress_struct dstinfo; jpeg_error_mgr jsrcerr, jdsterr; std::cerr << "Transforming DCT coefficients." << std::endl; jvirt_barray_ptr* src_coef_arrays; jvirt_barray_ptr* dst_coef_arrays; // Initialize the JPEG decompression object with default error handling. srcinfo.err = jpeg_std_error(&jsrcerr); jpeg_create_decompress(&srcinfo); // Initialize the JPEG compression object with default error handling. dstinfo.err = jpeg_std_error(&jdsterr); // Initialize the JPEG compression object with default error handling. jpeg_create_compress(&dstinfo); srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use; private_copy.seekg (0); cpp_stream_src (&srcinfo, &private_copy); // Read file header jpeg_read_header(&srcinfo, (boolean)TRUE); transformoption.transform = code; transformoption.trim = (boolean)TRUE; transformoption.perfect = (boolean)FALSE; transformoption.force_grayscale = (boolean)(to_gray ? TRUE : FALSE); transformoption.crop = (boolean)(crop ? TRUE : FALSE); if (crop) { transformoption.crop_xoffset = x; transformoption.crop_xoffset_set = JCROP_POS; transformoption.crop_yoffset = y; transformoption.crop_yoffset_set = JCROP_POS; transformoption.crop_width = w; transformoption.crop_width_set = JCROP_POS; transformoption.crop_height = h; transformoption.crop_height_set = JCROP_POS; } // Any space needed by a transform option must be requested before // jpeg_read_coefficients so that memory allocation will be done right. jtransform_request_workspace(&srcinfo, &transformoption); // Read source file as DCT coefficients src_coef_arrays = jpeg_read_coefficients(&srcinfo); // Initialize destination compression parameters from source values jpeg_copy_critical_parameters(&srcinfo, &dstinfo); // Adjust destination parameters if required by transform options; // also find out which set of coefficient arrays will hold the output. if (transformoption.transform != JXFORM_NONE || transformoption.force_grayscale || transformoption.crop) dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); else dst_coef_arrays = src_coef_arrays; // Specify data destination for compression std::stringstream stream; if (!s) stream.str().reserve(private_copy.str().size()); cpp_stream_dest (&dstinfo, s ? s : &stream); jpeg_compress_set_density (&dstinfo, image); // Start compressor (note no image data is actually written here) jpeg_write_coefficients(&dstinfo, dst_coef_arrays); // Execute image transformation, if any jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); // Finish compression and release memory jpeg_finish_compress(&dstinfo); jpeg_destroy_compress(&dstinfo); jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); // if we are not just writing if (!s) { // copy into the shadow buffer private_copy.str (stream.str()); // if the data is accessed again, it must be re-encoded image.setRawData(0); image.setCodec(this); // Update meta: w, h, spp might have changed. image.w = transformoption.output_width; image.h = transformoption.output_height; // avoid the expensive readMeta for some cases switch (code) { case JXFORM_ROT_90: case JXFORM_ROT_270: image.setResolution(image.resolutionX(), image.resolutionY()); image.setCodec(this); case JXFORM_ROT_180: case JXFORM_FLIP_H: case JXFORM_FLIP_V: default: ; // silence compiler } if (to_gray) { image.spp = 1; } // We re-read the header because we do not want to re-hardcode the // trimming required for all the other corner cases. //std::cerr << "Re-reading meta data." << std::endl; //readMeta (&private_copy, image); //image.setCodec(this); } return true; } JPEGCodec jpeg_loader; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/pnm.cc���������������������������������������������������������������������0000644�0000764�0000764�00000014112�12460712237�014725� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2015 René Rebe * * 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. */ /* * C++ PNM library. * * I former times we used to use the netbpm library here, but as * it can not handle in memory or otherwise transferred files, allowing * access via the C FILE* exclusively (???!!!) we had to write our * own parser here ... * */ #include <string.h> // memcpy #include <iostream> #include <string> #include <sstream> #ifdef _MSC_VER #include <vector> #endif #include "pnm.hh" #include "Endianess.hh" using namespace Exact; int getNextHeaderNumber (std::istream* stream) { for (bool whitespace = true; whitespace && stream;) { int c = stream->peek(); switch (c) { case ' ': stream->get(); // consume silently break; case '\n': case '\r': stream->get(); // consume silently // comment line? while (stream->peek() == '#') { std::string str; std::getline(*stream, str); // consume comment line } break; default: whitespace = false; } } int i; *stream >> i; return i; } int PNMCodec::readImage (std::istream* stream, Image& image, const std::string& decompres) { // check signature if (stream->peek () != 'P') return false; stream->get(); // consume P image.bps = 0; char mode = stream->peek(); switch (mode) { case '1': case '4': image.bps = 1; case '2': case '5': image.spp = 1; break; case '3': case '6': image.spp = 3; break; default: stream->unget(); // P return false; } stream->get(); // consume format number image.w = getNextHeaderNumber (stream); image.h = getNextHeaderNumber (stream); int maxval = 1; if (image.bps != 1) { maxval = getNextHeaderNumber (stream); } image.bps = 1; while ((1 << image.bps) < maxval) ++image.bps; // not stored in the format :-( image.setResolution(0, 0); // allocate data, if necessary image.resize (image.w, image.h); // consume the left over spaces and newline 'till the data begins { std::string str; std::getline (*stream, str); } if (mode <= '3') // ascii / plain text { Image::iterator it = image.begin (); for (int y = 0; y < image.h; ++y) { for (int x = 0; x < image.w; ++x) { if (image.spp == 1) { int i; *stream >> i; i = i * (255 / maxval); // only mode 1 is defined with 1 == black, ... if (mode == '1') i = 255 - i; it.setL (i); } else { uint16_t r, g, b; *stream >> r >> g >> b; it.setRGB (r, g, b); } it.set (it); ++it; } } } else // binary data { const int stride = image.stride (); const int bps = image.bps; for (int y = 0; y < image.h; ++y) { uint8_t* dest = image.getRawData() + y * stride; stream->read ((char*)dest, stride); // is it publically defined somewhere??? if (bps == 1) { uint8_t* xor_ptr = dest; for (int x = 0; x < image.w; x += 8) *xor_ptr++ ^= 0xff; } if (bps == 16) { uint16_t* swap_ptr = (uint16_t*)dest; for (int x = 0; x < stride/2; ++x, ++swap_ptr) *swap_ptr = ByteSwap<NativeEndianTraits,BigEndianTraits, uint16_t>::Swap (*swap_ptr); } } } return true; } bool PNMCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { // ok writing should be easy ,-) just dump the header // and the data thereafter ,-) int format = 0; if (image.spp == 1 && image.bps == 1) format = 1; else if (image.spp == 1) format = 2; else if (image.spp == 3) format = 3; else { std::cerr << "Not (yet?) supported PBM format." << std::endl; return false; } std::string c (compress); std::transform (c.begin(), c.end(), c.begin(), tolower); if (c == "plain") c = "ascii"; if (c != "ascii") format += 3; *stream << "P" << format << std::endl; *stream << "# http://exactcode.com/oss/exactimage/" << std::endl; *stream << image.w << " " << image.h << std::endl; // maxval const int maxval = (1 << image.bps) - 1; const int divval = image.bps < 8 ? 255 / maxval : 1; if (image.bps > 1) *stream << maxval << std::endl; Image::iterator it = image.begin (); if (c == "ascii") { for (int y = 0; y < image.h; ++y) { for (int x = 0; x < image.w; ++x, ++it) { if (x != 0) *stream << " "; *it; if (image.spp == 1) { unsigned i = it.getL(); // only mode 1 is defined with 1 == black, ... if (format == 1) i = 255 - i; *stream << i / divval; } else { uint16_t r = 0, g = 0, b = 0; it.getRGB (&r, &g, &b); *stream << (int)r << " " << (int)g << " " << (int)b; } } *stream << std::endl; } } else { const int stride = image.stride(); const int bps = image.bps; #ifndef _MSC_VER uint8_t ptr[stride]; #else std::vector<uint8_t> ptr(stride); #endif for (int y = 0; y < image.h; ++y) { memcpy (&ptr[0], image.getRawData() + y * stride, stride); // is this publically defined somewhere??? if (bps == 1) { uint8_t* xor_ptr = &ptr[0]; for (int x = 0; x < image.w; x += 8) *xor_ptr++ ^= 0xff; } if (bps == 16) { uint16_t* swap_ptr = (uint16_t*)&ptr[0]; for (int x = 0; x < stride/2; ++x, ++swap_ptr) *swap_ptr = ByteSwap<BigEndianTraits, NativeEndianTraits, uint16_t>::Swap (*swap_ptr); } stream->write ((char*)&ptr[0], stride); } } stream->flush (); return true; } PNMCodec pnm_loader; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/jpegint.h������������������������������������������������������������������0000644�0000764�0000764�00000036540�10550751407�015446� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * jpegint.h * * Copyright (C) 1991-1997, Thomas G. Lane. * This file is part of the Independent JPEG Group's software. * For conditions of distribution and use, see the accompanying README file. * * This file provides common declarations for the various JPEG modules. * These declarations are considered internal to the JPEG library; most * applications using the library shouldn't need to include this file. */ /* Declarations for both compression & decompression */ typedef enum { /* Operating modes for buffer controllers */ JBUF_PASS_THRU, /* Plain stripwise operation */ /* Remaining modes require a full-image buffer to have been created */ JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ } J_BUF_MODE; /* Values of global_state field (jdapi.c has some dependencies on ordering!) */ #define CSTATE_START 100 /* after create_compress */ #define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ #define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ #define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ #define DSTATE_START 200 /* after create_decompress */ #define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ #define DSTATE_READY 202 /* found SOS, ready for start_decompress */ #define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ #define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ #define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ #define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ #define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ #define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ #define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ #define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ /* Declarations for compression modules */ /* Master control module */ struct jpeg_comp_master { JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); /* State variables made visible to other modules */ boolean call_pass_startup; /* True if pass_startup must be called */ boolean is_last_pass; /* True during last pass */ }; /* Main buffer control (downsampled-data buffer) */ struct jpeg_c_main_controller { JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, process_data, (j_compress_ptr cinfo, JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail)); }; /* Compression preprocessing (downsampling input buffer control) */ struct jpeg_c_prep_controller { JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, JDIMENSION in_rows_avail, JSAMPIMAGE output_buf, JDIMENSION *out_row_group_ctr, JDIMENSION out_row_groups_avail)); }; /* Coefficient buffer control */ struct jpeg_c_coef_controller { JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, JSAMPIMAGE input_buf)); }; /* Colorspace conversion */ struct jpeg_color_converter { JMETHOD(void, start_pass, (j_compress_ptr cinfo)); JMETHOD(void, color_convert, (j_compress_ptr cinfo, JSAMPARRAY input_buf, JSAMPIMAGE output_buf, JDIMENSION output_row, int num_rows)); }; /* Downsampling */ struct jpeg_downsampler { JMETHOD(void, start_pass, (j_compress_ptr cinfo)); JMETHOD(void, downsample, (j_compress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION in_row_index, JSAMPIMAGE output_buf, JDIMENSION out_row_group_index)); boolean need_context_rows; /* TRUE if need rows above & below */ }; /* Forward DCT (also controls coefficient quantization) */ struct jpeg_forward_dct { JMETHOD(void, start_pass, (j_compress_ptr cinfo)); /* perhaps this should be an array??? */ JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, jpeg_component_info * compptr, JSAMPARRAY sample_data, JBLOCKROW coef_blocks, JDIMENSION start_row, JDIMENSION start_col, JDIMENSION num_blocks)); }; /* Entropy encoding */ struct jpeg_entropy_encoder { JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); }; /* Marker writing */ struct jpeg_marker_writer { JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); /* These routines are exported to allow insertion of extra markers */ /* Probably only COM and APPn markers should be written this way */ JMETHOD(void, write_marker_header, (j_compress_ptr cinfo, int marker, unsigned int datalen)); JMETHOD(void, write_marker_byte, (j_compress_ptr cinfo, int val)); }; /* Declarations for decompression modules */ /* Master control module */ struct jpeg_decomp_master { JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); /* State variables made visible to other modules */ boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ }; /* Input control module */ struct jpeg_input_controller { JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); /* State variables made visible to other modules */ boolean has_multiple_scans; /* True if file has multiple scans */ boolean eoi_reached; /* True when EOI has been consumed */ }; /* Main buffer control (downsampled-data buffer) */ struct jpeg_d_main_controller { JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, process_data, (j_decompress_ptr cinfo, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); }; /* Coefficient buffer control */ struct jpeg_d_coef_controller { JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); /* Pointer to array of coefficient virtual arrays, or NULL if none */ jvirt_barray_ptr *coef_arrays; }; /* Decompression postprocessing (color quantization buffer control) */ struct jpeg_d_post_controller { JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); }; /* Marker reading & parsing */ struct jpeg_marker_reader { JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); /* Read markers until SOS or EOI. * Returns same codes as are defined for jpeg_consume_input: * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. */ JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); /* Read a restart marker --- exported for use by entropy decoder only */ jpeg_marker_parser_method read_restart_marker; /* State of marker reader --- nominally internal, but applications * supplying COM or APPn handlers might like to know the state. */ boolean saw_SOI; /* found SOI? */ boolean saw_SOF; /* found SOF? */ int next_restart_num; /* next restart number expected (0-7) */ unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ }; /* Entropy decoding */ struct jpeg_entropy_decoder { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, JBLOCKROW *MCU_data)); /* This is here to share code between baseline and progressive decoders; */ /* other modules probably should not use it */ boolean insufficient_data; /* set TRUE after emitting warning */ }; /* Inverse DCT (also performs dequantization) */ typedef JMETHOD(void, inverse_DCT_method_ptr, (j_decompress_ptr cinfo, jpeg_component_info * compptr, JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); struct jpeg_inverse_dct { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); /* It is useful to allow each component to have a separate IDCT method. */ inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; }; /* Upsampling (note that upsampler must also call color converter) */ struct jpeg_upsampler { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(void, upsample, (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, JDIMENSION in_row_groups_avail, JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); boolean need_context_rows; /* TRUE if need rows above & below */ }; /* Colorspace conversion */ struct jpeg_color_deconverter { JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); JMETHOD(void, color_convert, (j_decompress_ptr cinfo, JSAMPIMAGE input_buf, JDIMENSION input_row, JSAMPARRAY output_buf, int num_rows)); }; /* Color quantization or color precision reduction */ struct jpeg_color_quantizer { JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows)); JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); }; /* Miscellaneous useful macros */ #undef MAX #define MAX(a,b) ((a) > (b) ? (a) : (b)) #undef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) /* We assume that right shift corresponds to signed division by 2 with * rounding towards minus infinity. This is correct for typical "arithmetic * shift" instructions that shift in copies of the sign bit. But some * C compilers implement >> with an unsigned shift. For these machines you * must define RIGHT_SHIFT_IS_UNSIGNED. * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. * It is only applied with constant shift counts. SHIFT_TEMPS must be * included in the variables of any routine using RIGHT_SHIFT. */ #ifdef RIGHT_SHIFT_IS_UNSIGNED #define SHIFT_TEMPS INT32 shift_temp; #define RIGHT_SHIFT(x,shft) \ ((shift_temp = (x)) < 0 ? \ (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ (shift_temp >> (shft))) #else #define SHIFT_TEMPS #define RIGHT_SHIFT(x,shft) ((x) >> (shft)) #endif /* Short forms of external names for systems with brain-damaged linkers. */ #ifdef NEED_SHORT_EXTERNAL_NAMES #define jinit_compress_master jICompress #define jinit_c_master_control jICMaster #define jinit_c_main_controller jICMainC #define jinit_c_prep_controller jICPrepC #define jinit_c_coef_controller jICCoefC #define jinit_color_converter jICColor #define jinit_downsampler jIDownsampler #define jinit_forward_dct jIFDCT #define jinit_huff_encoder jIHEncoder #define jinit_phuff_encoder jIPHEncoder #define jinit_marker_writer jIMWriter #define jinit_master_decompress jIDMaster #define jinit_d_main_controller jIDMainC #define jinit_d_coef_controller jIDCoefC #define jinit_d_post_controller jIDPostC #define jinit_input_controller jIInCtlr #define jinit_marker_reader jIMReader #define jinit_huff_decoder jIHDecoder #define jinit_phuff_decoder jIPHDecoder #define jinit_inverse_dct jIIDCT #define jinit_upsampler jIUpsampler #define jinit_color_deconverter jIDColor #define jinit_1pass_quantizer jI1Quant #define jinit_2pass_quantizer jI2Quant #define jinit_merged_upsampler jIMUpsampler #define jinit_memory_mgr jIMemMgr #define jdiv_round_up jDivRound #define jround_up jRound #define jcopy_sample_rows jCopySamples #define jcopy_block_row jCopyBlocks #define jzero_far jZeroFar #define jpeg_zigzag_order jZIGTable #define jpeg_natural_order jZAGTable #endif /* NEED_SHORT_EXTERNAL_NAMES */ /* Compression module initialization routines */ EXTERN(void) jinit_compress_master JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_c_master_control JPP((j_compress_ptr cinfo, boolean transcode_only)); EXTERN(void) jinit_c_main_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_c_prep_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_c_coef_controller JPP((j_compress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_color_converter JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_downsampler JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_forward_dct JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_huff_encoder JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_phuff_encoder JPP((j_compress_ptr cinfo)); EXTERN(void) jinit_marker_writer JPP((j_compress_ptr cinfo)); /* Decompression module initialization routines */ EXTERN(void) jinit_master_decompress JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_d_main_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_d_coef_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_d_post_controller JPP((j_decompress_ptr cinfo, boolean need_full_buffer)); EXTERN(void) jinit_input_controller JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_marker_reader JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_huff_decoder JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_inverse_dct JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_upsampler JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_color_deconverter JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); EXTERN(void) jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); /* Memory manager initialization */ EXTERN(void) jinit_memory_mgr JPP((j_common_ptr cinfo)); /* Utility routines in jutils.c */ EXTERN(long) jdiv_round_up JPP((long a, long b)); EXTERN(long) jround_up JPP((long a, long b)); EXTERN(void) jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, JSAMPARRAY output_array, int dest_row, int num_rows, JDIMENSION num_cols)); EXTERN(void) jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, JDIMENSION num_blocks)); EXTERN(void) jzero_far JPP((void FAR * target, size_t bytestozero)); /* Constant tables in jutils.c */ #if 0 /* This table is not actually needed in v6a */ extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ #endif extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ /* Suppress undefined-structure complaints if necessary. */ #ifdef INCOMPLETE_TYPES_BROKEN #ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ struct jvirt_sarray_control { long dummy; }; struct jvirt_barray_control { long dummy; }; #endif #endif /* INCOMPLETE_TYPES_BROKEN */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/tiff.hh��������������������������������������������������������������������0000644�0000764�0000764�00000002763�11603344415�015103� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2005 - 2011 René Rebe * * 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 "Codecs.hh" #include <tiffconf.h> #include <tiffio.h> // not TIFFCodec due the TIFFCodec in libtiff itself ... class TIFCodec : public ImageCodec { public: TIFCodec (); TIFCodec (TIFF* ctx); ~TIFCodec (); virtual std::string getID () { return "TIFF"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres, int index); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); // for multi-page writing virtual ImageCodec* instanciateForWrite (std::ostream* stream); virtual bool Write (Image& image, int quality, const std::string& compress, int index); private: static bool writeImageImpl (TIFF* out, const Image& image, const std::string& conpress, int page = 0); private: TIFF* tiffCtx; }; �������������exact-image-0.9.1/codecs/gif.hh���������������������������������������������������������������������0000644�0000764�0000764�00000002045�11343547354�014721� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2008 René Rebe * * 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 "Codecs.hh" class GIFCodec : public ImageCodec { public: GIFCodec () { registerCodec ("gif", this); }; virtual std::string getID () { return "GIF"; }; virtual int readImage (std::istream* stream, Image& image, const std::string& decompres); virtual bool writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress); }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/codecs/tiff.cc��������������������������������������������������������������������0000644�0000764�0000764�00000036541�11607273052�015074� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2005 - 2011 René Rebe, ExactCODE GmbH, Berlin * (C) 2005 Archivista GmbH, CH-8042 Zuerich * * 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 <stdio.h> #include <stdlib.h> #include <string.h> #include "tiff.hh" #include "Colorspace.hh" #include <algorithm> #include <iostream> /* Well, sadly our own c++ glue, the libtiff native one does not provide readble out streams it requires for multi-page files, ... */ static const bool trace = false; extern "C" { struct tiffis_data { std::istream* IS; long streamStartPos; }; struct tiffos_data { std::ostream* OS; long streamStartPos; }; static tsize_t _tiffisReadProc(thandle_t fd, tdata_t buf, tsize_t size) { tiffis_data* data = (tiffis_data*)fd; data->IS->read((char*)buf, (int)size); return data->IS->gcount(); } static tsize_t _tiffosReadProc(thandle_t fd, tdata_t buf, tsize_t size) { if (trace) std::cerr << __FUNCTION__ << " " << size << std::endl; tiffos_data* data = (tiffos_data*)fd; std::istream* is = dynamic_cast<std::istream*>(data->OS); if (is) { is->sync(); if (trace) std::cerr << is->tellg() << std::endl; is->read((char*)buf, (int)size); long c = is->gcount(); if (trace) std::cerr << is->tellg() << std::endl;; if (trace) std::cerr << c << std::endl; return c; } else return 0; } static tsize_t _tiffosWriteProc(thandle_t fd, tdata_t buf, tsize_t size) { tiffos_data* data = (tiffos_data*)fd; std::ostream* os = data->OS; int pos = os->tellp(); if (trace) std::cerr << __FUNCTION__ << " " << size << " " << os->fail() << std::endl; os->write((const char*)buf, size); int c = ((int)os->tellp()) - pos; if (trace) std::cerr << c << std::endl; return c; } static tsize_t _tiffisWriteProc(thandle_t, tdata_t, tsize_t) { return 0; } static toff_t _tiffosSeekProc(thandle_t fd, toff_t off, int whence) { if (trace) std::cerr << __FUNCTION__ << " " << off << std::endl; tiffos_data* data = (tiffos_data*)fd; std::ostream* os = data->OS; // according to my tests g and p pointer are changed in-sync // if the stream has already failed, don't do anything if (os->fail()) os->clear(); if (trace) std::cerr << "failed: " << os->fail() << std::endl; switch (whence) { case SEEK_SET: if (trace) std::cerr << "SET " << data->streamStartPos << " " << off << std::endl; os->seekp(data->streamStartPos + off, std::ios::beg); break; case SEEK_CUR: os->seekp(off, std::ios::cur); break; case SEEK_END: os->seekp(off, std::ios::end); break; } if (trace) std::cerr << "failed: " << os->fail() << std::endl; // Attempt to workaround problems with seeking past the end of the // stream. ofstream doesn't have a problem with this but // ostrstream/ostringstream does. In that situation, add intermediate // '\0' characters. if (os->fail()) { std::ios::iostate old_state; toff_t origin = 0; old_state = os->rdstate(); // reset the fail bit or else tellp() won't work below os->clear(os->rdstate() & ~std::ios::failbit); switch (whence) { case SEEK_SET: origin = data->streamStartPos; break; case SEEK_CUR: origin = os->tellp(); break; case SEEK_END: os->seekp(0, std::ios::end); origin = os->tellp(); break; } // restore original stream state os->clear(old_state); // only do something if desired seek position is valid if (origin + off > data->streamStartPos) { toff_t num_fill; // clear the fail bit os->clear(os->rdstate() & ~std::ios::failbit); // extend the stream to the expected size os->seekp(0, std::ios::end); num_fill = origin + off - (toff_t)os->tellp(); for (toff_t i = 0; i < num_fill; i++) os->put('\0'); // retry the seek os->seekp(origin + off, std::ios::beg); } } int c = os->tellp(); if (trace) std::cerr << c << " failed: " << os->fail() << std::endl; return c; } static toff_t _tiffisSeekProc(thandle_t fd, toff_t off, int whence) { tiffis_data* data = (tiffis_data*)fd; switch (whence) { case SEEK_SET: data->IS->seekg(data->streamStartPos + off, std::ios::beg); break; case SEEK_CUR: data->IS->seekg(off, std::ios::cur); break; case SEEK_END: data->IS->seekg(off, std::ios::end); break; } return ((long)data->IS->tellg()) - data->streamStartPos; } static toff_t _tiffosSizeProc(thandle_t fd) { if (trace) std::cerr << __FUNCTION__ << std::endl; tiffos_data *data = (tiffos_data*)fd; std::ostream *os = data->OS; toff_t pos = os->tellp(); toff_t len; os->seekp(0, std::ios::end); len = os->tellp(); os->seekp(pos); return len; } static toff_t _tiffisSizeProc(thandle_t fd) { tiffis_data *data = (tiffis_data*)fd; int pos = data->IS->tellg(); int len; data->IS->seekg(0, std::ios::end); len = data->IS->tellg(); data->IS->seekg(pos); return len; } static int _tiffosCloseProc(thandle_t fd) { if (trace) std::cerr << __FUNCTION__ << std::endl; delete (tiffos_data*)fd; return 0; } static int _tiffisCloseProc(thandle_t fd) { delete (tiffis_data*)fd; return 0; } static int _tiffDummyMapProc(thandle_t , tdata_t* , toff_t*) { if (trace) std::cerr << __FUNCTION__ << std::endl; return (0); } static void _tiffDummyUnmapProc(thandle_t , tdata_t , toff_t) { } } // end. extern "C" static TIFF* _tiffStreamOpen(const char* name, const char* mode, void* fd) { TIFF* tif; if (strchr(mode, 'w')) { tiffos_data* data = new tiffos_data; data->OS = (std::ostream*)fd; data->streamStartPos = data->OS->tellp(); if (data->streamStartPos < 0) data->streamStartPos = 0; tif = TIFFClientOpen(name, mode, (thandle_t) data, _tiffosReadProc, _tiffosWriteProc, _tiffosSeekProc, _tiffosCloseProc, _tiffosSizeProc, _tiffDummyMapProc, _tiffDummyUnmapProc); } else { tiffis_data* data = new tiffis_data; data->IS = (std::istream*)fd; data->streamStartPos = data->IS->tellg(); if (data->streamStartPos < 0) data->streamStartPos = 0; // Open for reading. tif = TIFFClientOpen(name, mode, (thandle_t) data, _tiffisReadProc, _tiffisWriteProc, _tiffisSeekProc, _tiffisCloseProc, _tiffisSizeProc, _tiffDummyMapProc, _tiffDummyUnmapProc); } if (trace) std::cerr << tif << std::endl; return tif; } static TIFF* TIFFStreamOpen(const char* name, std::ostream* os) { // If os is either a ostrstream or ostringstream, and has no data // written to it yet, then tellp() will return -1 which will break us. // We workaround this by writing out a dummy character and // then seek back to the beginning. if (trace) std::cerr << "test: " << os->tellp() << std::endl; if (!os->fail() && (int)os->tellp() < 0) { *os << '\0'; os->seekp(1); if (trace) std::cerr << "test: " << os->tellp() << std::endl; if (trace) std::cerr << "wrote a dummy" << std::endl; } return _tiffStreamOpen(name, "wm", os); // m for no mmap } static TIFF* TIFFStreamOpen(const char* name, std::istream* is) { // NB: We don't support mapped files with streams so add 'm' return _tiffStreamOpen(name, "rm", is); // m for no mmap } /* back to our codec */ TIFCodec::TIFCodec () : tiffCtx(0) { registerCodec ("tiff", this); registerCodec ("tif", this); } TIFCodec::TIFCodec (TIFF* ctx) : tiffCtx(ctx) { } TIFCodec::~TIFCodec() { if (tiffCtx) TIFFClose(tiffCtx); } int TIFCodec::readImage (std::istream* stream, Image& image, const std::string& decompres, int index) { TIFF* in; // quick magic check { char a, b; a = stream->get (); b = stream->peek (); stream->putback (a); int magic = (a << 8) | b; if (magic != TIFF_BIGENDIAN && magic != TIFF_LITTLEENDIAN) return false; } in = TIFFStreamOpen ("", stream); if (!in) return false; int n_images = TIFFNumberOfDirectories(in); if (index > 0 || index != TIFFCurrentDirectory(in)) if (!TIFFSetDirectory(in, index)) { TIFFClose(in); return false; } uint16 photometric = 0; TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric); // std::cerr << "photometric: " << (int)photometric << std::endl; switch (photometric) { case PHOTOMETRIC_MINISWHITE: case PHOTOMETRIC_MINISBLACK: case PHOTOMETRIC_RGB: case PHOTOMETRIC_PALETTE: break; default: std::cerr << "TIFCodec: Unrecognized photometric: " << (int)photometric << std::endl; TIFFClose(in); return false; } uint32 _w = 0; TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &_w); uint32 _h = 0; TIFFGetField(in, TIFFTAG_IMAGELENGTH, &_h); uint16 _spp = 0; TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &_spp); uint16 _bps = 0; TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &_bps); if (!_w || !_h || !_spp || !_bps) { TIFFClose(in); stream->seekg(0); return false; } //uint16 config; //TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config); image.w = _w; image.h = _h; image.spp = _spp; image.bps = _bps; float _xres, _yres; if (!TIFFGetField(in, TIFFTAG_XRESOLUTION, &_xres)) _xres = 0; if (!TIFFGetField(in, TIFFTAG_YRESOLUTION, &_yres)) _yres = 0; image.setResolution(_xres, _yres); int stride = image.stride(); image.resize (image.w, image.h); uint16 *rmap = 0, *gmap = 0, *bmap = 0; if (photometric == PHOTOMETRIC_PALETTE) { if (!TIFFGetField (in, TIFFTAG_COLORMAP, &rmap, &gmap, &bmap)) std::cerr << "TIFCodec: Error reading colormap." << std::endl; } uint8_t* data2 = image.getRawData(); for (int row = 0; row < image.h; row++) { if (TIFFReadScanline(in, data2, row, 0) < 0) break; if (photometric == PHOTOMETRIC_MINISWHITE && image.bps == 1) for (int i = 0; i < stride; ++i) data2[i] = data2[i] ^ 0xFF; data2 += stride; } /* some post load fixup */ /* invert if saved "inverted", we already invert 1bps on-the-fly */ if (photometric == PHOTOMETRIC_MINISWHITE && image.bps != 1) invert (image); /* strange 16bit gray images ??? or GRAYA? */ if (image.spp == 2) { for (uint8_t* it = image.getRawData(); it < image.getRawDataEnd(); it += 2) { char x = it[0]; it[0] = it[1]; it[1] = x; } image.spp = 1; image.bps *= 2; } if (photometric == PHOTOMETRIC_PALETTE) { colorspace_de_palette (image, 1 << image.bps, rmap, gmap, bmap); /* free'd by TIFFClose; free(rmap); free(gmap); free(bmap); */ } TIFFClose (in); return n_images; } // for multi-page writing ImageCodec* TIFCodec::instanciateForWrite (std::ostream* stream) { TIFF* out = TIFFStreamOpen ("", stream); if (out == NULL) return 0; return new TIFCodec(out); } bool TIFCodec::Write (Image& image, int quality, const std::string& compress, int index) { return writeImageImpl (tiffCtx, image, compress, index); } bool TIFCodec::writeImage (std::ostream* stream, Image& image, int quality, const std::string& compress) { TIFF* out = TIFFStreamOpen ("", stream); if (out == NULL) return false; bool ret = writeImageImpl (out, image, compress, 0); TIFFClose (out); return ret; } bool TIFCodec::writeImageImpl (TIFF* out, const Image& image, const std::string& compress, int page) { uint32 rowsperstrip = (uint32)-1; uint16 compression = image.bps == 1 ? COMPRESSION_CCITTFAX4 : COMPRESSION_DEFLATE; if (!compress.empty()) { std::string c (compress); std::transform (c.begin(), c.end(), c.begin(), tolower); if (c == "g3" || c == "fax" || c == "group3") compression = COMPRESSION_CCITTFAX3; else if (c == "g4" || c == "group4") compression = COMPRESSION_CCITTFAX4; else if (c == "lzw") compression = COMPRESSION_LZW; else if (c == "deflate" || c == "zip") compression = COMPRESSION_DEFLATE; else if (c == "packbits") compression = COMPRESSION_PACKBITS; else if (c == "none") compression = COMPRESSION_NONE; else std::cerr << "TIFCodec: Unrecognized compression option '" << compress << "'" << std::endl; } if (page) { TIFFSetField (out, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE); TIFFSetField (out, TIFFTAG_PAGENUMBER, page, 0); // total number unknown // TIFFSetField (out, TIFFTAG_PAGENAME, page_name); } TIFFSetField (out, TIFFTAG_IMAGEWIDTH, image.w); TIFFSetField (out, TIFFTAG_IMAGELENGTH, image.h); TIFFSetField (out, TIFFTAG_BITSPERSAMPLE, image.bps); TIFFSetField (out, TIFFTAG_SAMPLESPERPIXEL, image.spp); TIFFSetField (out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField (out, TIFFTAG_COMPRESSION, compression); if (image.spp == 1 && image.bps == 1) // internally we actually have MINISBLACK, but some programs, // including the Apple Preview.app appear to ignore this bit TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE); else if (image.spp == 1) TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); else if (false) { /* just saved for reference */ uint16 rmap[256], gmap[256], bmap[256]; for (int i = 0;i < 256; ++i) { rmap[i] = gmap[i] = bmap[i] = i * 0xffff / 255; } TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE); TIFFSetField (out, TIFFTAG_COLORMAP, rmap, gmap, bmap); } else TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); if (image.resolutionX() != 0) { float _xres = image.resolutionX(); TIFFSetField (out, TIFFTAG_XRESOLUTION, _xres); } if (image.resolutionY() != 0) { float _yres = image.resolutionY(); TIFFSetField (out, TIFFTAG_YRESOLUTION, _yres); } if (page <= 1) { TIFFSetField (out, TIFFTAG_SOFTWARE, "ExactImage"); } //TIFFSetField (out, TIFFTAG_IMAGEDESCRIPTION, ""); rowsperstrip = TIFFDefaultStripSize (out, rowsperstrip); TIFFSetField (out, TIFFTAG_ROWSPERSTRIP, rowsperstrip); const int stride = image.stride(); /* Note: we on-the-fly invert 1-bit data to please some historic apps */ uint8_t* src = image.getRawData(); uint8_t* scanline = 0; if (image.bps == 1) scanline = (uint8_t*) malloc (stride); for (int row = 0; row < image.h; ++row, src += stride) { int err = 0; if (image.bps == 1) { for (int i = 0; i < stride; ++i) scanline [i] = src [i] ^ 0xFF; err = TIFFWriteScanline (out, scanline, row, 0); } else err = TIFFWriteScanline (out, src, row, 0); if (err < 0) { if (scanline) free (scanline); return false; } } if (scanline) free (scanline); return TIFFWriteDirectory(out); } TIFCodec tif_loader; ���������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/TODO������������������������������������������������������������������������������0000644�0000764�0000764�00000002626�11122232321�013044� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� * crash on 0 byte input? * eimport * cut and resave in edisplay - GRAY, RGB, CMYK, YUV iterators with bit fields specified - SVG text tag, styles, def refs (e.g. text pathes, styles) - black / white- point Array subscription, ala: image[][] type inside the image: RGB, YUV, CMYK, palette (direct, without expansion on load) - cheap copies - copy on write - sub-images - shear - rotate by double shear Loaders: - palette saving - gzip / bzip2 / ... compressed streams - http:// et al (libcurl or so?) - 2 and 4 bit TIFF "imperfect" General: - Exif, XMP and ordinary, classic comment support Algorithms: - rgb_A_ iterator and thus scaling, rotation - faster and ddt scaling! - descreen - blur - sharp, unsharp - all the others - affine transforms - 2D Baccode recognition: Datamatrix, Semacode, BeeTagg and QR Colorspaces: - more generic but faster and let all algorithms use it in the most generic form - RGBA - float, double support - CMYK - YUV - sRGB vs. Adobe RGB - ... + /* + Basic colorspace: GRAY, GRAYA, RGB, RGBA, CMYK, YUV, YUVA + Bit depth: INT1 INT2 INT4 INT8 INT16 INT32 FLOAT32 FLOAT64 + */ uint8_t* getRawData () const; uint8_t* getRawDataEnd () const; Frontends: - edentify: - more complete - econvert: - seperate channels - edisplay: - browsing - thumbnailing - slideshow - partial decoding on load - faster zooming ����������������������������������������������������������������������������������������������������������exact-image-0.9.1/ContourMatching/������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664255�015506� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/ContourMatching/ContourMatching.cc������������������������������������������������0000644�0000764�0000764�00000014447�10652116346�021116� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <math.h> #include <iostream> #include <iomanip> #include "ArgumentList.hh" #include "Codecs.hh" #include "Colorspace.hh" #include "Matrix.hh" #include "optimize2bw.hh" #include "ContourMatching.hh" using namespace Utility; int main (int argc, char* argv[]) { ArgumentList arglist; // setup the argument list Argument<bool> arg_help ("", "help", "display this help text and exit"); Argument<std::string> arg_input ("i", "input", "input file", 1, 1); Argument<std::string> arg_output ("o", "output", "output file", 1, 1); // optimize2bw options Argument<int> arg_low ("l", "low", "low normalization value", 0, 0, 1); Argument<int> arg_high ("h", "high", "high normalization value", 0, 0, 1); Argument<int> arg_threshold ("t", "threshold", "bi-level threshold value", 0, 0, 1); Argument<int> arg_radius ("r", "radius", "\"unsharp mask\" radius", 0, 0, 1); Argument<double> arg_sd ("sd", "standard-deviation", "standard deviation for Gaussian distribution", 0.0, 0, 1); // matching options Argument<std::string> arg_logo ("L", "logo", "logo file", 1, 1); Argument<unsigned int> arg_features("F", "features", "maximum number of logo features", (unsigned int)10, 0, 1, false, false); Argument<unsigned int> arg_tolerance("T", "tolerance", "tolerated maximum average distance", (unsigned int)20, 0, 1, false, false); Argument<double> arg_angle("A", "angle", "maximum rotation angle for pre-matching", 0.0, 0, 1); Argument<double> arg_step("S", "step", "rotation angle increment for pre-matching", 0.0, 0, 1); Argument<unsigned int> arg_shift("R", "reduction", "coordinate bit reduction for pre-matching", (unsigned int)3, 0, 1, false, false); arglist.Add (&arg_help); arglist.Add (&arg_input); arglist.Add (&arg_logo); arglist.Add (&arg_output); arglist.Add (&arg_low); arglist.Add (&arg_high); arglist.Add (&arg_threshold); arglist.Add (&arg_radius); arglist.Add (&arg_sd); arglist.Add (&arg_features); arglist.Add (&arg_tolerance); arglist.Add (&arg_angle); arglist.Add (&arg_step); arglist.Add (&arg_shift); // parse the specified argument list - and maybe output the Usage if (!arglist.Read (argc, argv) || arg_help.Get() == true) { std::cerr << "Based on Color / Gray image to Bi-level optimizer" << " - Copyright 2005, 2006 by René Rebe" << std::endl << "Usage:" << std::endl; arglist.Usage (std::cerr); return 1; } Image o_image; if (!ImageCodec::Read (arg_input.Get(), o_image)) { std::cerr << "Error reading input file." << std::endl; return 1; } Image l_image; if (!ImageCodec::Read (arg_logo.Get(), l_image)) { std::cerr << "Error reading logo file." << std::endl; return 1; } Image image=o_image; int low = 0; int high = 0; int sloppy_threshold = 0; int radius = 3; double sd = 2.1; if (arg_low.Get() != 0) { low = arg_low.Get(); std::cerr << "Low value overwritten: " << low << std::endl; } if (arg_high.Get() != 0) { high = arg_high.Get(); std::cerr << "High value overwritten: " << high << std::endl; } if (arg_radius.Get() != 0) { radius = arg_radius.Get(); std::cerr << "Radius: " << radius << std::endl; } if (arg_sd.Get() != 0) { sd = arg_sd.Get(); std::cerr << "SD overwritten: " << sd << std::endl; } // convert to 1-bit (threshold) int threshold = 0; if (arg_threshold.Get() != 0) { threshold = arg_threshold.Get(); std::cerr << "Threshold: " << threshold << std::endl; } optimize2bw (image, low, high, threshold, sloppy_threshold, radius, sd); optimize2bw (l_image, low, high, threshold, sloppy_threshold, radius, sd); if (arg_threshold.Get() == 0) threshold = 200; FGMatrix mi(image, threshold); FGMatrix ml(l_image, threshold); std::cout << "Contouring" << std::endl; Contours conti(mi); Contours contl(ml); std::cout << "done." << std::endl; #if false // Export test FILE* test=fopen("test.cnt", "w"); if (!WriteContourArray(test, conti.contours)) std::cout << "write error" << std::endl; fclose(test); Contours copy; test=fopen("test.cnt", "r"); if (ReadContourArray(test, copy.contours)) { if (copy.contours.size() != conti.contours.size()) { std::cout << "contour count differs" << std::endl; } else { for (unsigned int c=0; c<copy.contours.size(); c++) { if (copy.contours[c]->size() != conti.contours[c]->size()) std::cout << "size" << std::endl; else for (unsigned int i=0; i<copy.contours[c]->size(); i++) if ((*(copy.contours[c]))[i] != (*(conti.contours[c]))[i]) std::cout << "content\t" << i << "\t" << (*(copy.contours[c]))[i].first << "\t" << (*(copy.contours[c]))[i].second << "\t" << (*(conti.contours[c]))[i].first << "\t" << (*(conti.contours[c]))[i].second << std::endl; } } } else std::cout << "read error" << std::endl; fclose(test); #endif // Todo: check for insane values unsigned int features=arg_features.Get(); unsigned int tolerance=arg_tolerance.Get(); unsigned int shift=arg_shift.Get(); double max_angle=arg_angle.Get(); double angle_step=arg_step.Get(); LogoRepresentation lrep(&contl, features, tolerance, shift, max_angle, angle_step); std::cout << "score: " << lrep.Score(&conti) << std::endl; int tx=lrep.logo_translation.first; int ty=lrep.logo_translation.second; double angle=M_PI * lrep.rot_angle / 180.0; std::cout << "logo translation: " << tx << "\t" << ty << "\trotation angle: " << lrep.rot_angle << std::endl; for (unsigned int i=0; i<lrep.mapping.size(); i++) { double trash; Contours::Contour transformed; RotCenterAndReduce(*lrep.mapping[i].first, transformed, angle, 0, 0, trash, trash); DrawTContour(o_image, transformed, tx, ty, 0, 0, 255); //transformed.clear(); //RotCenterAndReduce(*lrep.mapping[i].first, transformed, 0, 0, 0, trash, trash); //DrawTContour(o_image, transformed, tx, ty, 0, 255, 255); DrawContour(o_image, *lrep.mapping[i].second, 0, 255, 0); } if (!ImageCodec::Write(arg_output.Get(), o_image)) { std::cerr << "Error writing output file." << std::endl; return 1; } return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/ContourMatching/segmentation.cc���������������������������������������������������0000644�0000764�0000764�00000010646�11015274766�020511� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Valentin Ziegler, ExactCODE GmbH Germany. * * 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 <math.h> #include <iostream> #include <iomanip> #include "ArgumentList.hh" #include "segmentation.hh" #include "Codecs.hh" #include "Colorspace.hh" #include "Matrix.hh" #include "optimize2bw.hh" using namespace Utility; void Draw(Segment* s, Image& img) { if (s->children.size() == 0) s->Draw(img); else for (unsigned int i=0; i<s->children.size(); i++) Draw(s->children[i], img); } int main (int argc, char* argv[]) { ArgumentList arglist; // setup the argument list Argument<bool> arg_help ("", "help", "display this help text and exit"); Argument<std::string> arg_input ("i", "input", "input file", 1, 1); Argument<std::string> arg_output ("o", "output", "output file", 1, 1); Argument<int> arg_low ("l", "low", "low normalization value", 0, 0, 1); Argument<int> arg_high ("h", "high", "high normalization value", 0, 0, 1); Argument<int> arg_threshold ("t", "threshold", "bi-level threshold value", 0, 0, 1); Argument<int> arg_radius ("r", "radius", "\"unsharp mask\" radius", 0, 0, 1); Argument<double> arg_sd ("sd", "standard-deviation", "standard deviation for Gaussian distribution", 0.0, 0, 1); Argument<double> arg_tolerance ("T", "tolerance", "fraction of foreground pixels tolerated per line", 0.02, 0, 1); Argument<int> arg_width("W", "width", "minimum width of vertical separator", 10, 0, 1); Argument<int> arg_height("H", "height", "minimum height of horizontal separator", 20, 0, 1); arglist.Add (&arg_help); arglist.Add (&arg_input); arglist.Add (&arg_output); arglist.Add (&arg_low); arglist.Add (&arg_high); arglist.Add (&arg_threshold); arglist.Add (&arg_radius); arglist.Add (&arg_sd); arglist.Add (&arg_tolerance); arglist.Add (&arg_width); arglist.Add (&arg_height); // parse the specified argument list - and maybe output the Usage if (!arglist.Read (argc, argv) || arg_help.Get() == true) { std::cerr << "Based on Color / Gray image to Bi-level optimizer" << " - Copyright 2005, 2006 by René Rebe" << std::endl << "Usage:" << std::endl; arglist.Usage (std::cerr); return 1; } Image o_image; if (!ImageCodec::Read (arg_input.Get(), o_image)) { std::cerr << "Error reading input file." << std::endl; return 1; } Image image=o_image; int low = 0; int high = 0; int sloppy_threshold = 0; int radius = 3; double sd = 2.1; if (arg_low.Get() != 0) { low = arg_low.Get(); std::cerr << "Low value overwritten: " << low << std::endl; } if (arg_high.Get() != 0) { high = arg_high.Get(); std::cerr << "High value overwritten: " << high << std::endl; } if (arg_radius.Get() != 0) { radius = arg_radius.Get(); std::cerr << "Radius: " << radius << std::endl; } if (arg_sd.Get() != 0) { sd = arg_sd.Get(); std::cerr << "SD overwritten: " << sd << std::endl; } // convert to 1-bit (threshold) int threshold = 0; if (arg_threshold.Get() != 0) { threshold = arg_threshold.Get(); std::cerr << "Threshold: " << threshold << std::endl; } optimize2bw (image, low, high, threshold, sloppy_threshold, radius, sd); if (arg_threshold.Get() == 0) threshold = 200; double tolerance=arg_tolerance.Get(); int width=arg_width.Get(); int height=arg_height.Get(); // TODO: check for nonsense values FGMatrix foreground(image, threshold); Segment* segment=segment_image(foreground, tolerance, width, height); segment = segment; Draw(segment, o_image); if (!ImageCodec::Write(arg_output.Get(), o_image)) { std::cerr << "Error writing output file." << std::endl; return 1; } return 0; } ������������������������������������������������������������������������������������������exact-image-0.9.1/ContourMatching/Contours.cc�������������������������������������������������������0000644�0000764�0000764�00000010714�11015274766�017624� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Valentin Ziegler, ExactCODE GmbH Germany. * * 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 <iostream> #include <iomanip> #include "ArgumentList.hh" #include "Codecs.hh" #include "Colorspace.hh" #include "Matrix.hh" #include "optimize2bw.hh" #include "Contours.hh" void PutPixel(Image& img, int x, int y, uint16_t R, uint16_t G, uint16_t B) { Image::iterator color=img.begin(); color.setRGB(R, G, B); Image::iterator p=img.begin(); p=p.at(x,y); p.set(color); } void DrawContour(Image& img, const Contours::Contour& c, uint16_t r, uint16_t g, uint16_t b) { for (unsigned int i=0; i<c.size(); i++) PutPixel(img, c[i].first, c[i].second, r, g, b); } using namespace Utility; int main (int argc, char* argv[]) { ArgumentList arglist; // setup the argument list Argument<bool> arg_help ("", "help", "display this help text and exit"); Argument<std::string> arg_input ("i", "input", "input file", 1, 1); Argument<std::string> arg_output ("o", "output", "output file", 1, 1); Argument<int> arg_low ("l", "low", "low normalization value", 0, 0, 1); Argument<int> arg_high ("h", "high", "high normalization value", 0, 0, 1); Argument<int> arg_threshold ("t", "threshold", "bi-level threshold value", 0, 0, 1); Argument<int> arg_radius ("r", "radius", "\"unsharp mask\" radius", 0, 0, 1); Argument<double> arg_sd ("sd", "standard-deviation", "standard deviation for Gaussian distribution", 0.0, 0, 1); arglist.Add (&arg_help); arglist.Add (&arg_input); arglist.Add (&arg_output); arglist.Add (&arg_low); arglist.Add (&arg_high); arglist.Add (&arg_threshold); arglist.Add (&arg_radius); arglist.Add (&arg_sd); // parse the specified argument list - and maybe output the Usage if (!arglist.Read (argc, argv) || arg_help.Get() == true) { std::cerr << "Based on Color / Gray image to Bi-level optimizer" << " - Copyright 2005, 2006 by René Rebe" << std::endl << "Usage:" << std::endl; arglist.Usage (std::cerr); return 1; } Image o_image; if (!ImageCodec::Read (arg_input.Get(), o_image)) { std::cerr << "Error reading input file." << std::endl; return 1; } Image image=o_image; int low = 0; int high = 0; int sloppy_threshold = 0; int radius = 3; double sd = 2.1; if (arg_low.Get() != 0) { low = arg_low.Get(); std::cerr << "Low value overwritten: " << low << std::endl; } if (arg_high.Get() != 0) { high = arg_high.Get(); std::cerr << "High value overwritten: " << high << std::endl; } if (arg_radius.Get() != 0) { radius = arg_radius.Get(); std::cerr << "Radius: " << radius << std::endl; } if (arg_sd.Get() != 0) { sd = arg_sd.Get(); std::cerr << "SD overwritten: " << sd << std::endl; } // convert to 1-bit (threshold) int threshold = 0; if (arg_threshold.Get() != 0) { threshold = arg_threshold.Get(); std::cerr << "Threshold: " << threshold << std::endl; } optimize2bw (image, low, high, threshold, sloppy_threshold, radius, sd); if (arg_threshold.Get() == 0) threshold = 200; FGMatrix m(image, threshold); std::cout << "Contouring" << std::endl; Contours cont(m); std::cout << "done." << std::endl; for (unsigned int i=0; i<cont.contours.size(); i++) { unsigned int r; unsigned int g; unsigned int b; switch (i % 6) { case 0: r=255; g=0; b=0; break; case 1: r=0; g=255; b=0; break; case 2: r=0; g=0; b=255; break; case 3: r=255; g=255; b=0; break; case 4: r=0; g=255; b=255; break; case 5: r=255; g=0; b=255; break; } DrawContour(o_image, *cont.contours[i], r,g,b); } if (!ImageCodec::Write(arg_output.Get(), o_image)) { std::cerr << "Error writing output file." << std::endl; return 1; } return 0; } ����������������������������������������������������exact-image-0.9.1/ContourMatching/distance.cc�������������������������������������������������������0000644�0000764�0000764�00000010067�11015274766�017603� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Valentin Ziegler, ExactCODE GmbH Germany. * * 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 <math.h> #include <iostream> #include <iomanip> #include "ArgumentList.hh" #include "DistanceMatrix.hh" #include "Codecs.hh" #include "Colorspace.hh" #include "Matrix.hh" #include "optimize2bw.hh" using namespace Utility; int main (int argc, char* argv[]) { ArgumentList arglist; // setup the argument list Argument<bool> arg_help ("", "help", "display this help text and exit"); Argument<std::string> arg_input ("i", "input", "input file", 1, 1); Argument<std::string> arg_output ("o", "output", "output file", 1, 1); Argument<int> arg_low ("l", "low", "low normalization value", 0, 0, 1); Argument<int> arg_high ("h", "high", "high normalization value", 0, 0, 1); Argument<int> arg_threshold ("t", "threshold", "bi-level threshold value", 0, 0, 1); Argument<int> arg_radius ("r", "radius", "\"unsharp mask\" radius", 0, 0, 1); Argument<double> arg_sd ("sd", "standard-deviation", "standard deviation for Gaussian distribution", 0.0, 0, 1); arglist.Add (&arg_help); arglist.Add (&arg_input); arglist.Add (&arg_output); arglist.Add (&arg_low); arglist.Add (&arg_high); arglist.Add (&arg_threshold); arglist.Add (&arg_radius); arglist.Add (&arg_sd); // parse the specified argument list - and maybe output the Usage if (!arglist.Read (argc, argv) || arg_help.Get() == true) { std::cerr << "Based on Color / Gray image to Bi-level optimizer" << " - Copyright 2005, 2006 by René Rebe" << std::endl << "Usage:" << std::endl; arglist.Usage (std::cerr); return 1; } Image o_image; if (!ImageCodec::Read (arg_input.Get(), o_image)) { std::cerr << "Error reading input file." << std::endl; return 1; } Image image=o_image; int low = 0; int high = 0; int sloppy_threshold = 0; int radius = 3; double sd = 2.1; if (arg_low.Get() != 0) { low = arg_low.Get(); std::cerr << "Low value overwritten: " << low << std::endl; } if (arg_high.Get() != 0) { high = arg_high.Get(); std::cerr << "High value overwritten: " << high << std::endl; } if (arg_radius.Get() != 0) { radius = arg_radius.Get(); std::cerr << "Radius: " << radius << std::endl; } if (arg_sd.Get() != 0) { sd = arg_sd.Get(); std::cerr << "SD overwritten: " << sd << std::endl; } // convert to 1-bit (threshold) int threshold = 0; if (arg_threshold.Get() != 0) { threshold = arg_threshold.Get(); std::cerr << "Threshold: " << threshold << std::endl; } optimize2bw (image, low, high, threshold, sloppy_threshold, radius, sd); if (arg_threshold.Get() == 0) threshold = 200; //FGMatrix m(image, threshold); //DistanceMatrix dm(m); DistanceMatrix dm(image, threshold); unsigned int line=0; unsigned int row=0; Image::iterator i=o_image.begin(); Image::iterator end=o_image.end(); Image::iterator color=o_image.begin(); for (; i!=end ; ++i) { int value=255-(int)dm(row,line); uint16_t r = value < 0 ? 0 : value, g = value==255 ? 255 : 0, b = 0; color.setRGB(r, g, b); i.set(color); if (++row == (unsigned int)image.w) { line++; row=0; } } if (!ImageCodec::Write(arg_output.Get(), o_image)) { std::cerr << "Error writing output file." << std::endl; return 1; } return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/ContourMatching/Makefile����������������������������������������������������������0000644�0000764�0000764�00000000612�10714036632�017126� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include build/top.make # build each .cc file as executable - if this is not desired # in the future a list must be supplied manually ... BINARY = $(basename $(notdir $(wildcard $(X_MODULE)/*.cc))) BINARY_EXT = $(X_EXEEXT) DEPS = $(lib_BINARY) $(codecs_BINARY) $(X_OUTARCH)/utility/ArgumentList$(X_OBJEXT) CPPFLAGS += -I utility X_NO_INSTALL := 1 include build/bottom.make X_NO_INSTALL := 0 ����������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/��������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664323�014101� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/FlexLexer.hh��������������������������������������������������������������0000644�0000764�0000764�00000014065�10311256605�016310� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������// $Header: /home/daffy/u0/vern/flex/RCS/FlexLexer.h,v 1.19 96/05/25 20:43:02 vern Exp $ // FlexLexer.h -- define interfaces for lexical analyzer classes generated // by flex // Copyright (c) 1993 The Regents of the University of California. // All rights reserved. // // This code is derived from software contributed to Berkeley by // Kent Williams and Tom Epperly. // // Redistribution and use in source and binary forms with or without // modification are permitted provided that: (1) source distributions retain // this entire copyright notice and comment, and (2) distributions including // binaries display the following acknowledgement: ``This product includes // software developed by the University of California, Berkeley and its // contributors'' in the documentation or other materials provided with the // distribution and in all advertising materials mentioning features or use // of this software. Neither the name of the University nor the names of // its contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED // WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. /* --- NO-GSMP-COPYRIGHT-NOTE --- * * This is a slightly modified copy of the file <FlexLexer.h> which comes with the * flex package by the GNU Project / FSF * */ // This file defines FlexLexer, an abstract class which specifies the // external interface provided to flex C++ lexer objects, and yyFlexLexer, // which defines a particular lexer class. // // If you want to create multiple lexer classes, you use the -P flag // to rename each yyFlexLexer to some other xxFlexLexer. You then // include <FlexLexer.h> in your other sources once per lexer class: // // #undef yyFlexLexer // #define yyFlexLexer xxFlexLexer // #include <FlexLexer.h> // // #undef yyFlexLexer // #define yyFlexLexer zzFlexLexer // #include <FlexLexer.h> // ... // To encapsulate yyFlecLexer in some namespace, define yyNamespace // and combine with the -P flag, e.g. -Pnamespace::yy #ifndef __FLEX_LEXER_H // Never included before - need to define base class. #define __FLEX_LEXER_H #include <iostream> extern "C++" { struct yy_buffer_state; typedef int yy_state_type; class FlexLexer { public: virtual ~FlexLexer() { } const char* YYText() { return yytext; } int YYLeng() { return yyleng; } virtual void yy_switch_to_buffer( struct yy_buffer_state* new_buffer ) = 0; virtual struct yy_buffer_state* yy_create_buffer( std::istream* s, int size ) = 0; virtual void yy_delete_buffer( struct yy_buffer_state* b ) = 0; virtual void yyrestart( std::istream* s ) = 0; virtual int yylex() = 0; // Call yylex with new input/output sources. int yylex( std::istream* new_in, std::ostream* new_out = 0 ) { switch_streams( new_in, new_out ); return yylex(); } // Switch to new input/output streams. A nil stream pointer // indicates "keep the current one". virtual void switch_streams( std::istream* new_in = 0, std::ostream* new_out = 0 ) = 0; int lineno() const { return yylineno; } int debug() const { return yy_flex_debug; } void set_debug( int flag ) { yy_flex_debug = flag; } protected: char* yytext; int yyleng; int yylineno; // only maintained if you use %option yylineno int yy_flex_debug; // only has effect with -d or "%option debug" }; } #endif #if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce) // Either this is the first time through (yyFlexLexerOnce not defined), // or this is a repeated include to define a different flavor of // yyFlexLexer, as discussed in the flex man page. #define yyFlexLexerOnce #ifdef yyNamespace namespace yyNamespace { #endif class yyFlexLexer : public FlexLexer { public: // arg_yyin and arg_yyout default to the cin and cout, but we // only make that assignment when initializing in yylex(). yyFlexLexer( std::istream* arg_yyin = 0, std::ostream* arg_yyout = 0 ); virtual ~yyFlexLexer(); void yy_switch_to_buffer( struct yy_buffer_state* new_buffer ); struct yy_buffer_state* yy_create_buffer( std::istream* s, int size ); void yy_delete_buffer( struct yy_buffer_state* b ); void yyrestart( std::istream* s ); virtual int yylex(); virtual void switch_streams( std::istream* new_in, std::ostream* new_out ); protected: virtual int LexerInput( char* buf, int max_size ); virtual void LexerOutput( const char* buf, int size ); virtual void LexerError( const char* msg ); void yyunput( int c, char* buf_ptr ); int yyinput(); void yy_load_buffer_state(); void yy_init_buffer( struct yy_buffer_state* b, std::istream* s ); void yy_flush_buffer( struct yy_buffer_state* b ); int yy_start_stack_ptr; int yy_start_stack_depth; int* yy_start_stack; void yy_push_state( int new_state ); void yy_pop_state(); int yy_top_state(); yy_state_type yy_get_previous_state(); yy_state_type yy_try_NUL_trans( yy_state_type current_state ); int yy_get_next_buffer(); std::istream* yyin; // input source for default LexerInput std::ostream* yyout; // output sink for default LexerOutput struct yy_buffer_state* yy_current_buffer; // yy_hold_char holds the character lost when yytext is formed. char yy_hold_char; // Number of characters read into yy_ch_buf. int yy_n_chars; // Points to current character in buffer. char* yy_c_buf_p; int yy_init; // whether we need to initialize int yy_start; // start state number // Flag which is used to allow yywrap()'s to do buffer switches // instead of setting up a fresh yyin. A bit of a hack ... int yy_did_buffer_switch_on_eof; // The following are not always needed, but may be depending // on use of certain flex features (like REJECT or yymore()). yy_state_type yy_last_accepting_state; char* yy_last_accepting_cpos; yy_state_type* yy_state_buf; yy_state_type* yy_state_ptr; char* yy_full_match; int* yy_full_state; int yy_full_lp; int yy_lp; int yy_looking_for_trail_begin; int yy_more_flag; int yy_more_len; int yy_more_offset; int yy_prev_more_offset; }; #ifdef yyNamespace } #endif #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Endianess.hh��������������������������������������������������������������0000644�0000764�0000764�00000014625�11721145173�016330� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: pcm/include/Types.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2012 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* Short Description: * Advanced templates to perform automated type convertion for * various kind of integer and floating point types. Convertions for * the same type are entirely optimized away - and integer convertions * are "normally" optimized down to a single shift instruction - of * course fully inlined. */ #ifndef LOWLEVEL__ENDIANESS_HH__ #define LOWLEVEL__ENDIANESS_HH__ #include <sys/types.h> #include <inttypes.h> #if defined(__FreeBSD__) #include <sys/endian.h> #define bswap_16 bswap16 #define bswap_32 bswap32 #define bswap_64 bswap64 #elif defined(__APPLE__) #include <libkern/OSByteOrder.h> #define bswap_16 OSSwapConstInt16 #define bswap_32 OSSwapConstInt32 #define bswap_64 OSSwapConstInt64 #elif defined (_MSC_VER) || defined (_WIN32) inline uint16_t bswap_16(uint16_t x) { return (x & 0xff00) >> 8 | (x & 0x00ff) << 8; } inline uint32_t bswap_32(uint32_t x) { return (x & 0xff000000) >> 24 | (x & 0x00ff0000) >> 8 | (x & 0x0000ff00) << 8 | (x & 0x000000ff) << 24; } inline uint64_t bswap_64(uint64_t x) { return (x & 0xff000000000000LL) >> 56 | (x & 0xff0000000000LL) >> 32 | (x & 0xff0000000000LL) >> 16 | (x & 0xff00000000LL) >> 8 | (x & 0xff000000LL) << 8 | (x & 0x00ff0000LL) << 16 | (x & 0xff00LL) << 32 | (x & 0xffLL) << 56; } #undef __BIG_ENDIAN__ #undef BYTE_ORDER #else #include <endian.h> #include <byteswap.h> #endif namespace Exact { class EndianTraits { public: static const bool IsSpecialized = false; static const bool HasEndianess = false; static const bool IsBigendian = false; }; class LittleEndianTraits : public EndianTraits { public: static const bool IsSpecialized = true; static const bool HasEndianess = true; static const bool IsBigendian = false; }; class BigEndianTraits : public EndianTraits { public: static const bool IsSpecialized = true; static const bool HasEndianess = true; static const bool IsBigendian = true; }; #if defined(__BIG_ENDIAN__) || (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) typedef BigEndianTraits NativeEndianTraits; #else typedef LittleEndianTraits NativeEndianTraits; #endif typedef BigEndianTraits NetworkEndianTraits; template <typename E_SRC, typename E_DEST, typename T> class ByteSwap { }; template <typename E_SRC, typename E_DEST> class ByteSwap<E_SRC, E_DEST, int8_t> { public: inline static const int8_t Swap (const int8_t& source) { return source; }; }; template <typename E_SRC, typename E_DEST> class ByteSwap<E_SRC, E_DEST, int16_t> { public: inline static const int16_t Swap (const int16_t& source) { if (E_SRC::IsBigendian == E_DEST::IsBigendian) return source; else return bswap_16 (source); }; }; template <typename E_SRC, typename E_DEST> class ByteSwap<E_SRC, E_DEST, uint16_t> { public: inline static const uint16_t Swap (const uint16_t& source) { if (E_SRC::IsBigendian == E_DEST::IsBigendian) return source; else return bswap_16 (source); }; }; template <typename E_SRC, typename E_DEST> class ByteSwap<E_SRC, E_DEST, int32_t> { public: inline static const int32_t Swap (const int32_t& source) { if (E_SRC::IsBigendian == E_DEST::IsBigendian) return source; else return bswap_32 (source); }; }; template <typename E_SRC, typename E_DEST> class ByteSwap<E_SRC, E_DEST, uint32_t> { public: inline static const uint32_t Swap (const uint32_t& source) { if (E_SRC::IsBigendian == E_DEST::IsBigendian) return source; else return bswap_32 (source); }; }; template <typename E_SRC, typename E_DEST> class ByteSwap<E_SRC, E_DEST, int64_t> { public: inline static const int64_t Swap (const int64_t& source) { if (E_SRC::IsBigendian == E_DEST::IsBigendian) return source; else return bswap_64 (source); }; }; template <typename E_SRC, typename E_DEST> class ByteSwap<E_SRC, E_DEST, uint64_t> { public: inline static const uint64_t Swap (const uint64_t& source) { if (E_SRC::IsBigendian == E_DEST::IsBigendian) return source; else return bswap_64 (source); }; }; template <typename E_SRC, typename E_DEST> class ByteSwap<E_SRC, E_DEST, float> { public: inline static const float Swap (const float& source) { uint32_t* t = (uint32_t*)&source; if (E_SRC::IsBigendian != E_DEST::IsBigendian) *t = bswap_32(*t); return *(float*)t; }; }; template <typename E_SRC, typename E_DEST> class ByteSwap<E_SRC, E_DEST, double> { public: inline static const double Swap (const double& source) { uint64_t* t = (uint64_t*)&source; if (E_SRC::IsBigendian != E_DEST::IsBigendian) *t = bswap_64(*t); return *(double*)t; }; }; // --- // must be Plain Old Data (for 0-overhead and packing) template <typename T, typename E> struct EndianessConverter { T value; // access wrappers inline void operator= (T v) { value = ByteSwap<NativeEndianTraits, E, T>::Swap (v); } inline T operator* () const { return ByteSwap<E,NativeEndianTraits, T>::Swap (value); } inline operator T () const { return ByteSwap<E,NativeEndianTraits, T>::Swap (value); } }; } #endif // LOWLEVEL__ENDIANESS_HH__ �����������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Lua.hh��������������������������������������������������������������������0000644�0000764�0000764�00000056270�12461460550�015143� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2009-2015 René Rebe, ExactCODE GmbH * Copyright (C) 2008 Valentin Ziegler, 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. */ #ifndef __LUA_HH #define __LUA_HH extern "C" { #include "lua.h" #include "lauxlib.h" #include "lualib.h" } #ifndef lua_pushglobaltable // Lua 5.1 et al. #define lua_pushglobaltable(L) lua_pushvalue(L, LUA_GLOBALSINDEX) #endif #include <string.h> #include <string> #include <vector> #include <algorithm> #include <stdexcept> namespace LuaWrapper { class AutoReleaseItem; extern AutoReleaseItem* autoReleaseList; template <typename T> class typeName; template <> class typeName<int> { public: static const char* name() {return "int"; } }; template <> class typeName<unsigned int> { public: static const char* name() {return "unsigned int"; } }; template <> class typeName<double> { public: static const char* name() {return "double"; } }; template <> class typeName<const char*> { public: static const char* name() {return "const char*"; } }; template <> class typeName<bool> { public: static const char* name() {return "bool"; } }; template <> class typeName<std::string> { public: static const char* name() {return "std::string"; } }; static void argError(lua_State* L, int index, const char* type_name) { // slightly adapted from luaL_argerror and luaL_typerror lua_Debug ar; if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ ar.name = "?"; else lua_getinfo(L, "n", &ar); if (ar.name == NULL) ar.name = "?"; luaL_error(L, "cannot convert argument #%d from %s to %s (current stackframe: " LUA_QS " )", index, luaL_typename(L, index), type_name, ar.name); } template <typename T, T RET, bool MARK=false> class DefaultConst { public: DefaultConst(lua_State* L, int index) { if (MARK) lua_pushnil(L); }; static const T ret = RET; }; template <typename T, bool MARK=false> class DefaultInitializer { public: DefaultInitializer(lua_State* L, int index) : ret() { if (MARK) lua_pushnil(L); }; T ret; }; template <typename T> class TypeError { public: TypeError(lua_State* L, int index) : ret() { argError(L, index, typeName<T>::name() ); } T ret; }; template <typename T> class TypeError<T&> { public: TypeError(lua_State* L, int index) : ret() { argError(L, index, typeName<T>::name()); } T* ret; }; template <typename T> class TypeError<const T&> { public: TypeError(lua_State* L, int index) : ret() { argError(L, index, typeName<T>::name()); } T* ret; }; template <> class TypeError<const std::string&> { public: TypeError(lua_State* L, int index) { argError(L, index, typeName<std::string>::name()); } std::string ret; }; template <typename T, typename DEF> T getDefault(lua_State* L, int index) { DEF def(L, index); return def.ret; } class LuaClassData { public: LuaClassData(const std::string& name) { handle = name; } void insertMetaTablePtr(void* ptr) { metaTablePtrs.push_back(ptr); std::sort(metaTablePtrs.begin(), metaTablePtrs.end()); } bool isCompatible(void* ptr) { return std::binary_search(metaTablePtrs.begin(), metaTablePtrs.end(), ptr); } std::string handle; std::vector <void*> metaTablePtrs; }; template <typename T> class LuaClass { public: LuaClass(const std::string& name) { if (!data) { data = new LuaClassData(name); } } ~LuaClass() { if (data) { delete data; data = 0; } } static const char* luahandle() { return data->handle.c_str(); } static T* getPtr(lua_State* L, int index) { void** p = (void**)lua_touserdata(L, index); if (p) if (lua_getmetatable(L, index)) { void* meta = (void*)lua_topointer(L, -1); lua_pop(L, 1); if (data->isCompatible(meta)) return (T*)*p; } //luaL_typerror(L, index, luahandle()); return 0; /* avoid warnings */ } static T** getRawPtr(lua_State* L, int index) { void** p = (void**)lua_touserdata(L, index); if (p) if (lua_getmetatable(L, index)) { void* meta = (void*)lua_topointer(L, -1); lua_pop(L, 1); if (data->isCompatible(meta)) return (T**)p; } //luaL_typerror(L, index, luahandle()); return 0; /* avoid warnings */ } static void packPtr(lua_State* L, T* obj) { T** ptr = (T**)lua_newuserdata(L, sizeof(T*)); *ptr = obj; luaL_getmetatable(L, luahandle()); lua_setmetatable(L, -2); } static LuaClassData* data; }; template <typename T> LuaClassData* LuaClass<T>::data = 0; class AutoReleaseItem { public: AutoReleaseItem() { this->next = autoReleaseList; autoReleaseList = this; } virtual ~AutoReleaseItem() {} AutoReleaseItem* next; }; template <typename T> class EncapsulatedReleaseItem : public AutoReleaseItem { public: T t; EncapsulatedReleaseItem(const T& init) : t(init){} }; template <typename T> class ReleaseReferenceReleaseItem : public AutoReleaseItem { public: T t; ReleaseReferenceReleaseItem(const T& init) : t(init){} ~ReleaseReferenceReleaseItem() { t.releaseReference(); } }; static inline void runAutoRelease() { while (autoReleaseList) { AutoReleaseItem* next = autoReleaseList->next; delete autoReleaseList; autoReleaseList = next; } } class LuaTable { public: int handle; lua_State* my_L; LuaTable() // stub ctor, for default initializers etc { my_L = 0; // make sure missuse of this constructor in code // be noticed quick ;) handle = 0; } LuaTable(lua_State* L) // create a new table and reference { lua_newtable(L); handle = luaL_ref(L, LUA_REGISTRYINDEX); my_L = L; } LuaTable(lua_State* L, int stackIndex) // reference a table on stack { if (lua_type(L, stackIndex) == LUA_TTABLE) { lua_pushvalue(L, stackIndex); handle = luaL_ref(L, LUA_REGISTRYINDEX); my_L = L; } else { my_L = 0; handle = 0; } } LuaTable(const LuaTable& src) { handle = src.handle; my_L = src.my_L; } void push() { lua_rawgeti(my_L, LUA_REGISTRYINDEX, handle); } void autoRelease() { new ReleaseReferenceReleaseItem<LuaTable>(*this); } void releaseReference() { luaL_unref(my_L, LUA_REGISTRYINDEX, handle); my_L = 0; } bool valid() const { return my_L != 0; } operator bool() const { return valid(); } int size() { push(); int result = lua_objlen(my_L, -1); lua_pop(my_L, 1); return result; } bool exists(const char* key) { push(); lua_getfield(my_L, -1, key); bool result = (lua_isnil(my_L, -1) == 0); lua_pop(my_L, 2); return result; } bool exists(int ikey) { push(); lua_pushinteger(my_L, ikey); lua_gettable(my_L, -2); bool result = (lua_isnil(my_L, -1) == 0); lua_pop(my_L, 2); return result; } template <typename T, typename DEF > T getD(const char* key); template <typename T, typename DEF > T getD(int ikey); template <typename T> T get(const char* key) { return getD <T, DefaultInitializer<T> > (key); } template <typename T> T get(int ikey) { return getD <T, DefaultInitializer<T> > (ikey); } template <typename T> T defaultGet(const char* key, T def); template <typename T> T defaultGet(int ikey, T def); template <typename T> void set(const char* key, T obj); template <typename T> void set(int ikey, T obj); }; class LuaFunctionBase { public: virtual bool prepareStack(lua_State* L) = 0; virtual void cleanStack(lua_State* L) = 0; int addValues; }; class Global : public LuaFunctionBase { public: Global(const char* function_name) { addValues = 0; name = function_name; } virtual bool prepareStack(lua_State* L) { lua_pushglobaltable(L); lua_getfield(L, -1, name); if (!lua_isfunction(L, -1)) { lua_pop(L, 1); return false; } return true; } virtual void cleanStack(lua_State* L) {} const char* name; }; class Method : public LuaFunctionBase { public: Method(LuaTable obj, const char* function_name) : table(obj) { addValues = 1; name = function_name; } virtual bool prepareStack(lua_State* L) { if (table.my_L != L) return false; table.push(); lua_getfield(L, -1, name); if (!lua_isfunction(L, -1)) { lua_pop(L, 2); return false; } lua_pushvalue(L, -2); // first arg is self return true; } virtual void cleanStack(lua_State* L) { lua_pop(L, 1); // remove table reference from stack } const char* name; LuaTable table; }; class LuaFunction : public LuaFunctionBase { public: int handle; lua_State* my_L; LuaFunction() // stub ctor, for default initializers etc { my_L = 0; // make sure missuse of this constructor in code // be noticed quick ;) handle = 0; addValues = 0; } LuaFunction(lua_State* L, int stackIndex) // reference a function on stack { if (lua_type(L, stackIndex) == LUA_TFUNCTION) { lua_pushvalue(L, stackIndex); handle = luaL_ref(L, LUA_REGISTRYINDEX); my_L = L; } else { my_L = 0; handle =0; } addValues = 0; } LuaFunction(const LuaFunction& src) { handle = src.handle; my_L = src.my_L; addValues = 0; } virtual ~LuaFunction() {}; virtual bool prepareStack(lua_State* L) { if (my_L != L) return false; lua_rawgeti(my_L, LUA_REGISTRYINDEX, handle); return true; } virtual void cleanStack(lua_State* L) { } void releaseReference() { luaL_unref(my_L, LUA_REGISTRYINDEX, handle); my_L = 0; } }; template <> class typeName<LuaTable> { public: static const char* name() {return "LuaWrapper::LuaTable"; } }; template <> class typeName<LuaFunction> { public: static const char* name() {return "LuaWrapper::LuaFunction"; } }; template <typename T> class typeName { public: static const char* name() { return LuaClass<T>::luahandle(); } }; template <typename T> class typeName<T&> : public typeName<T> {}; template <typename T> class typeName<const T&> : public typeName<T> {}; template <typename T> class typeName<T*> : public typeName<T> {}; template <typename T, typename DEF=TypeError<T> > class Unpack {}; template <typename DEF> class Unpack<int, DEF> { public: static int convert(lua_State* L, int index) { lua_Integer d = lua_tointeger(L, index); if (d == 0 && !lua_isnumber(L, index)) return getDefault<int, DEF>(L, index); return (int) d; } }; template <typename DEF> class Unpack<unsigned int, DEF> { public: static unsigned int convert(lua_State* L, int index) { lua_Integer d = lua_tointeger(L, index); if (d == 0 && !lua_isnumber(L, index)) return getDefault<unsigned int, DEF>(L, index); return (unsigned int) d; } }; template <typename DEF> class Unpack<double, DEF> { public: static double convert(lua_State* L, int index) { lua_Number d = lua_tonumber(L, index); if (d == 0 && !lua_isnumber(L, index)) return getDefault<double, DEF>(L, index); return (double) d; } }; template <typename DEF> class Unpack<bool, DEF> { public: static bool convert(lua_State* L, int index) { if (lua_type(L, index) != LUA_TBOOLEAN) return getDefault<bool, DEF>(L, index); return lua_toboolean(L, index) == 0 ? false : true; } }; template <typename DEF> class Unpack<const char*, DEF> { public: static const char* convert(lua_State* L, int index) { const char* str = lua_tostring(L, index); if (str == 0) return getDefault<const char*, DEF>(L, index); return str; } }; template <typename DEF> class Unpack<std::string, DEF> { public: static std::string convert(lua_State* L, int index) { size_t strlen = 0; const char* str = lua_tolstring(L, index, &strlen); if (str == 0) return getDefault<std::string, DEF>(L, index); return std::string(str, strlen); } }; template <typename DEF> class Unpack<std::string&, DEF> { public: static std::string& convert(lua_State* L, int index) { typedef EncapsulatedReleaseItem<std::string> AutoRelease; AutoRelease* rel; rel = new AutoRelease(Unpack<std::string, DEF>::convert(L, index)); return rel->t; } }; template <typename DEF> class Unpack<const std::string&, DEF> { public: static const std::string& convert(lua_State* L, int index) { typedef EncapsulatedReleaseItem<std::string> AutoRelease; AutoRelease* rel; rel = new AutoRelease(Unpack<std::string, DEF>::convert(L, index)); return rel->t; } }; template <typename DEF> class Unpack<LuaTable, DEF> { public: static LuaTable convert(lua_State* L, int index) { LuaTable t(L, index); if (t.my_L == 0) return getDefault<LuaTable, DEF>(L, index); return t; } }; template <typename DEF> class Unpack<LuaFunction, DEF> { public: static LuaFunction convert(lua_State* L, int index) { LuaFunction f(L, index); if (f.my_L == 0) return getDefault<LuaFunction, DEF>(L, index); return f; } }; template <typename T, typename DEF> class Unpack<T*, DEF> { public: static T* convert(lua_State* L, int index) { T* t=LuaClass<T>::getPtr(L, index); if (t == 0) return getDefault<T*, DEF>(L, index); return t; } }; template <typename T, typename DEF > class Unpack<T&, DEF> { public: static T& convert(lua_State* L, int index) { return *( Unpack<T*, DEF>::convert(L, index) ); } }; template <typename T, typename DEF> class Unpack<const T&, DEF> { public: static const T& convert(lua_State* L, int index) { return *( Unpack<T*, DEF>::convert(L, index) ); } }; template <typename T> class Pack {}; template <> class Pack<int> { public: static void convert(lua_State* L, int value) { lua_pushinteger(L, value); } }; template <> class Pack<unsigned int> { public: static void convert(lua_State* L, unsigned int value) { lua_pushinteger(L, value); } }; template <> class Pack<float> { public: static void convert(lua_State* L, float value) { lua_pushnumber(L, value); } }; template <> class Pack<double> { public: static void convert(lua_State* L, double value) { lua_pushnumber(L, value); } }; template <> class Pack<bool> { public: static void convert(lua_State* L, bool value) { lua_pushboolean(L, value); } }; template <> class Pack<const char*> { public: static void convert(lua_State* L, const char* value) { lua_pushstring(L, value); } }; template <> class Pack<std::string> { public: static void convert(lua_State* L, std::string value) { lua_pushlstring(L, value.c_str(), value.size()); } }; template <> class Pack<std::string&> { public: static void convert(lua_State* L, std::string value) { lua_pushlstring(L, value.c_str(), value.size()); } }; template <> class Pack<const std::string&> { public: static void convert(lua_State* L, std::string value) { lua_pushlstring(L, value.c_str(), value.size()); } }; template <> class Pack<LuaTable> { public: static void convert(lua_State* L, LuaTable value) { value.push(); } }; template <> class Pack<LuaFunction> { public: static void convert(lua_State* L, LuaFunction value) { value.prepareStack(L); } }; template <typename T> class Pack <T*> { public: static void convert(lua_State* L, T* obj) { LuaClass<T>::packPtr(L, obj); } }; template <typename T> class Pack <T&> { public: static void convert(lua_State* L, T& obj) { LuaClass<T>::packPtr(L, *obj); } }; template <typename T, typename DEF> T LuaTable::getD(const char* key) { push(); lua_getfield(my_L, -1, key); T ret = Unpack<T, DEF>::convert(my_L, -1); lua_pop(my_L, 2); return ret; } template <typename T, typename DEF> T LuaTable::getD(int ikey) { push(); lua_pushinteger(my_L, ikey); lua_gettable(my_L, -2); T ret = Unpack<T, DEF>::convert(my_L, -1); lua_pop(my_L, 2); return ret; } template <typename T> T LuaTable::defaultGet(const char* key, T def) { push(); lua_getfield(my_L, -1, key); T ret = Unpack<T, DefaultInitializer<T, true> >::convert(my_L, -1); if (lua_isnil(my_L, -1)) { set(key, def); lua_pop(my_L, 3); return def; } lua_pop(my_L, 2); return ret; } template <typename T> T LuaTable::defaultGet(int ikey, T def) { push(); lua_pushinteger(my_L, ikey); lua_gettable(my_L, -2); T ret = Unpack<T, DefaultInitializer<T, true> >::convert(my_L, -1); if (lua_isnil(my_L, -1)) { set(ikey, def); lua_pop(my_L, 3); return def; } lua_pop(my_L, 2); return ret; } template <typename T> void LuaTable::set(const char* key, T obj) { push(); Pack<T>::convert(my_L, obj); lua_setfield(my_L, -2, key); lua_pop(my_L, 1); } template <typename T> void LuaTable::set(int ikey, T obj) { push(); lua_pushinteger(my_L, ikey); Pack<T>::convert(my_L, obj); lua_settable(my_L, -3); lua_pop(my_L, 1); } template <typename ORIG, typename ALIAS> class UnpackTypedef { public: static ALIAS convert(lua_State* L, int index) { return (ALIAS)Unpack<ORIG>::convert(L, index); } }; template <typename ORIG, typename ALIAS> class PackTypedef { public: static void convert(lua_State* L, ALIAS value) { Pack<ORIG>::convert(L, (ORIG)value); } }; #include "LuaWrappers.hh" // does not need to be expanded in LuaWrappers.hh hackery, since // dtors never take arguments ;) template <typename OBJ> class DtorWrapper { public: typedef OBJ myobjectT; static int Wrapper(lua_State* L) { OBJ** obj = LuaClass<OBJ>::getRawPtr(L, 1); if (*obj) { delete *obj; *obj = 0; } return 0; } static const bool hasmeta = true; static const bool noindex = false; }; template <typename WRAPPER> class ExportToLua { public: typedef typename WRAPPER::myobjectT objectT; ExportToLua(lua_State* L, const char* module_name, const char* function_name) { luaL_Reg entry[2] = {{function_name, WRAPPER::Wrapper}, {NULL, NULL}}; if (WRAPPER::hasmeta) { luaL_getmetatable(L, LuaClass<objectT>::luahandle()); if (strncmp(function_name, "__", 2) != 0 && !WRAPPER::noindex) { lua_getfield(L, -1, "__index"); luaL_register(L, 0, entry); lua_pop(L, 2); } else { // allow direct registration of ctors and __* methods luaL_register(L, 0, entry); lua_pop(L, 1); } } else { luaL_register(L, module_name, entry); } } }; template <typename T> void DeclareToLua(lua_State* L, const char* module_name = 0) { luaL_newmetatable(L, LuaClass<T>::luahandle()); if (module_name) { // drop a reference to the metatable into the module table lua_pushglobaltable(L); luaL_findtable(L, -1, module_name, 1); lua_remove(L, -2); // globaltable lua_pushvalue(L, -2); lua_setfield(L, -2, LuaClass<T>::luahandle()); lua_pop(L, 1); } // create index table lua_newtable(L); lua_setfield(L, -2, "__index"); // remember metatable raw pointer for later type checks LuaClass<T>::data->insertMetaTablePtr((void*)lua_topointer(L, -1)); lua_pop(L, 1); } template <typename BASE, typename DERIVED> void InheritMeta(lua_State* L) { luaL_getmetatable(L, LuaClass<DERIVED>::luahandle()); // -5 lua_getfield(L, -1, "__index"); // -4 luaL_getmetatable(L, LuaClass<BASE>::luahandle()); // -3 lua_getfield(L, -1, "__index"); // -2 lua_pushnil(L); /* -1 first key */ while (lua_next(L, -2) != 0) { lua_pushvalue(L, -2); // copy key and move down lua_insert(L, -3); lua_settable(L, -6); // DERIVED __index at -6 } lua_pop(L, 5); } template <typename BASE, typename DERIVED> void AllowDowncast(lua_State* L) { luaL_getmetatable(L, LuaClass<DERIVED>::luahandle()); LuaClass<BASE>::data->insertMetaTablePtr((void*)lua_topointer(L, -1)); lua_pop(L, 1); } template <typename C> void RegisterValue(lua_State* L, const char* module_name, const char* name, C value) { lua_pushglobaltable(L); luaL_findtable(L, -1, module_name, 1); lua_remove(L, -2); // globaltable Pack<C>::convert(L, value); lua_setfield(L, -2, name); lua_pop(L, 1); } // convenient helper inline void dumpStack (lua_State* L) { int top = lua_gettop(L); for (int i = 1; i <= top; ++i) { int t = lua_type(L, i); switch (t) { case LUA_TSTRING: printf("'%s' ", lua_tostring(L, i)); break; case LUA_TBOOLEAN: printf("%s ", lua_toboolean(L, i) ? "true" : "false"); break; case LUA_TNUMBER: printf("%g ", lua_tonumber(L, i)); break; default: printf("%s ", lua_typename(L, t)); break; } } printf("\n"); } inline void insertLoader(lua_State* L, int (*fptr)(lua_State* L)) { lua_pushglobaltable(L); luaL_findtable(L, -1, "package.loaders", 0); LuaWrapper::LuaTable loaders(L, -1); lua_pop(L, 2); int i = 1; while (loaders.exists(i)) ++i; // move all loaders by one, to insert ours at the first index for (; i > 0; --i) { loaders.push(); // tables registry handle lua_pushinteger(L, i); if (i > 1) { lua_pushinteger(L, i - 1); lua_gettable(L, -3); lua_settable(L, -3); } else { lua_pushcclosure(L, fptr, 0); lua_settable(L, -3); } lua_pop(L, 1); // table ref } loaders.releaseReference(); } } // some convenient defines: #define ToLuaTypedef(ORIG, ALIAS) \ namespace LuaWrapper { \ template <> class Unpack<ALIAS>:public UnpackTypedef<ORIG, ALIAS>{}; \ template <> class Pack<ALIAS>:public PackTypedef<ORIG, ALIAS>{}; } #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Limits.hh�����������������������������������������������������������������0000644�0000764�0000764�00000003740�10311256605�015651� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/Limits.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* Short Description: * Numeric limit templates. */ #ifndef UTILITY__LIMITS_HH__ #define UTILITY__LIMITS_HH__ namespace Utility { template <class U, class V> inline const U limit_min (const U& value, const V& min) { if (value < min) //__attribute__((unlikely)) return min; else return value; }; template <class U, class V> inline const U limit_max (const U& value, const V& max) { if (value > max) //__attribute__((unlikely)) return max; else return value; }; // should only be used when min < max ... !! template <class U, class V, class W> inline const U limit_min_max (const U& value, const V& min, const W& max) { // TODO: warn if debug and min > max !! if (value < min) //__attribute__((unlikely)) return min; else if (value > max) //__attribute__((unlikely)) return max; else return value; }; } // end namespace utility #endif // UTILITY__LIMITS_HH__ ��������������������������������exact-image-0.9.1/utility/Logger.hh�����������������������������������������������������������������0000644�0000764�0000764�00000014404�10430056565�015633� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/Logger.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef UTILITY__LOGGER_HH__ #define UTILITY__LOGGER_HH__ #include "SplitStreamBuffer.hh" #include <fstream> #include "TypeInformation.hh" namespace Utility { class LogDeviceConfig { public: static const bool disabled = false; // no logging on this device at all static const bool thread_save = false; // not supported yet... static const bool do_timestamping = true; // print nummeric timestamps after writing to a different logdevice static const bool print_log_prelude = true; // print time and date when creating/switching logfile //TODO: static const bool output_logfile_acces_errors = true; // print message to stderr on write errors static const bool redirect_to_stdout_on_error = true; // redirect all content to stdout after printing error message }; class LogDestinationConfig { public: static const bool echo_log_stdout = false; // log output will be branched to stdout static const bool log_to_file = true; // log output will be branched into file static const bool function_names_in_log = false; // log messages will be prefixed with pretty function name static const bool context_in_log = false; // log messages will be prefixed with context string static const bool echo_warn_stderr = true; // warn options in analogy to log options static const bool warn_to_file = true; static const bool function_names_in_warn = true; static const bool context_in_warn = true; }; // WL_TRAITS predefined configs class WL_Quiet { public: static const bool warn = false; static const bool log = false; }; class WL_Warn { public: static const bool warn = true; static const bool log = false; }; class WL_Verbose { public: static const bool warn = true; static const bool log = true; }; class BasicLogDevice { protected: typedef uint64_t timestamp_t; typedef enum {std,file,both} direction; static timestamp_t current; static direction last_direction; static BasicLogDevice* last_device; BasicLogDevice (); bool TimeStamp (direction d); void PrintPrelude (); void PrintTimeStamp (std::ostream* str); void AllocateSplitStreams (); void DeallocateSplitStreams (); SplitStreamBuffer* split_buffer_cout; SplitStreamBuffer* split_buffer_cerr; std::ostream* split_stream_cout; std::ostream* split_stream_cerr; std::ofstream* log_file; }; template <typename LDEVC = LogDeviceConfig> class LogDevice : public BasicLogDevice { public: typedef LDEVC Config; LogDevice (std::ofstream& logfile); LogDevice (); ~LogDevice (); void SwitchLogFile (std::ofstream& logfile); void NoLogFile (); template <typename LDESC> std::ostream& SplitLog (); template <typename LDESC> std::ostream& SplitWarn (); protected: direction DetermineDirection (const bool to_std, const bool to_file); }; template <typename LDESC, typename LDEVC> class LogDestination { public: typedef LogDevice <LDEVC> Device; typedef typename LogDevice <LDEVC>::Config DeviceConfig; LogDestination (std::string i_context, Device& i_device); inline bool DoLog () {return (!LDEVC::disabled) && (LDESC::echo_log_stdout || LDESC::log_to_file);} inline bool DoWarn () {return (!LDEVC::disabled) && (LDESC::echo_warn_stderr || LDESC::warn_to_file);} std::ostream& Log (); std::ostream& Warn (); protected: std::string context; Device& device; }; template <typename LDESC, typename LDEVC, typename WL_TRAITS> class Logger { public: typedef LogDestination <LDESC, LDEVC> Destination; Logger (Destination& i_destination); inline bool DoLog () {return destination.DoLog () && WL_TRAITS::log; } inline bool DoWarn () {return destination.DoLog () && WL_TRAITS::warn; } std::ostream& Log (const char* pretty_function_name); std::ostream& Warn (const char* pretty_function_name); private: Destination& destination; }; template <typename LDESC, typename LDEVC, typename WL_TRAITS, typename OBJ> class ObjectLogger : public Logger <LDESC, LDEVC, WL_TRAITS> { public: typedef typename Logger <LDESC, LDEVC, WL_TRAITS>::Destination Destination; ObjectLogger (Destination& i_destination, OBJ* i_parent); ~ObjectLogger (); std::ostream& Log (const char* pretty_function_name); std::ostream& Warn (const char* pretty_function_name); private: OBJ* parent; }; // we export cout and cerr to avoid <iostream> inclusion extern std::ostream& wrap_cout; extern std::ostream& wrap_cerr; } // end namespace Utility // now we do some nasty preprocessor stuff... #ifdef Q_LOG # ifndef UTILITY__CUSTOM_Q_LOG__ # warning "the Q_LOG macro is already defined" # endif #else # define Q_LOG(logger) if (logger.DoLog ()) logger.Log (__PRETTY_FUNCTION__) #endif #ifdef Q_WARN # ifndef UTILITY__CUSTOM_Q_WARN__ # warning "the Q_WARN macro is already defined" # endif #else # define Q_WARN(logger) if (logger.DoWarn ()) logger.Warn (__PRETTY_FUNCTION__) #endif #define UTILITY__LOGGER_TMPL__ #include "template/Logger.tcc" #undef UTILITY__LOGGER_TMPL__ #endif // UTILITY__LOGGER_HH__ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Timer.cc������������������������������������������������������������������0000644�0000764�0000764�00000010247�11354370452�015463� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/src/Timer.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2010 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* * Alternatively, commercial licensing options are available from the * copyright holder ExactCODE GmbH Germany. */ #include "Timer.hh" #include <sys/types.h> #include <sys/stat.h> #ifdef _WIN32 #include <windows.h> // Sleep() #else #include <unistd.h> #endif #include <iostream> #ifndef _WIN32 Utility::TickTimer::TickTimer () { times (&m_times); } void Utility::TickTimer::Reset () { times (&m_times); } uint64_t Utility::TickTimer::Delta () const { tms t_times; times (&t_times); return t_times.tms_utime - m_times.tms_utime; } uint64_t Utility::TickTimer::Value () const { tms t_times; times (&t_times); return t_times.tms_utime; } uint64_t Utility::TickTimer::PerSecond () const { return sysconf (_SC_CLK_TCK); } #endif // --- Utility::TimebaseTimer::TimebaseTimer () { start_tick = Value (); } void Utility::TimebaseTimer::Reset () { start_tick = Value (); } uint64_t Utility::TimebaseTimer::Delta () const { return Value () - start_tick; } uint64_t Utility::TimebaseTimer::Value () const { #if defined(__i386__) || defined(_MSC_VER) #ifdef _MSC_VER uint32_t lo, hi; __asm rdtsc __asm mov lo, eax __asm mov hi, edx return ((uint64_t)hi << 32) | lo; #else uint64_t x; __asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (x)); return x; #endif #elif defined(__x86_64__) uint32_t hi, lo; __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); return ((uint64_t)hi << 32) | lo; #elif defined(__powerpc64__) uint64_t x; __asm__ __volatile__ ( "\tmftb %0" : "=r"(x) ); return x; #elif defined(__powerpc__) || defined(__ppc__) uint32_t hi, lo, tmp; __asm__ __volatile__ ( "0: \n" "\tmftbu %0 \n" "\tmftb %1 \n" "\tmftbu %2 \n" "\tcmpw %2,%0 \n" "\tbne 0b \n" : "=r"(hi),"=r"(lo),"=r"(tmp) ); return ((uint64_t)hi << 32) | lo; #elif defined(__sparc_v9__) #ifdef __LP64__ uint64_t ticks; __asm__ volatile( "rd %%tick, %0\n" : "=r" (ticks) // : "0" (ticks) ); return ticks; #else uint32_t hi, lo; __asm__ volatile( "rd %%tick,%%g3\n" "\tor %%g3,0,%0\n" // lower bits "\tsrlx %%g3,32,%%g3\n" "\tor %%g3,0,%1" // higher bits : "=r" (lo), "=r" (hi) ); return ((uint64_t)hi << 32) | lo; #endif #elif defined(__mips__) unsigned int ticks; __asm__ __volatile__ ("dmfc0 %0,$9" : "=r" (ticks)); return ticks; #elif defined(__ia64__) unsigned int ticks; __asm__ __volatile__ ("mov %0=ar.itc ;;" : "=rO" (ticks)); return ticks; #elif defined(__bfin__) unsigned int ticks; __asm__ __volatile__ ("%0 = CYCLES;\n\t" : "=&d" (ticks) : : "R1"); return ticks #else // TODO (at least): Alpha, ARM, AVR32, SuperH, ... #warning "No CPU timebase read implemented for this architecture, yet!" return 0; #endif } uint64_t Utility::TimebaseTimer::PerSecond () const { static uint64_t per_second = 0; // meassure, not yet very accurate, depends on a exact 1s schedule of the OS if (!per_second) { uint64_t s1 = Value (); #ifndef _WIN32 sleep (1); #else Sleep (1000); #endif uint64_t s2 = Value (); per_second = s2 - s1; } return per_second; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Timer.hh������������������������������������������������������������������0000644�0000764�0000764�00000006274�11207524252�015476� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/Timer.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2008 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* * Alternatively, commercial licensing options are available from the * copyright holder ExactCODE GmbH Germany. */ /* Short Description: * Some basic timer classes. */ #ifndef UTILITY__TIMER_HH__ #define UTILITY__TIMER_HH__ #ifndef _WIN32 #include <sys/time.h> // used by Timer #include <sys/times.h> // used by TickTimer #else #include <sys/types.h> #include <sys/timeb.h> #endif #include <inttypes.h> #include <iostream> #include <string> namespace Utility { class Timer { public: Timer () { Reset (); } void Reset () { m_start = Value(); } uint64_t Delta () const { return Value() - m_start; } inline uint64_t PerSecond () const { return 1000000; } uint64_t Value () const { #if !defined(_MSC_VER) timeval t_time; gettimeofday (&t_time, NULL); return (t_time.tv_sec * PerSecond()) + t_time.tv_usec; #else struct timeb tb; ftime(&tb); return (uint64_t)tb.time * PerSecond() + tb.millitm * 1000; #endif } const char* Unit () const { return "us"; } private: uint64_t m_start; }; #ifndef _WIN32 class TickTimer { public: TickTimer (); void Reset (); uint64_t Delta () const; uint64_t PerSecond () const; uint64_t Value () const; const char* Unit () const { return "us"; } private: struct tms m_times; }; #endif class TimebaseTimer { public: TimebaseTimer (); void Reset (); uint64_t Delta () const; uint64_t PerSecond () const; uint64_t Value () const; const char* Unit () const { return "cycles"; } private: uint64_t start_tick; }; template <typename T> class AutoTimer { public: AutoTimer (const std::string& i_text) { m_text = i_text; } ~AutoTimer () { std::cout << ">> AutoTimer: \"" << m_text << "\" took: " << m_timer.Delta () << " " << m_timer.Unit () << std::endl; } uint64_t Delta () const { return m_timer.Delta (); } uint64_t PerSecond () const { return m_timer.PerSecond (); } private: T m_timer; std::string m_text; }; } // end namespace utility #endif // UTILITY__TIMER_HH__ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/SplitStreamBuffer.hh������������������������������������������������������0000644�0000764�0000764�00000003542�10311256605�020011� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/SplitStreamBuffer.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef UTILITY__SPLITSTREAMBUFFER_HH__ #define UTILITY__SPLITSTREAMBUFFER_HH__ #include <ostream> namespace Utility { // a std::streambuffer implementation that forwards output to two // std::ostreams. Usage example (w.o. namespaces): // // ostream (new SplitStreamBuffer (cout, logfile)) logstream; // logstream << "Hello world" << endl; class SplitStreamBuffer : public std::streambuf { public: SplitStreamBuffer (std::ostream& forward1, std::ostream& forward2) : fw1(forward1), fw2(forward2) { } protected: virtual int_type overflow (int_type c); std::ostream& fw1; std::ostream& fw2; }; } // end namespace Utility #define UTILITY__SPLITSTREAMBUFFER_TMPL__ #include "template/SplitStreamBuffer.tcc" #undef UTILITY__SPLITSTREAMBUFFER_TMPL__ #endif // UTILITY__SPLITSTREAMBUFFER_HH__ ��������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/LuaWrappers.hh������������������������������������������������������������0000644�0000764�0000764�00000027650�12461460550�016667� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008-2015 René Rebe, ExactCODE GmbH * Copyright (C) 2008 Valentin Ziegler, 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. */ // The aim of this file is to create code for // FunctionWrapper_*_* and MethodWrapper_*_* classes // as well as the Call_*_* functions // Hint: if you want a more readable version of this file, // use g++ -E // Sorry for the grave hack, // c++ templates definitly suck at variadic signatures... // please port me to the next c++ standard !! // the macro hackery in this file iterates from N = 7 to N = 0 // and includes this file once for each iteration. // name(X) is X##N // ai(X) is "X" if i <= N, ignored otherwise // aic(X) is ",X" if i <= N, ignored otherwise // comma is "," if i >= 0 // a0(X) is "X" if i == 0 #ifndef N #define N 8 #define comma , #define a0(X) #define a1(X) X #define a1c(X) ,X #define a2(X) X #define a2c(X) ,X #define a3(X) X #define a3c(X) ,X #define a4(X) X #define a4c(X) ,X #define a5(X) X #define a5c(X) ,X #define a6(X) X #define a6c(X) ,X #define a7(X) X #define a7c(X) ,X #define a8(X) X #define a8c(X) ,X #define name(X) X##8 #elif N > 7 #undef N #undef name #undef a8 #undef a8c #define N 7 #define a8(X) #define a8c(X) #define name(X) X##7 #elif N > 6 #undef N #undef name #undef a7 #undef a7c #define N 6 #define a7(X) #define a7c(X) #define name(X) X##6 #elif N > 5 #undef N #undef name #undef a6 #undef a6c #define N 5 #define a6(X) #define a6c(X) #define name(X) X##5 #elif N > 4 #undef N #undef name #undef a5 #undef a5c #define N 4 #define a5(X) #define a5c(X) #define name(X) X##4 #elif N > 3 #undef N #undef name #undef a4 #undef a4c #define N 3 #define a4(X) #define a4c(X) #define name(X) X##3 #elif N > 2 #undef N #undef name #undef a3 #undef a3c #define N 2 #define a3(X) #define a3c(X) #define name(X) X##2 #elif N > 1 #undef N #undef name #undef a2 #undef a2c #define N 1 #define a2(X) #define a2c(X) #define name(X) X##1 #elif N > 0 #undef N #undef comma #undef name #undef a1 #undef a1c #define N 0 #define comma #define a1(X) #define a1c(X) #define name(X) X##0 #undef a0 #define a0(X) X #endif // content starts here template < typename RET a1c(typename P1) a2c(typename P2) a3c(typename P3) a4c(typename P4) a5c(typename P5) a6c(typename P6) a7c(typename P7) a8c(typename P8), RET (*F)(a1(P1)a2c(P2)a3c(P3)a4c(P4)a5c(P5)a6c(P6)a7c(P7)a8c(P8))> class name(FunctionWrapper_1_) { public: typedef void myobjectT; static int Wrapper(lua_State* L) { Pack<RET>::convert(L, F(a1(Unpack<P1>::convert(L, 1)) a2c(Unpack<P2>::convert(L, 2)) a3c(Unpack<P3>::convert(L, 3)) a4c(Unpack<P4>::convert(L, 4)) a5c(Unpack<P5>::convert(L, 5)) a6c(Unpack<P6>::convert(L, 6)) a7c(Unpack<P7>::convert(L, 7)) a8c(Unpack<P8>::convert(L, 8)) )); runAutoRelease(); return 1; } static const bool hasmeta = false; static const bool noindex = true; }; template < a1(typename P1) a2c(typename P2) a3c(typename P3) a4c(typename P4) a5c(typename P5) a6c(typename P6) a7c(typename P7) a8c(typename P8) comma void (*F)(a1(P1)a2c(P2)a3c(P3)a4c(P4)a5c(P5)a6c(P6)a7c(P7)a8c(P8))> class name(FunctionWrapper_0_) { public: typedef void myobjectT; static int Wrapper(lua_State* L) { F(a1(Unpack<P1>::convert(L, 1)) a2c(Unpack<P2>::convert(L, 2)) a3c(Unpack<P3>::convert(L, 3)) a4c(Unpack<P4>::convert(L, 4)) a5c(Unpack<P5>::convert(L, 5)) a6c(Unpack<P6>::convert(L, 6)) a7c(Unpack<P7>::convert(L, 7)) a8c(Unpack<P7>::convert(L, 8)) ); runAutoRelease(); return 0; } static const bool hasmeta = false; static const bool noindex = true; }; template < a1(typename P1) a2c(typename P2) a3c(typename P3) a4c(typename P4) a5c(typename P5) a6c(typename P6) a7c(typename P7) a8c(typename P8) comma int (*F)(lua_State* a1c(P1)a2c(P2)a3c(P3)a4c(P4)a5c(P5)a6c(P6)a7c(P7)a8c(P8))> class name(FunctionWrapper_N_) { public: typedef void myobjectT; static int Wrapper(lua_State* L) { int n = F(L a1c(Unpack<P1>::convert(L, 1)) a2c(Unpack<P2>::convert(L, 2)) a3c(Unpack<P3>::convert(L, 3)) a4c(Unpack<P4>::convert(L, 4)) a5c(Unpack<P5>::convert(L, 5)) a6c(Unpack<P6>::convert(L, 6)) a7c(Unpack<P7>::convert(L, 7)) a8c(Unpack<P7>::convert(L, 8)) ); runAutoRelease(); return n; } static const bool hasmeta = false; static const bool noindex = true; }; template < typename OBJ, typename DEFOBJ, typename RET a1c(typename P1) a2c(typename P2) a3c(typename P3) a4c(typename P4) a5c(typename P5) a6c(typename P6) a7c(typename P7) a8c(typename P8) , RET (DEFOBJ::*F)(a1(P1)a2c(P2)a3c(P3)a4c(P4)a5c(P5)a6c(P6)a7c(P7)a8c(P8))> class name(MethodWrapper_1_) { public: typedef OBJ myobjectT; static int Wrapper(lua_State* L) { RET (DEFOBJ::*f)(a1(P1)a2c(P2)a3c(P3)a4c(P4)a5c(P5)a6c(P6)a7c(P7)a8c(P8)) = F; OBJ* obj = Unpack<OBJ*>::convert(L, 1); Pack<RET>::convert(L, (obj->*f)(a1(Unpack<P1>::convert(L, 2)) a2c(Unpack<P2>::convert(L, 3)) a3c(Unpack<P3>::convert(L, 4)) a4c(Unpack<P4>::convert(L, 5)) a5c(Unpack<P5>::convert(L, 6)) a6c(Unpack<P6>::convert(L, 7)) a7c(Unpack<P7>::convert(L, 8)) a8c(Unpack<P8>::convert(L, 9)) )); runAutoRelease(); return 1; } static const bool hasmeta = true; static const bool noindex = false; }; template < typename OBJ, typename DEFOBJ a1c(typename P1) a2c(typename P2) a3c(typename P3) a4c(typename P4) a5c(typename P5) a6c(typename P6) a7c(typename P7) a8c(typename P8) , void (DEFOBJ::*F)(a1(P1)a2c(P2)a3c(P3)a4c(P4)a5c(P5)a6c(P6)a7c(P7)a8c(P8))> class name(MethodWrapper_0_) { public: typedef OBJ myobjectT; static int Wrapper(lua_State* L) { void (DEFOBJ::*f)(a1(P1)a2c(P2)a3c(P3)a4c(P4)a5c(P5)a6c(P6)a7c(P7)a8c(P8)) = F; OBJ* obj = Unpack<OBJ*>::convert(L, 1); (obj->*f)(a1(Unpack<P1>::convert(L, 2)) a2c(Unpack<P2>::convert(L, 3)) a3c(Unpack<P3>::convert(L, 4)) a4c(Unpack<P4>::convert(L, 5)) a5c(Unpack<P5>::convert(L, 6)) a6c(Unpack<P6>::convert(L, 7)) a7c(Unpack<P7>::convert(L, 8)) a8c(Unpack<P8>::convert(L, 9)) ); runAutoRelease(); return 0; } static const bool hasmeta = true; static const bool noindex = false; }; template < typename OBJ, typename DEFOBJ a1c(typename P1) a2c(typename P2) a3c(typename P3) a4c(typename P4) a5c(typename P5) a6c(typename P6) a7c(typename P7) a8c(typename P8) , int (DEFOBJ::*F)(lua_State* a1c(P1)a2c(P2)a3c(P3)a4c(P4)a5c(P5)a6c(P6)a7c(P7)a8c(P8))> class name(MethodWrapper_N_) { public: typedef OBJ myobjectT; static int Wrapper(lua_State* L) { int (DEFOBJ::*f)(lua_State* a1c(P1)a2c(P2)a3c(P3)a4c(P4)a5c(P5)a6c(P6)a7c(P7)a8c(P8)) = F; OBJ* obj = Unpack<OBJ*>::convert(L, 1); int n = (obj->*f)(L a1c(Unpack<P1>::convert(L, 2)) a2c(Unpack<P2>::convert(L, 3)) a3c(Unpack<P3>::convert(L, 4)) a4c(Unpack<P4>::convert(L, 5)) a5c(Unpack<P5>::convert(L, 6)) a6c(Unpack<P6>::convert(L, 7)) a7c(Unpack<P7>::convert(L, 8)) a8c(Unpack<P8>::convert(L, 9)) ); runAutoRelease(); return n; } static const bool hasmeta = true; static const bool noindex = false; }; template < typename OBJ a1c(typename P1) a2c(typename P2) a3c(typename P3) a4c(typename P4) a5c(typename P5) a6c(typename P6) a7c(typename P7) a8c(typename P8) > class name(CtorWrapper_) { public: typedef OBJ myobjectT; static int Wrapper(lua_State* L) { Pack<OBJ*>::convert(L, new OBJ(a1(Unpack<P1>::convert(L, 1)) a2c(Unpack<P2>::convert(L, 2)) a3c(Unpack<P3>::convert(L, 3)) a4c(Unpack<P4>::convert(L, 4)) a5c(Unpack<P5>::convert(L, 5)) a6c(Unpack<P6>::convert(L, 6)) a7c(Unpack<P7>::convert(L, 7)) a8c(Unpack<P8>::convert(L, 8)) )); runAutoRelease(); return 1; } static const bool hasmeta = true; static const bool noindex = true; }; template < typename OBJ a1c(typename P1) a2c(typename P2) a3c(typename P3) a4c(typename P4) a5c(typename P5) a6c(typename P6) a7c(typename P7) a8c(typename P8) > class name(CtorWrapper_N_) { public: typedef OBJ myobjectT; static int Wrapper(lua_State* L) { Pack<OBJ*>::convert(L, new OBJ(L comma a1(Unpack<P1>::convert(L, 1)) a2c(Unpack<P2>::convert(L, 2)) a3c(Unpack<P3>::convert(L, 3)) a4c(Unpack<P4>::convert(L, 4)) a5c(Unpack<P5>::convert(L, 5)) a6c(Unpack<P6>::convert(L, 6)) a7c(Unpack<P7>::convert(L, 7)) a8c(Unpack<P8>::convert(L, 8)) )); runAutoRelease(); return 1; } static const bool hasmeta = true; static const bool noindex = true; }; template < typename RET a1c(typename P1) a2c(typename P2) a3c(typename P3) a4c(typename P4) a5c(typename P5) a6c(typename P6) a7c(typename P7) a8c(typename P8) , typename DEF > RET name(Call_1_)(lua_State* L, LuaFunctionBase& f a1c(P1 p1)a2c(P2 p2)a3c(P3 p3)a4c(P4 p4)a5c(P5 p5)a6c(P6 p6)a7c(P7 p7)a8c(P8 p8)) { if (f.prepareStack (L)) { a1(Pack<P1>::convert(L, p1);) a2(Pack<P2>::convert(L, p2);) a3(Pack<P3>::convert(L, p3);) a4(Pack<P4>::convert(L, p4);) a5(Pack<P5>::convert(L, p5);) a6(Pack<P6>::convert(L, p6);) a7(Pack<P7>::convert(L, p7);) a8(Pack<P8>::convert(L, p8);) if (lua_pcall(L, N + f.addValues, 1, 0)) { std::string err = lua_tostring(L, -1); lua_pop(L, 1); throw std::runtime_error(err); } RET val = Unpack<RET, DEF>::convert(L, -1); lua_pop(L, 1); // pop the returned value f.cleanStack(L); return val; } else return getDefault<RET, DEF>(L, -1); } template < typename RET a1c(typename P1) a2c(typename P2) a3c(typename P3) a4c(typename P4) a5c(typename P5) a6c(typename P6) a7c(typename P7) a8c(typename P8) > RET name(Call_1_)(lua_State* L, LuaFunctionBase& f a1c(P1 p1)a2c(P2 p2)a3c(P3 p3)a4c(P4 p4)a5c(P5 p5)a6c(P6 p6)a7c(P7 p7)a8c(P8 p8)) { return name(Call_1_)<RET a1c(P1) a2c(P2) a3c(P3) a4c(P4) a5c(P5) a6c(P6) a7c(P7) a8c(P8), DefaultInitializer<RET> >( L, f a1c(p1) a2c(p2) a3c(p3) a4c(p4) a5c(p5) a6c(p6) a7c(p7) a8c(p8) ); } a1(template < a1(typename P1) a2c(typename P2) a3c(typename P3) a4c(typename P4) a5c(typename P5) a6c(typename P6) a7c(typename P7) a8c(typename P8) >) static void #ifdef __GNUC__ __attribute__((unused)) #endif name(Call_0_)(lua_State* L, LuaFunctionBase& f a1c(P1 p1)a2c(P2 p2)a3c(P3 p3)a4c(P4 p4)a5c(P5 p5)a6c(P6 p6)a7c(P7 p7)a8c(P8 p8)) { if (f.prepareStack(L)) { a1(Pack<P1>::convert(L, p1);) a2(Pack<P2>::convert(L, p2);) a3(Pack<P3>::convert(L, p3);) a4(Pack<P4>::convert(L, p4);) a5(Pack<P5>::convert(L, p5);) a6(Pack<P6>::convert(L, p6);) a7(Pack<P7>::convert(L, p7);) a8(Pack<P8>::convert(L, p8);) if (lua_pcall(L, N + f.addValues, 0, 0)) { std::string err = lua_tostring(L, -1); lua_pop(L, 1); throw std::runtime_error(err); } f.cleanStack(L); } } // content end #if N > 0 #include "LuaWrappers.hh" #else #undef N #undef a0 #undef a1 #undef a1c #undef a2 #undef a2c #undef a3 #undef a3c #undef a4 #undef a4c #undef a5 #undef a5c #undef a6 #undef a6c #undef a7 #undef a7c #undef a8 #undef a8c #undef name #endif ����������������������������������������������������������������������������������������exact-image-0.9.1/utility/Logger.cc�����������������������������������������������������������������0000644�0000764�0000764�00000004443�10311256605�015616� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/src/Logger.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include "Logger.hh" #include <time.h> #include <iostream> namespace Utility { // Exports bool basic_log_device_initialized = false; extern BasicLogDevice::timestamp_t BasicLogDevice::current; extern BasicLogDevice::direction BasicLogDevice::last_direction; extern BasicLogDevice* BasicLogDevice::last_device; std::ostream& wrap_cout = std::cout; std::ostream& wrap_cerr = std::cerr; } using namespace Utility; BasicLogDevice::BasicLogDevice () { if (!basic_log_device_initialized) { current = true; last_device = this; basic_log_device_initialized = true; } } void BasicLogDevice::PrintPrelude () { time_t t; time (&t); (*log_file) << "log opened " << ctime(&t) << std::endl; } void BasicLogDevice::PrintTimeStamp (std::ostream* str) { (*str) << "[@t" << current++ << "] "; } void BasicLogDevice::AllocateSplitStreams () { split_buffer_cout = new SplitStreamBuffer (std::cout, *log_file); split_buffer_cerr = new SplitStreamBuffer (std::cerr, *log_file); split_stream_cout = new std::ostream (split_buffer_cout); split_stream_cerr = new std::ostream (split_buffer_cerr); } void BasicLogDevice::DeallocateSplitStreams () { delete split_stream_cout; delete split_stream_cerr; delete split_buffer_cout; delete split_buffer_cerr; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Storage.cc����������������������������������������������������������������0000644�0000764�0000764�00000005122�10311256605�015776� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/src/Storage.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include "Storage.hh" #include "template/Storage.tcc" #include <sstream> using namespace Utility; void Serializer::Add (BasicStorage* storage) { content [storage->name] = storage; } std::istream& Serializer::Read (std::istream& is, bool verbose) { char seperator = '='; std::vector<char> comments; comments.push_back (';'); comments.push_back ('#'); // TODO: error handling std::string line; while (std::getline (is, line)) { // strip comments for (std::vector<char>::iterator comment = comments.begin (); comment != comments.end (); ++comment) { std::string::size_type it = line.find (*comment); if (it != std::string::npos) { line.erase (it, line.size () ); } } // s.th. left to parse? if (line.size() > 0) { std::stringstream streamline (line); std::string key, sep, value; streamline >> key >> sep; if (sep.size() == 1 && sep[0] == seperator) { std::map<std::string, BasicStorage*>::iterator it = content.find (key); if (it != content.end () ) { it->second->Read(streamline); } else { if (verbose) std::cout << "Key " << key << " not registered!" << std::endl; } } else { if (verbose) std::cout << "Parse error - no key found in line!" << std::endl; } } } // end while /* debug std::map<std::string, BasicStorage*>::iterator it; for (it = content.begin (); it != content.end(); ++it) { std::cout << "-> " << it->second->name << ": "; it->second->Write(std::cout) << std::endl; } */ return is; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Delete.hh�����������������������������������������������������������������0000644�0000764�0000764�00000003076�10311256605�015614� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/Delete.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* Short Description: * Object delete function and functor - to help deleting objects e.g. * with STL algorithms. */ #ifndef UTILITY__DELETE_HH__ #define UTILITY__DELETE_HH__ namespace Utility { template <typename T> void DelFunction (T& del_obj) { delete del_obj; del_obj = 0; } // to delete container of objects via for_each ... template <typename T> class DelFunctor { public: void operator () (T& del_obj) { DelFunction <T> (del_obj); } }; } // end namespace utility #endif // UTILITY__DELETE_HH__ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Makefile������������������������������������������������������������������0000644�0000764�0000764�00000002265�10624034750�015532� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# --- GSMP-COPYRIGHT-NOTE-BEGIN --- # # This copyright note is auto-generated by ./scripts/Create-CopyPatch. # Please add additional copyright information _after_ the line containing # the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by # the ./scripts/Create-CopyPatch script. Do not edit this copyright text! # # GSMP: utility/src/Makefile # General Sound Manipulation Program is Copyright (C) 2000 - 2004 # Valentin Ziegler and René Rebe # # 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. # # --- GSMP-COPYRIGHT-NOTE-END --- NOT_INCS := BinomiHeap.hh include build/top.make BINARY = libgsmutil BINARY_EXT = $(X_DYNEXT) DEPS = CXXFLAGS += -I utility/ LDFLAGS += $(SIGC2LIBS) # -ldl -pthread include build/bottom.make �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/BinomiHeap.hh�������������������������������������������������������������0000644�0000764�0000764�00000016227�10311256605�016427� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/BinomiHeap.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef BIN_HEAP_HH #define BIN_HEAP_HH /************************************************************ * * Ein binaerer Heap mit statischer Groesse [Size ()] * welche initial festzulegen ist. * * Schablonenklasse mit Parametern * * ITEM_T : Typ des Elementes * KEY_T : Typ der Schluessel * RANGE_CHECKING : entweder BinomiHeap_Checking, um auf * ungueltige ID's, Schluesselwerte * etc testen lassen * oder BinomiHeap_NoChecking; Keine Tests, * keine Exceptions, dafuer effizientes * Laufzeitverhalten * oder Selbstimplementiere Klasse, welche * gleichnamige Methoden exportiert. * * Bei komplexem Elementtyp sollte aus Effizienzgruenden ein * Pointer als ITEM_T verwendet werden. * * Folgende naive / ueberladene Operatoren muessen von KEY_T * bereitgestellt werden: * * operator < * operator > * operator = * KEY_T (const KEY_T&) * * Fuer Zugriffe auf Elemente im Heap wird eine numerische ID * vom typen int aus dem intervall [ 0, Size ) verwendet. * ***********************************************************/ // Exceptions // werden geworfen, falls als Rangechecker BinomiHeap_Exceptions verwended wird class InvalidIdException {}; // ungueltige ID in uebergebenem Parameter class DuplicateIdException {}; // ID zum zweiten Male eingefuegt class HeapEmptyException {}; // Heap ist leer (bei ExtractMin) class HeapFullException {}; // Heap ist voll (bei Insert) class InvalidKeyException {}; // neuer Schluessel groesser als alter (bei DecreaseKey) template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> class BinomiHeap { public: BinomiHeap (int maximal_size); // Constructor. [maximal_size] legt Groesse des Heaps fest ~BinomiHeap (); /************** oeffentliche Heapoperationen *******************/ // Element [item] mit Schluessel [key] einfuegen. Zugriffs-ID [id]. // Bei Verwendung von BinomiHeap_Checking: // wirft InvalidIdException, falls id nicht innerhalb [ 0, Size ) // wirft DuplicateIdException, falls id bereits in Verwendung void Insert (ITEM_T item, KEY_T key, int id); // Element mit minimalem Key zurueckliefern und aus Heap entfernen // Bei Verwendung von BinomiHeap_Checking: // wirft HeapEmptyException, falls Heap leer. ITEM_T ExtractMin (); // Schluessel des Elementes mit ID [id] erniedrigen // Bei Verwendung von BinomiHeap_Checking: // wirft InvalidKeyException, falls neuer Schluessel groesser als alter void DecreaseKey (KEY_T new_key, int id); //********************* Informationen **************************/ // liefert (statische) Groesse des Heaps zurueck inline int Size (); // liefert momentane Anzahl enthaltener Elemente zurueck inline int CurSize (); // Heap leer? inline bool Empty (); // aktueller Schluessel des Elementes mit ID [id] // Bei Verwendung von BinomiHeap_Checking: // wirft InvalidIdException KEY_T GetKey (int id); // Element der ID [id] // Bei Verwendung von BinomiHeap_Checking: // wirft InvalidIdException ITEM_T GetItem (int id); // ************************************************************/ private: class Node { // repraesentiert Knotenpunkt des Heap public: ITEM_T item; KEY_T key; int id; }; int max_size; // maximale Anzahl von Elementen int cur_size; // aktuelle Anzahl von Elementen Node** real_node_map; // Vektor, der alle Knoten enthaelt Node** node_map; // Pseudo-vektor, mit dem gearbeitet wird, // so dass real_node_map [i] == node_map [i+1] // d.h. Indizes von node_map laufen von 1 bis n int* id_map; // assoziatives array fuer ID's : // node_map [ id_map [id] ] enthaelt // Element mit ID [id] /****************** interne Operationen ********************** * * kleine Hilfsoperationen, die aus Effizienzgruenden inline * deklariert werden * *************************************************************/ // Vertauscht Knoten der Indizies i und j incl. Anpassung der id_map inline void ExchangeNodes (int i, int j); // Initiiert Knoten mit Index i inc. Eintrag in die id_map inline void InitNode (int i, ITEM_T item, KEY_T key, int id); // Liefert die Indizes der Kinder inline int LeftChildIndex (int index); inline int RightChildIndex (int index); // Liefert Index des Kindes mit dem kleinstem Schluessel // falls aufgrund eines hohen Index' keine Kinder im Heap // sein koennen, wird [index] zurueckgegeben inline int SmallestChildIndex (int index); // Index des Mutterknotens, liefert 0 falls // [index] bereits Wurzel inline int MotherIndex (int index); // Neutral, falls [id] gueltige ID eines im Heap // enthaltenen Elementes ist. // wirft ansonsten InvalidIdException inline void CheckId (int id); }; // RangeCheckers for Binomi Heap template <typename KEY_T> class BinomiHeap_Checking { public: // Diese Kasse implementiert das Rangechecking fur den BinomiHeap. static inline void CheckFull (int heap_cur_size, int heap_max_size); static inline void CheckEmpty (int heap_cur_size); static inline void CheckDecrease (KEY_T old_key, KEY_T new_key); static inline void CheckIDRange (int id, int heap_max_size); static inline void CheckDuplicateID (int id_val); static inline void CheckId (int id_val); }; template <typename KEY_T> class BinomiHeap_NoChecking { public: // Diese Klasse ist neutral, alle Methodenaufrufe werdem vom Compiler wegoptimiert. static inline void CheckFull (int heap_cur_size, int heap_max_size) {}; static inline void CheckEmpty (int heap_cur_size) {}; static inline void CheckDecrease (KEY_T old_key, KEY_T new_key) {}; static inline void CheckIDRange (int id, int heap_max_size) {}; static inline void CheckDuplicateID (int id_val) {}; static inline void CheckId (int id_val) {}; }; // Implementationsschablone einbinden #define BIN_HEAP_HH__ #include "template/BinomiHeap.tcc" #undef BIN_HEAP_HH__ #endif BIN_HEAP_HH �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Attribute.hh��������������������������������������������������������������0000644�0000764�0000764�00000003741�10311256605�016354� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/Attribute.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* Short Description: * A attribute / property implementation. */ #ifndef UTILITY__ATTRIBUTE_HH__ #define UTILITY__ATTRIBUTE_HH__ #include <sigc++/signal.h> namespace Utility { // the public base of all attributes just holding the value and // a Get() method template <class T> class PublicAttribute { public: const T& Get () const { return value; }; protected: T value; }; // the real Attribute with control about signalling ... template <class T, bool do_signal = true> class Attribute : public PublicAttribute<T> { public: const T& Set (const T& n_value) { this->value = n_value; }; }; template <class T> class Attribute <T, true> : public PublicAttribute<T> { public: sigc::signal <void, const T&> changed; const T& Set (const T& n_value) { this->value = n_value; changed.emit (this->value); }; }; } // end namespace Utility #endif // UTILITY__ATTRIBUTE_HH__ �������������������������������exact-image-0.9.1/utility/Empty.hh������������������������������������������������������������������0000644�0000764�0000764�00000002356�10311256605�015510� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/Empty.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* Short Description: * An empty class sometimes handy. */ #ifndef UTILITY__EMPTY_HH__ #define UTILITY__EMPTY_HH__ namespace Utility { class Empty {}; } // end namespace Utility #endif // UTILITY__EMPTY_HH__ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Threads.hh����������������������������������������������������������������0000644�0000764�0000764�00000016530�11253424775�016016� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/Threads.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2009 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* * A Pthread wrapper based on a former implementation from the sigc++ * package by Karl Nelson. * */ #ifndef UTILITY__THREAD_HH__ #define UTILITY__THREAD_HH__ // ?? ... #define THREAD_API #include <pthread.h> namespace Utility { namespace Threads { struct CondAttr { pthread_condattr_t* impl; }; struct MutexAttr { pthread_mutexattr_t* impl; }; struct ThreadAttr { pthread_attr_t* impl; }; typedef pthread_mutex_t MutexImpl; typedef pthread_cond_t CondImpl; typedef pthread_key_t KeyImpl; typedef pthread_t ThreadImpl; // Mutual Exclusion class Mutex { typedef MutexImpl Impl; public: static THREAD_API MutexAttr Default; operator Impl* () { return (Impl*)(&mutex); } Mutex (const MutexAttr attr = Default) { pthread_mutex_init (&mutex, attr.impl); }; Mutex (int type) { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, type); pthread_mutex_init (&mutex, &attr); pthread_mutexattr_destroy(&attr); // TODO: required to hold during mutex lifetime? }; // (needs work) ~Mutex() { Destroy (); }; int Lock () { return pthread_mutex_lock (&mutex); }; int TryLock() { return pthread_mutex_trylock (&mutex); }; int Unlock() { return pthread_mutex_unlock (&mutex); }; private: Impl mutex; int Destroy() { return pthread_mutex_destroy (&mutex); }; }; // A lazy way to unlock at end of scope class MLock { public: MLock (Mutex& mutex) : mutex(mutex) { mutex.Lock(); }; ~MLock () { mutex.Unlock(); }; private: Mutex& mutex; }; // Condition Variable class Condition { private: typedef CondImpl Impl; public: static THREAD_API CondAttr Default; operator Impl* () { return (Impl*)(&cond); }; Condition (const CondAttr &attr = Default) { pthread_cond_init (&cond, attr.impl); }; ~Condition () { Destroy (); }; // restarts exactly one thread hung on condition int Signal () { return pthread_cond_signal (&cond); } // restarts all threads waiting on condition int Broadcast () { return pthread_cond_broadcast (&cond); } // unlocks a mutex while waiting on a condition, then reaquires lock. int Wait (Mutex &m) { return pthread_cond_wait (&cond, m); } // unlocks a mutex while waiting on a condition, then reaquires lock // with a fixed maximum duration. int Wait (Mutex &m, struct timespec* spec) { return pthread_cond_timedwait (&cond, m, spec); } private: Impl cond; int Destroy () { return pthread_cond_destroy (&cond); } }; // Integer Semaphore class Semaphore { public: Semaphore (int i_value = 1) : value (i_value) {} ~Semaphore () {} void Up (); void Down (); private: int value; Condition sig; Mutex access; }; /* This is a very basic thread skeleton. */ class Thread { protected: typedef ThreadImpl Impl; static THREAD_API ThreadAttr Default; public: Thread (const ThreadAttr& i_attr = Default); virtual ~Thread (); /* Create () creates the new thread of execution of the given instance. Internally the thread of execution starts in the private main method. arg is for passing extra data to main, but never pass a local variable or address of local variable. Arg must be available throughout the lifetime of the program. */ int Create (void* arg = 0); /* Detach () put the thread th in the detached state. This guarantees that the memory resources consumed by th will be freed immediately when th terminates. However, this prevents other threads from synchronizing on the termination of this thread using Join (). */ int Detach (); /* Join () suspends the execution of the calling Thread until this thread terminates, either by returning from the main () method or by being Cancel ()ed. */ void* Join (); /* StopInDebugger () will emit a SIGTRAP (or pefroming other actions valid for the given plaform) from the calling thread. */ static void StopInDebugger (); #ifdef __linux__ /* EnableRealtimeScheduling () enables rea-time scheduling for the calling thread. */ static bool EnableRealtimeScheduling (); #endif /* USleep () suspends execution of the calling thread/process for (at least) usec microseconds. The sleep may be lengthened slightly by any system activity or by the time spent processing the call or by the granularity of system timers. If high_precission is set to false (the default) USleep will limit the minimal value where the Operating System will release sleep instead of an busy loop (2ms on Linux) */ static void USleep (int usec, bool high_precission = false); /* NSleep () suspsends execution of the calling thread/process in the same was as USleep - but with nanosecond precission */ static void NSleep (int nsec, bool high_precission = false); /* A thread can relinquish the processor voluntarily without blocking by calling Yield. The thread will then be moved to the end of the queue for its static priority and a new thread/process gets to run. Note: If the current thread is the only thread/process in the highest priority list at that time, this process will continue to run after a call to sched_yield. */ static void Yield (); /* SetPriotry () sets the scheduling priority of the thread. Priority is a value in the range -20 to 20. The default priority is 0; lower priorities cause more favorable scheduling. */ static bool SetPriority (int priority); /* Priority obtains the current priority of the calling thread. */ static int Priority (); operator Impl* () { return &thread; } protected: // the real code for the thread virtual void* main (void* arg) = 0; // trampolines void* call_main_ (void* arg); static void* call_main_static_ (void* arg); Impl thread; void* arg_; ThreadAttr attr; }; } /* namespace Threads */ } /* namespace Utility */ #endif /* __UTILITY_THREAD_HH__ */ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/File.hh�������������������������������������������������������������������0000644�0000764�0000764�00000005417�10311256605�015272� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/File.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* Short Description: * A simple POSIX file abstraction. */ #ifndef UTILITY__FILE_HH__ #define UTILITY__FILE_HH__ #include <sys/stat.h> #include <string> namespace Utility { class FileType { private: int type; public: FileType (int i_type = 0) {type = i_type;} const FileType& operator= (int n_type) {type = n_type; return *this;} bool IsUnknown () const {return (type & S_IFMT) == 0;} bool IsFile () const {return S_ISREG(type);} bool IsDirectory () const {return S_ISDIR(type);} bool IsCharDevice () const {return S_ISCHR(type);} bool IsBlockDevice () const {return S_ISBLK(type);} bool IsFIFO () const {return S_ISFIFO(type);} bool IsSymlink () const {return S_ISLNK(type);} bool IsSocket () const {return S_ISSOCK(type);} }; /* this is some wrapping around the (ugly) posix directory stuff not really a perfectly crafted object */ class File { public: File (); File (const std::string& str); ~File (); void SetFile (const std::string& str); const std::string& Dirname (); const std::string& Basename (); std::string BasenameWOExtension (); const std::string& Extension (); const FileType Type (); const std::string Name () const { return filename; } // more to be done on demand private: inline bool updateStat (); void updateDirBaseExt (); void reset (); std::string filename; std::string dirname; // just cached std::string basename; // just cached std::string extension; // just cached struct stat c_stat; bool c_stat_valid; }; std::ostream& operator<< (std::ostream& os, const File& file); } // namespace Utility #endif // UTILITY__FILE_HH__ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Storage.hh����������������������������������������������������������������0000644�0000764�0000764�00000005012�10311256605�016006� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/Storage.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* Short Description: * Object oriented trival "Storage" I/O. */ #ifndef UTILITY__STORAGE_HH__ #define UTILITY__STORAGE_HH__ #include <string> #include <vector> #include <map> #include <iostream> namespace Utility { class BasicStorage { public: virtual ~BasicStorage () {}; virtual std::istream& Read (std::istream& is) = 0; virtual std::ostream& Write (std::ostream& os) = 0; std::string name; }; template <typename T> class Storage : public BasicStorage { public: Storage (const std::string& i_name) { name = i_name; } Storage (const std::string& i_name, const T& i_value) { name = i_name; value = i_value; } virtual std::istream& Read (std::istream& is) { // TODO: error handling is >> value; return is; } virtual std::ostream& Write (std::ostream& os) { os << value; return os; } T Get () { return value; } void Set (const T& v) { value = v; } private: T value; }; // some bool specialisations ... template <> std::istream& Storage<bool>::Read (std::istream& is); class Serializer { public: void Add (BasicStorage* storage); std::istream& Read (std::istream& is, bool verbose = true); private: typedef std::map<std::string, BasicStorage*> container; typedef container::iterator iterator; container content; }; } // namespace Utility #include "template/Storage.tcc" #endif // UTILITY__STORAGE__ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/DirIterator.hh������������������������������������������������������������0000644�0000764�0000764�00000010622�10412544140�016631� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/DirIterator.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* Short Description: * A simple directory iterator. */ #ifndef UTILITY__DIRITERATOR_HH__ #define UTILITY__DIRITERATOR_HH__ #include <dirent.h> // used by directory iterator #include <string> #include <File.hh> namespace Utility { /* Find a unique filename, "fname + i". The first i can be specified. The fname is overwritten - the used index is returned. - A file is unique when there is no file with the tested name -> even if the trailing path is not available */ int FindUniqueName (std::string& fname, const std::string& base, const std::string& ext, int first_tried_index = 0); /* this is some wrapping around the (ugly) posix directory stuff not really an iterator ... */ class DirList { public: class Iterator { public: Iterator (); Iterator (DirList* i_dirlist); Iterator (const Iterator& i_other); ~Iterator (); const FileType Type (); const Iterator& operator++ () { Next (); return *this; } const Iterator operator++ (int) { Iterator it (*this); Next (); return it; } const std::string& operator* () { // maybe Open() was delayed? if (!m_open && !m_end) Open(); return m_entry_name; } const Iterator& operator= (const Iterator& other) { if (m_open) Close (); m_end = other.m_end; m_dirlist = other.m_dirlist; m_entry_name = other.m_entry_name; // no Open() here - delayed until next access return *this; } bool operator== (const Iterator& other) { return (m_dirlist == other.m_dirlist && m_end == other.m_end && m_entry_name == other.m_entry_name); } bool operator!= (const Iterator& other) { return (m_dirlist != other.m_dirlist || m_end != other.m_end || m_entry_name != other.m_entry_name); } friend class Utility::DirList; private: void Open (); void Close (); // must be Opened! void Next () { // avoid recursion ;-) while (true) { m_internal_dir_entry = readdir (m_internal_dir); if (m_internal_dir_entry == 0) { m_entry_name = ""; m_end = true; return; } // skip . and .. - any dir has those and apps normally do not need them // here are some optimizations since Next() is performance critical m_entry_name = m_internal_dir_entry->d_name; // short path if (m_entry_name[0] != '.' || m_entry_name.size() > 2) return; // expensive checks if (!(m_entry_name == "." || m_entry_name == "..")) return; } } // direct state bool m_open; bool m_end; DirList* m_dirlist; std::string m_entry_name; // indirect state of C API DIR* m_internal_dir; dirent* m_internal_dir_entry; // a File object for the case the dirent does not yield a // valid d_type File m_file; }; DirList (const std::string& i_dirmname = "/"); ~DirList (); #ifdef TODO // navigate in the directory tree void Down (); bool Up (const Iterator& it); // navigation alias bool Enter (const Iterator& it) { return Up (it); }; #endif const Iterator Begin (); const Iterator End (); friend class Iterator; protected: std::string m_dirname; }; } // end namespace utility #endif // UTILITY__DIRITERATOR_HH__ ��������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Threads.cc����������������������������������������������������������������0000644�0000764�0000764�00000007521�11253424775�016004� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/src/Threads.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2009 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include <unistd.h> #include <signal.h> #include <sched.h> // Linux/POSIX scheduler / realtime scheduling ... #include <sys/resource.h> // set_priority #include "Threads.hh" #include "Logging.hh" using namespace Utility::Threads; MutexAttr Mutex::Default = {0}; CondAttr Condition::Default = {0}; ThreadAttr Thread::Default = {0}; void Semaphore::Up() { access.Lock(); ++ value; access.Unlock(); sig.Signal(); } void Semaphore::Down() { access.Lock(); while (value < 1) sig.Wait (access); -- value; access.Unlock(); } Thread::Thread (const ThreadAttr &i_attr) : attr(i_attr) { } Thread::~Thread () { } int Thread::Create (void* arg) { arg_ = arg; // copy the arg for the static trampoline Thread *t = this; return pthread_create (&thread, attr.impl, call_main_static_, t); } int Thread::Detach () { return pthread_detach (thread); } void* Thread::Join () { void* thread_return; if (pthread_join (thread, &thread_return) == 0) return thread_return; else return 0; } void Thread::StopInDebugger () { pid_t m_pid = getpid (); kill (m_pid, SIGTRAP); } #ifdef __linux__ bool Thread::EnableRealtimeScheduling () { int t_pri = sched_get_priority_min (SCHED_FIFO); Q_LOG (UtilityLog) << "priority_min: " << t_pri << std::endl; if (t_pri >= 0) { sched_param t_params; t_params.sched_priority = t_pri; int error = sched_setscheduler (0, SCHED_FIFO, &t_params); if (error < 0) { Q_WARN (UtilityLog) << "WARNING POSIX realtime-scheduling " << "not available (not root?)!" << std::endl; } return error >= 0; } Q_WARN (UtilityLog) << "WARNING minimal priority is positive!" << std::endl; return false; } #endif void Thread::USleep (int delay, bool high_precission) { /* From the nanosleep man-page: * * If the process is scheduled under a real-time policy like * SCHED_FIFO or SCHED_RR, then pauses of up to 2 ms will be * performed as busy waits with microsecond precision. */ if (!high_precission || delay > 2000) usleep (delay); else sched_yield (); } void Thread::NSleep (int delay, bool high_precission) { /* From the nanosleep man-page: * * If the process is scheduled under a real-time policy like * SCHED_FIFO or SCHED_RR, then pauses of up to 2 ms will be * performed as busy waits with microsecond precision. */ if (!high_precission || delay > 2000000) usleep (delay); else sched_yield (); } void Thread::Yield () { sched_yield (); } bool Thread::SetPriority (int priority) { return setpriority (PRIO_PROCESS, 0, priority) >= 0; } void* Thread::call_main_ (void* arg) { void* return_; return_ = main (arg); pthread_exit (return_); } void* Thread::call_main_static_ (void* obj) { Thread *thread_ = (Thread*)obj; return thread_->call_main_ (thread_->arg_); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/File.cc�������������������������������������������������������������������0000644�0000764�0000764�00000006653�10311256605�015263� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/src/File.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <iostream> #include "File.hh" Utility::File::File () { c_stat_valid = false; } Utility::File::File (const std::string& str) { filename = str; c_stat_valid = false; } Utility::File::~File () { } void Utility::File::SetFile (const std::string& str) { if (str != filename) { reset(); filename = str; } } const std::string& Utility::File::Dirname () { // this is slightly unoptimal if we really do not have a dirname // but since this is rare we keep this simple if (dirname == "") updateDirBaseExt (); return dirname; } const std::string& Utility::File::Basename () { // we always have a basename - a leading dot forms a hidden Unix file .... if (basename == "") updateDirBaseExt (); return basename; } std::string Utility::File::BasenameWOExtension () { // we always have a basename - a leading dot forms a hidden Unix file .... if (basename == "") updateDirBaseExt (); std::string::size_type idx = extension.size(); if (idx) ++idx; std::string bwoe = basename.substr(0, basename.size() - idx); return bwoe; } const std::string& Utility::File::Extension () { // this is slightly unoptimal if we really do not have an extension // but since this is rare we keep this simple if (extension == "") updateDirBaseExt (); return extension; } const Utility::FileType Utility::File::Type () { updateStat(); return FileType(c_stat.st_mode); } void Utility::File::reset () { basename.clear(); extension.clear(); c_stat_valid = false; } bool Utility::File::updateStat () { if (c_stat_valid) return true; return stat (filename.c_str(), &c_stat) == 0; } void Utility::File::updateDirBaseExt () { // parse the filename extension std::string::size_type idx_ext = filename.rfind ('.'); std::string::size_type idx_base = filename.rfind ('/'); // ignore leading dots - they mark hidden Unix files ... if (idx_ext && idx_ext != std::string::npos) { extension = filename.substr (idx_ext + 1); } else { extension.clear (); } if (idx_base == std::string::npos) { dirname.clear (); basename = filename.substr (0, std::string::npos); } else { dirname = filename.substr (0, idx_base); basename = filename.substr (idx_base + 1, std::string::npos); } } std::ostream& Utility::operator<< (std::ostream& os, const File& file) { os << file.Name (); return os; } �������������������������������������������������������������������������������������exact-image-0.9.1/utility/fdstream.hh���������������������������������������������������������������0000644�0000764�0000764�00000004135�11463572425�016226� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2009 - 2010 René Rebe, ExactCODE GmbH, Germany. * * 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. */ #ifndef UTILITY__FDSTREAM_HH__ #define UTILITY__FDSTREAM_HH__ #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <stdarg.h> #include <iostream> namespace Utility { class fdbuf : public std::streambuf { protected: int fd; /* output */ virtual int_type overflow(int_type c) { if (c != EOF) { char cc = c; if (write(fd, &cc, 1) != 1) return EOF; } else { return EOF; } return c; } virtual std::streamsize xsputn(const char* s, std::streamsize num) { return write(fd, s, num); } /* input */ char buffer[2]; virtual int_type underflow() { if (gptr() < egptr()) return *gptr(); int numPutback = gptr() - eback(); if (numPutback > 1) numPutback = 1; buffer[0] = buffer[1]; int num = read(fd, &buffer[1], 1); if (num <= 0) return EOF; setg(buffer + 1 - numPutback, buffer + 1, buffer + 1 + num); return *gptr(); } public: fdbuf(int fd) : fd(fd) { setg(buffer+1, buffer+1, buffer+1); } ~fdbuf() { close(fd); } }; class fdostream : public std::ostream { public: fdostream(int fd) : std::ostream(&buf), buf(fd) { } protected: fdbuf buf; }; class fdistream : public std::istream { public: fdistream(int fd) : std::istream(&buf), buf(fd) { } protected: fdbuf buf; }; class fdstream : public std::iostream { public: fdstream(int fd) : std::iostream(&buf), buf(fd) { } protected: fdbuf buf; }; } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/tests/��������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664316�015245� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/tests/ThreadedFind.cc�����������������������������������������������������0000644�0000764�0000764�00000002406�10110254037�020051� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #include <vector> #include <iostream> #include <sstream> #include "DirIterator.hh" #include "Threads.hh" Utility::Threads::Mutex big_lock; class Scan : public Utility::Threads::Thread { private: std::string s; public: Scan (const std::string i_s) { // std::cout << "Creating thread for " << i_s << std::endl; s = i_s; Create (0); } protected: void* main (void*) { Utility::DirList dir (s); Utility::DirList::Iterator it, it_end; std::vector<Scan*> threads; it = dir.Begin (); it_end = dir.End (); while (it != it_end) { big_lock.Lock(); std::cout << s + '/' + *it << std::endl; big_lock.Unlock(); if (it.Type().IsDirectory()) { Scan* new_thread = new Scan (s + '/' + *it); threads.push_back(new_thread); } ++ it; } // join all threads ... while (threads.size()>0) { Scan* thread = threads.back(); // std::cout << "Waiting for thread " << thread->s << std::endl; thread->Join(); delete thread; threads.pop_back(); } return 0; } }; int main (int argc, char* argv[]) { std::string start ("/home/rene"); if (argc > 1) start = argv[1]; Scan s (start); s.Join(); //std::cout << "EOP" << std::endl; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/tests/Attribute.cc��������������������������������������������������������0000644�0000764�0000764�00000002647�10071347323�017511� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/tests/Attribute.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include "Attribute.hh" class foo { public: const Utility::Attribute<int>& bar; foo (); private: Utility::Attribute<int> real_bar; }; foo::foo () : bar (real_bar) { } int main () { Utility::Attribute<int, true> a_with_signal; Utility::Attribute<int, false> a_without_signal; int x; x = a_with_signal.Get (); x = a_without_signal.Get (); foo f; f.bar.Get (); return 0; } �����������������������������������������������������������������������������������������exact-image-0.9.1/utility/tests/Makefile������������������������������������������������������������0000644�0000764�0000764�00000002603�10110475122�016660� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� # --- GSMP-COPYRIGHT-NOTE-BEGIN --- # # This copyright note is auto-generated by ./scripts/Create-CopyPatch. # Please add additional copyright information _after_ the line containing # the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by # the ./scripts/Create-CopyPatch script. Do not edit this copyright text! # # GSMP: utility/tests/Makefile # General Sound Manipulation Program is Copyright (C) 2000 - 2004 # Valentin Ziegler and René Rebe # # 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. # # --- GSMP-COPYRIGHT-NOTE-END --- TOPDIR = ../.. NOT_SRCS := include $(TOPDIR)/Rules.pre BUILD_PROGS := Delete Logging Thread Attribute File Find ThreadedFind all: $(BUILD_OBJS) $(BUILD_PROGS) include $(TOPDIR)/Rules INCDIRS := . ../include ../../dam/include INCLUDES := $(SIGC2INCS) \ $(filter-out $(NOT_INCS), \ $(foreach dir, $(INCDIRS), -I$(dir))) LIBS := $(SIGCLIBS) -ldl ../src/libgsmutil.so �����������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/tests/File.cc�������������������������������������������������������������0000644�0000764�0000764�00000002113�10110477114�016405� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #include <iostream> #include "File.hh" using namespace Utility; int main (int argc, char* argv[]) { File f1 ("/usr/include"); if (f1.Dirname() != "/usr") std::cerr << "Error 1" << std::endl; if (f1.Basename() != "include") std::cerr << "Error 2" << std::endl; if (f1.BasenameWOExtension() != "include") std::cerr << "Error 2a" << std::endl; if (f1.Extension() != "") std::cerr << "Error 2" << std::endl; File f2 ("test.mp3"); if (f2.Dirname() != "") std::cerr << "Error 4" << std::endl; if (f2.Basename() != "test.mp3") std::cerr << "Error 5" << std::endl; if (f2.BasenameWOExtension() != "test") std::cerr << "Error 5a" << std::endl; if (f2.Extension() != "mp3") std::cerr << "Error 6" << std::endl; File f3 (".just-hidden"); if (f3.Dirname() != "") std::cerr << "Error 7" << std::endl; if (f3.Basename() != ".just-hidden") std::cerr << "Error 8" << std::endl; if (f3.BasenameWOExtension() != ".just-hidden") std::cerr << "Error 8a" << std::endl; if (f3.Extension() != "") std::cerr << "Error 9" << std::endl; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/tests/pstream.cc����������������������������������������������������������0000644�0000764�0000764�00000000506�10257470734�017222� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #include <iostream> #include "pstream.hh" using namespace Utility; int main () { pistream cat ("cat", (char*[]){"cat", "/proc/cpuinfo", 0} ); std::cout << cat.rdbuf(); pstream sed ("sed", "sed", "s/World/C++/g", NULL); sed << "Hello World!" << std::endl; sed.close_sink(); std::cout << sed.rdbuf(); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/tests/Find.cc�������������������������������������������������������������0000644�0000764�0000764�00000001547�10110542246�016417� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #include <iostream> #include <sstream> #include <deque> #include "DirIterator.hh" // !sorted might be faster but less sorted ... const bool sorted = true; std::deque<std::string> todo_queue; void scan (const std::string s) { Utility::DirList dir (s); Utility::DirList::Iterator it (dir.Begin()); Utility::DirList::Iterator it_end (dir.End ()); while (it != it_end) { std::cout << s + '/' + *it << std::endl; if (it.Type().IsDirectory()) { if (sorted) scan (s + '/' + *it); else todo_queue.push_back (s + '/' + *it); } ++ it; } if (!sorted) while (todo_queue.size() > 0) { std::string ts (todo_queue.front()); todo_queue.pop_front(); scan(ts); } } int main (int argc, char* argv[]) { std::string start ("/home/rene"); if (argc > 1) start = argv[1]; scan (start); } ���������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/tests/Thread.cc�����������������������������������������������������������0000644�0000764�0000764�00000003015�10051761332�016741� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/tests/Thread.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include <iostream> #include "Threads.hh" class TestThread : public Utility::Threads::Thread { public: TestThread () { std::cout << __PRETTY_FUNCTION__ << std::endl; } ~TestThread () { std::cout << __PRETTY_FUNCTION__ << std::endl; } protected: void* main (void* obj) { std::cout << __PRETTY_FUNCTION__ << std::endl; std::cout << "In thread" << std::endl; return 0; } }; int main () { TestThread thread; thread.Create (0); thread.Join (); return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/tests/Delete.cc�����������������������������������������������������������0000644�0000764�0000764�00000002714�10051751062�016740� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/tests/Delete.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include "Delete.hh" #include <iostream> #include <vector> #include <algorithm> using namespace std; class Obj { public: Obj () {cout << "ctor" << endl;} ~Obj () {cout << "dtor" << endl;} }; int main () { vector<Obj*> v; v.push_back (new Obj ()); v.push_back (new Obj ()); vector<Obj*>::iterator begin = v.begin (); vector<Obj*>::iterator end = v.end (); for_each (begin, end, Utility::DelFunctor<Obj*> ()); return 0; } ����������������������������������������������������exact-image-0.9.1/utility/tests/Logging.cc����������������������������������������������������������0000644�0000764�0000764�00000005744�10051751062�017132� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/tests/Logging.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include "Logger.hh" using namespace Utility; using namespace std; class stdoutLogDestinationConfig : public LogDestinationConfig { public: static const bool echo_log_stdout = true; static const bool log_to_file = false; }; class bothLogDestinationsConfig : public LogDestinationConfig { public: static const bool echo_log_stdout = true; }; typedef stdoutLogDestinationConfig SC; typedef bothLogDestinationsConfig BC; typedef LogDestinationConfig LC; ofstream lfile ("test.log"); LogDevice <> logA (lfile); LogDevice <> logB; LogDestination <LogDestinationConfig, LogDeviceConfig> logDst ("test", logB); class ObjWLog { public: ObjWLog () : m_logger (logDst, this) { } ObjectLogger <LogDestinationConfig, LogDeviceConfig, WL_Verbose, ObjWLog> m_logger; }; int main () { logA.SplitLog <LC> () << "This should be file only" << endl; logA.SplitLog <SC> () << "This should be stdout only" << endl; logA.SplitLog <BC> () << "This should be both file and stdout" << endl; logA.SplitLog <BC> () << "There should be no timestamp..." << endl; logA.SplitLog <BC> () << "... here neither" << endl; logB.SplitLog <LC> () << "but here..." << endl; logB.SplitLog <BC> () << "stdout only" << endl; logB.SplitLog <SC> () << "stdout only" << endl; logA.NoLogFile (); logB.SwitchLogFile (lfile); logA.SplitLog <LC> () << "file (not really)" << endl; logA.SplitLog <SC> () << "stdout" << endl; logA.SplitLog <BC> () << "both (means stdout)" << endl; logB.SplitLog <LC> () << "file" << endl; logB.SplitLog <BC> () << "both" << endl; logB.SplitLog <SC> () << "stdout" << endl; logDst.Log () << "logging" << endl; logDst.Warn () << "warning" << endl; Logger <LogDestinationConfig, LogDeviceConfig, WL_Verbose> logger (logDst); Q_LOG(logger) << "logger logging" << endl; Q_WARN(logger) << "logger warning" << endl; ObjWLog ol; Q_LOG(ol.m_logger) << "some logging" << endl; Q_WARN(ol.m_logger) << "some warning" << endl; return 0; }; ����������������������������exact-image-0.9.1/utility/pstream.hh����������������������������������������������������������������0000644�0000764�0000764�00000007311�11215740766�016073� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� #ifndef UTILITY__PSTREAM_HH__ #define UTILITY__PSTREAM_HH__ #include <unistd.h> #include <signal.h> // kill #include <sys/types.h> #include <sys/wait.h> #include <stdarg.h> #include <iostream> namespace Utility { class processbuf : public std::streambuf { protected: int pid; int sink[2]; int source[2]; /* output */ virtual int_type overflow (int_type c) { if (c != EOF) { char cc = c; if (write (sink[1], &cc, 1) != 1) return EOF; } else { close_sink(); return EOF; } return c; } virtual std::streamsize xsputn (const char* s, std::streamsize num) { return write (sink[1], s, num); } /* input */ char buffer [2]; virtual int_type underflow () { if (gptr() < egptr()) return *gptr(); int numPutback = gptr() - eback(); if (numPutback > 1) numPutback = 1; buffer[0] = buffer[1]; int num = read (source[0], &buffer[1], 1); if (num <= 0) return EOF; setg (buffer + 1 - numPutback, buffer + 1, buffer + 1 + num); return *gptr(); } public: processbuf () { setg (buffer+1, buffer+1, buffer+1); } processbuf (const char* file, char* const argv[]) { setg (buffer+1, buffer+1, buffer+1); exec (file, argv); } ~processbuf () { close(source[0]); close(sink[1]); waitpid(pid, NULL, 0); } void exec (const char* file, const char* arg, va_list ap) { const char* args[10]; // convert va_list into static char* array -sigh int i = 0; args[i++] = arg; for (; i < ((int) sizeof(args))-1; ++i) { const char* s = va_arg(ap, const char*); if (s != NULL) { // std::cout << "Got: " << s << std::endl; args[i] = s; } else break; } args[i] = NULL; exec (file, (char* const*)args); } void exec (const char* file, char* const argv[]) { pipe (sink); pipe (source); if ((pid = fork()) == 0) { dup2(sink[0],0); close(sink[0]); close(sink[1]); dup2(source[1],1); close(source[0]); close(source[1]); execvp(file, argv); perror(file); _exit(1); } close(source[1]); close(sink[0]); } void close_sink () { close(sink[1]); } void terminate (int signal) { close(source[0]); close(sink[1]); kill(pid, signal); } }; class postream : public std::ostream { public: postream (const char* file, char* const argv[]) : std::ostream(&buf), buf(file, argv){ } postream (const char* file, const char* args, ...) : std::ostream(&buf) { va_list ap, aq; va_start (ap, args); va_copy (aq, ap); buf.exec (file, args, ap); va_end (aq); va_end (ap); } void terminate (int signal=SIGTERM) { buf.terminate (signal); } protected: processbuf buf; }; class pistream : public std::istream { public: pistream (const char* file, char* const argv[]) : std::istream(&buf), buf(file, argv) { } pistream (const char* file, const char* args, ...) : std::istream(&buf) { va_list ap, aq; va_start (ap, args); va_copy (aq, ap); buf.exec (file, args, ap); va_end (aq); va_end (ap); } pistream (...) : std::istream(&buf) { // buf(", ""); } void terminate (int signal=SIGTERM) { buf.terminate (signal); } protected: processbuf buf; }; class pstream : public std::iostream { public: pstream (const char* file, char* const argv[]) : std::iostream(&buf), buf(file, argv) { } pstream (const char* file, const char* args, ...) : std::iostream(&buf) { va_list ap, aq; va_start (ap, args); va_copy (aq, ap); buf.exec (file, args, ap); va_end (aq); va_end (ap); } void close_sink () { buf.close_sink (); } void terminate (int signal=SIGTERM) { buf.terminate (signal); } protected: processbuf buf; }; } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Encodings.hh��������������������������������������������������������������0000644�0000764�0000764�00000021713�12320527002�016313� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * General purpose encoding and decoding. * Copyright (C) 2007 - 2014 Rene Rebe, ExactCODE GmbH * Copyright (c) 2008 Valentin Ziegle, ExactCODE GmbH * Copyright (C) 2007 Susanne Klaus, 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. */ #ifndef ENCODINGS_HH #define ENCODINGS_HH #include <inttypes.h> #include <vector> #include <iostream> /* All encoding functions have signature void Encode... (std::ostream& stream, const T& data, size_t length ....) Type T has to implement const CH& operator[] (int) const where CH can be casted into uint8_t. Most likely T will be one out of uint8_t*, std::vector<uint8_t>, std::string. */ template <typename T> void EncodeHex(std::ostream& stream, const T& data, size_t length) { const int limit=40; static const char nibble[] = "0123456789abcdef"; for (size_t i = 0; i < length; ++i) { if (i % limit == 0 && i != 0) stream.put('\n'); uint8_t byte=data[i]; stream.put(nibble[byte >> 4]); stream.put(nibble[byte & 0x0f]); } } template <typename T> void EncodeASCII85(std::ostream& stream, const T& data, size_t length) { const int limit=80; int bytes=0; if (length>0) { length--; // decrementing length allows comparisons below without // performing additional arithmetics uint32_t quad=0; int count=3; for (size_t i=0; i<=length; i++) { quad <<= 8; quad |= (uint8_t) data[i]; if (i==length || count==0) { if (i==length) // pad with zeroes if necessary for (int n=count; n>0; --n) quad <<= 8; if (!(count || quad)) { stream.put('z'); if(++bytes==limit) {stream.put('\n'); bytes=0;} } else { char seq[5]; int n; for (n=4; n>=0; n--) { uint32_t rem=quad % 85; quad /= 85; seq[n]='!'+rem; } for (n=0; n<5-count; n++) { stream.put(seq[n]); if(++bytes==limit) {stream.put('\n'); bytes=0;} } } quad=0; count=4; } count--; } } if (bytes>=limit-1) stream.put('\n'); stream << "~>"; } template <typename T> void EncodeBase64(std::ostream& stream, const T& data, size_t length) { const int limit = 57; static const char base64lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; for (size_t i = 0; i < length; i += 3) { if (i % limit == 0 && i != 0) stream.put('\n'); int pad = 0; uint32_t v = (uint32_t)data[i + 0] << 16; if (i + 1 < length) { v |= (uint32_t)data[i + 1] << 8; if (i + 2 < length) v |= (uint32_t)data[i + 2] << 0; else pad = 1; } else pad = 2; stream.put(base64lookup[v >> 18 & 63]); stream.put(base64lookup[v >> 12 & 63]); stream.put(pad > 1 ? '=' : base64lookup[(v >> 6 & 63)]); stream.put(pad > 0 ? '=' : base64lookup[(v >> 0 & 63)]); } } template <typename T> void DecodeBase64(std::ostream& stream, const T& data, size_t length) { static const char base64lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; for (size_t i = 0; i < length; ) { uint32_t v = 0; int skip = 0; for (int j = 4; i < length && j > 0;) { char c = data[i++]; // this is a bit sloppy and also skips for '=' in the middle of the // stream, but those are not well formed anyway if (c == '=') { ++skip; ++j; continue; } // valid base64 content? (skip \n\r et al.) unsigned int k; for (k = 0; k < sizeof(base64lookup) - 1; ++k) if (c == base64lookup[k]) break; if (k != sizeof(base64lookup) - 1) { --j; //std::cerr << j << ": c: " << c << " to " << k << " for " << std::endl; v |= k << (6 * j); } } stream.put((char)((v >> 16) & 0xFF)); if (skip < 2) stream.put((char)((v >> 8) & 0xFF)); if (skip < 1) stream.put((char)((v >> 0) & 0xFF)); } } #ifdef WITHZLIB #include <zlib.h> // TODO: make template, likewise // windowBits should be in the rage [8,15] // negative values indicate no header and CRC template <typename T> bool DecodeZlib(std::ostream& stream, const T& data, size_t length, const int windowBits = 15) { static const unsigned CHUNK = 16 * 1024; static bool trace = false; z_stream z; char out[CHUNK]; /* allocate deflate state */ z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; int ret = inflateInit2(&z, windowBits); if (ret != Z_OK) return false; z.next_in = (Bytef*)&data[0]; z.avail_in = length; // decompress until end of file or input data while (z.avail_in && ret != Z_STREAM_END) { if (trace) std::cerr << " @ " << z.next_in - (Bytef*)&data[0] << " avail in: " << z.avail_in << std::endl; /* run inflate() on input until output buffer is full, finish decompression if all of source has been read in */ z.next_out = (Bytef*)out; z.avail_out = CHUNK; ret = inflate(&z, Z_SYNC_FLUSH); if (trace) std::cerr << " ret: " << ret << ", avail_out: " << z.avail_out << ", next_in: " << (void*)z.next_in << ", next_out: " << (void*)z.next_out << std::endl; unsigned have = CHUNK - z.avail_out; stream.write(out, have); if (!stream) { (void)inflateEnd(&z); return false; } if (ret != Z_OK && ret != Z_STREAM_END) { (void)inflateEnd(&z); return false; } } // clean up and return (void)inflateEnd(&z); return true; } inline bool EncodeZlib (std::ostream& stream, const char* data, size_t length, int level = 9) { static const unsigned CHUNK = 16 * 1024; static const bool trace = false; z_stream z; char out[CHUNK]; /* allocate deflate state */ z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; int ret = deflateInit(&z, level); if (ret != Z_OK) return false; /* compress until end of file */ z.next_in = (Bytef*)&data[0]; z.avail_in = length; int flush = Z_NO_FLUSH; do { if (z.avail_in == 0) flush = Z_FINISH; z.next_out = (Bytef*)out; z.avail_out = CHUNK; deflate(&z, flush); const unsigned have = CHUNK - z.avail_out; if (trace) std::cerr << " ret: " << ret << ", have: " << have << ", avail_in: " << z.avail_in << ", avail_out: " << z.avail_out << ", next_in: " << (void*)z.next_in << ", next_out: " << (void*)z.next_out << std::endl; if (have) stream.write(out, have); // if there is space in the output buffer start to flush if (z.avail_out) flush = Z_FINISH; if (!stream) { (void)deflateEnd(&z); return false; } } while (z.avail_out < CHUNK); // clean up and return (void)deflateEnd(&z); return true; } #endif /* Some miscellaneous de- and encoders */ // TODO: make more generic inline void EncodeUtf8 (std::ostream& stream, uint32_t glyph_code) { // utf8 encoding char utf8[5]; if (glyph_code <= 0x7f) { utf8[0] = glyph_code; utf8[1] = 0; } else if (glyph_code <= 0x7FF) { utf8[0] = 0xC0 | (glyph_code >> 6); utf8[1] = 0x80 | ((glyph_code >> 0) & 0x3F); utf8[2] = 0; } else if (glyph_code <= 0xFFFF) { utf8[0] = 0xE0 | (glyph_code >> 12); utf8[1] = 0x80 | ((glyph_code >> 6) & 0x3F); utf8[2] = 0x80 | ((glyph_code >> 0) & 0x3F); utf8[3] = 0; } else if (glyph_code <= 0x10FFFF) { utf8[0] = 0xF0 | (glyph_code >> 18); utf8[1] = 0x80 | ((glyph_code >> 12) & 0x3F); utf8[2] = 0x80 | ((glyph_code >> 6) & 0x3F); utf8[3] = 0x80 | ((glyph_code >> 0) & 0x3F); utf8[4] = 0; } else { std::cerr << "invalid glyph_code: " << glyph_code << std::endl; } stream << utf8; } inline std::vector<uint32_t> DecodeUtf8(const char* data, size_t length) { std::vector<uint32_t> store; for (unsigned int i = 0; i < length;) { uint32_t g = data[i]; { if (g & (1<<7)) // utf-8 multi-byte-sequence? { // determine byte count int n; // we could pre-shift one bit, or switch on the bits for (n = 0; g & (1<<7); ++n) g <<= 1; if (n < 2 || n > 4) { std::cerr << "invalid utf-8 count: " << n << std::endl; } // first is variable g = ((data[i++]) & (0xff >> n)); for (--n; n > 0; --n) { // check the 10 MSB marks for sanity and security if ((data[i] & 0xC0) != 0x80) { std::cerr << "incorrect utf-8 multi-byte mark" << std::endl; } g = (g << 6) | ((data[i++]) & (0xff >> 2)); } } else i++; store.push_back(g); } } return store; } #endif �����������������������������������������������������exact-image-0.9.1/utility/TypeInformation.cc��������������������������������������������������������0000644�0000764�0000764�00000002622�10311256605�017523� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/src/TypeInformation.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include "TypeInformation.hh" #include <cxxabi.h> using namespace Utility; std::string Utility::FilteredName (const char* tname) { int status; char* ret_c ( abi::__cxa_demangle(tname, 0, 0, &status) ); std::string ret (ret_c); free (ret_c); return ret; } std::string Utility::FilteredName (std::string& tname) { return Utility::FilteredName (tname.c_str ()); } ��������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/ArgumentList.hh�����������������������������������������������������������0000644�0000764�0000764�00000014212�11576420150�017024� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/ArgumentList.hh * * Copyright (C) 2005 - 2011 * Ren\xe9\xa0\x92ebe, ExactCODE GmbH Germany * * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René ’ebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* Short Description: * Object oriented argument list parsing. */ #ifndef UTILITY__ARGUMENTLIST_HH__ #define UTILITY__ARGUMENTLIST_HH__ #include <iostream> #include <map> #include <vector> #include <string> #include <sstream> namespace Utility { class BasicArgument { public: BasicArgument (const std::string& i_sname, const std::string& i_lname, const std::string& i_desc, int i_min_count, int i_max_count, bool i_fragmented, bool i_reset); virtual ~BasicArgument (); void SetReset (bool i_reset) { reset=i_reset; } void SetList (bool i_list) { list=i_list; } virtual bool Probe (); virtual void Start () = 0; virtual bool Read () = 0; virtual bool Read (const std::string& arg) = 0; virtual bool Interrupt (); virtual bool Finalize (); std::string sname; std::string lname; std::string desc; int min_count, max_count; bool no_arg; bool fragmented; // fragment across several arguments bool reset; // reset (clear) for each new argument bool list; // list in the Usage int count, pass_count; protected: virtual bool InterruptImpl () { return true; } }; template <typename T> class Argument : public BasicArgument { public: Argument (const std::string& i_sname, const std::string& i_lname, const std::string& i_desc, int i_min_count = 0, int i_max_count = 0, bool i_fragmented = false, bool i_reset = false) : BasicArgument (i_sname, i_lname, i_desc, i_min_count, i_max_count, i_fragmented, i_reset), callback (0) { // if bool (or other special option) always use exaclty one value if (no_arg) values.push_back (T () ); } Argument (const std::string& i_sname, const std::string& i_lname, const std::string& i_desc, const T& i_value, int i_min_count = 0, int i_max_count = 0, bool i_fragmented = false, bool i_reset = false) : BasicArgument (i_sname, i_lname, i_desc, i_min_count, i_max_count, i_fragmented, i_reset), callback (0) { values.push_back (i_value); // if bool (or other special option) always containing one value if (no_arg) values.push_back (T () ); } void Start () { // reset requested? if (!no_arg && reset) { values.clear (); count = 0; } } bool Read () { std::cerr << "Error: Argument " << lname << " needs an parameter!" << std::endl; return false; } bool Read (const std::string& arg) { if (count >= max_count) { std::cerr << "Error: Too many parameter for argument " << lname << ", only " << max_count << " allowed!" << std::endl; return false; } T value = ReadImpl (arg); // special case if default was supplied -> overwrite the first ... if (count == 0 && values.size () > 0) values[0] = value; else values.push_back (value); ++count; ++pass_count; return true; } T Get (unsigned int i = 0) const { if (values.size () > i) { return values [i]; } else std::cerr << "Error: There is no parameter: " << i << " present for argument " << this->lname << std::endl; return T (); } int Size () const { return values.size(); } int Count () const { return count; } void Bind (bool (*function)(const Argument<T>&)) { callback = function; } const std::vector<T>& Values () const { return values; } private: T ReadImpl (const std::string& arg) { std::stringstream stream (arg); // TODO: error handling T value; stream >> value; return value; } virtual bool InterruptImpl () { if (callback) return callback(*this); return true; } std::vector<T> values; bool (*callback)(const Argument<T>&); }; // some bool specialisations ... template <> bool Argument<bool>::Read (); template <> bool Argument<bool>::Read (const std::string& arg); template <> std::string Argument<std::string>::ReadImpl (const std::string& arg); class ArgumentList { public: // inresidual mode the last stray parameters are gathered ArgumentList (bool i_residual = false); ~ArgumentList (); // register a to be parsed argument void Add (BasicArgument* arg); // parse options specified bool Read (int argc, char** argv); // return the vector of gathered residuals (if residual parsing enabled) const std::vector<std::string>& Residuals () const; // printout the usual usage list, generated from the registered arguments void Usage (std::ostream& os) const; private: typedef std::map<std::string, BasicArgument*> container; typedef container::iterator iterator; typedef container::const_iterator const_iterator; container short_content; container long_content; std::vector<std::string> residuals; bool residual; }; } // namespace Utility #include "template/ArgumentList.tcc" #endif // UTILITY__ARGUMENTLIST_HH__ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/TypeInformation.hh��������������������������������������������������������0000644�0000764�0000764�00000003272�10311256605�017537� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/TypeInformation.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef UTILITY__TYPEINFORMATION_HH__ #define UTILITY__TYPEINFORMATION_HH__ #include <typeinfo> #include <string> namespace Utility { // mangled typename, for typechecking use template <typename T> const char* SysTypeName (); // demangled Typename , for logging purposes template <typename T> std::string FilteredTypeName (); std::string FilteredName (const char* tname); std::string FilteredName (std::string& tname); } // end namespace UTILITY /* include template implementation */ #define UTILITY__TYPEINFORMATION_TMPL__ #include "template/TypeInformation.tcc" #undef UTILITY__TYPEINFORMATION_TMPL__ #endif // UTILITY__TYPEINFORMATION_HH__ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/ForEachIf.hh��������������������������������������������������������������0000644�0000764�0000764�00000003575�10311256605�016204� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/ForEachIf.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef UTILITY__FOREACHIF_HH__ #define UTILITY__FOREACHIF_HH__ namespace Utility { template<typename ITER, typename PRED, typename FUNC> FUNC for_each_if (ITER first, ITER last, PRED p, FUNC f) { for ( ; first != last; ++first ) if ( p ( *first ) ) f (*first); return f; } template<typename ITER, typename FUNC> bool for_each_noerror (ITER first, ITER last, FUNC f) { bool success = true; for ( ; first != last && success; ++first ) success &= f (*first); return success; } template<typename ITER, typename PRED, typename FUNC> bool for_each_if_noerror (ITER first, ITER last, PRED p, FUNC f) { bool success = true; for ( ; first != last && success; ++first ) if ( p ( *first ) ) success &= f (*first); return success; } } // end namespace Utility #endif // UTILITY__FOREACHIF_HH__ �����������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/C.h�����������������������������������������������������������������������0000644�0000764�0000764�00000002104�10731004107�014405� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/C.hh * Copyright (C) 2007 René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* Short Description: * Some useful C support macros. */ #define ARRAY_SIZE(_array) (sizeof(_array) / sizeof((_array)[0])) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/DirIterator.cc������������������������������������������������������������0000644�0000764�0000764�00000007412�10311256605�016626� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/src/DirIterator.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include "DirIterator.hh" #include <sys/types.h> #include <sys/stat.h> #include <iostream> #include <sstream> // for stringstream int Utility::FindUniqueName (std::string& fname, const std::string& base, const std::string& ext, int first_tried_index) { std::stringstream t_fname; int t_index = first_tried_index; bool t_found = false; while (!t_found) { t_fname.str (""); t_fname << base << t_index << ext; std::cout << "testing: (statting): " << t_fname.str () << std::endl; struct stat t_stat; if (stat (t_fname.str().c_str (), &t_stat) < 0) t_found = true; else ++ t_index; } fname = t_fname.str (); return t_index; } // --- Utility::DirList::Iterator::Iterator () { m_open = false; m_end = false; m_dirlist = 0; m_internal_dir_entry = 0; } Utility::DirList::Iterator::Iterator (DirList* i_dirlist) { m_open = false; m_end = false; m_dirlist = i_dirlist; m_entry_name = ""; } Utility::DirList::Iterator::Iterator (const Iterator& i_other) { m_open = false; operator=(i_other); } Utility::DirList::Iterator::~Iterator () { if (m_open) Close (); } const Utility::FileType Utility::DirList::Iterator::Type () { if (!m_open) Open(); FileType type; // use d_type _if_ usable ... if (m_internal_dir_entry && m_internal_dir_entry->d_type) type = DTTOIF(m_internal_dir_entry->d_type); else { m_file.SetFile (m_dirlist->m_dirname + '/' + m_entry_name); type = m_file.Type(); } return type; } void Utility::DirList::Iterator::Open () { if (m_open) { std::cout << " already open" << std::endl; return; } // special case: we have a dirname but are not yet open (e.g. // after a operator= and so want to search to the correct entry std::string t_entry_name = m_entry_name; m_internal_dir = opendir (m_dirlist->m_dirname.c_str () ); if (m_internal_dir == 0) { m_end = true; } else { m_open = true; m_end = false; Next (); // special case (also see above) we want to search an entry if (t_entry_name != "") { while (m_entry_name != t_entry_name && !m_end) Next (); } } } void Utility::DirList::Iterator::Close () { if (!m_open || !m_internal_dir) return; closedir (m_internal_dir); m_open = false; m_internal_dir = 0; } // --- Utility::DirList::DirList (const std::string& i_dirname) { m_dirname = i_dirname; } Utility::DirList::~DirList () { } const Utility::DirList::Iterator Utility::DirList::Begin () { // create a virgin Iterator Iterator it (this); it.Open(); return it; } const Utility::DirList::Iterator Utility::DirList::End () { // create an Iterator with end flag set Iterator it (this); it.m_end = true; it.m_entry_name = ""; return it; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Logging.hh����������������������������������������������������������������0000644�0000764�0000764�00000004016�10311256605�015773� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/Logging.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef UTILITY__LOGGING_HH__ #define UTILITY__LOGGING_HH__ #include "Logger.hh" #include "config/DebugConfig.hh" namespace Utility { extern UtilityLogDevice UtilityLogDev; extern UtilityLogDestination UtilityLogDst; template <typename WL_TRAITS> class UtilityLogger : public Logger <UtilityLogDestinationConfig, UtilityLogDeviceConfig, WL_TRAITS> { public: UtilityLogger () : Logger <UtilityLogDestinationConfig, UtilityLogDeviceConfig, WL_TRAITS> (UtilityLogDst) {} }; template <typename WL_TRAITS, typename OBJ> class UtilityObjectLogger : public ObjectLogger <UtilityLogDestinationConfig, UtilityLogDeviceConfig, WL_TRAITS, OBJ> { public: UtilityObjectLogger (OBJ* object) : ObjectLogger <UtilityLogDestinationConfig, UtilityLogDeviceConfig, WL_TRAITS, OBJ> (UtilityLogDst, object) {} }; extern UtilityLogger <DefaultLogging_Utility> UtilityLog; } // end namespace Utility #endif // UTILITY__LOGGING_HH__ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/config/�������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664322�015345� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/config/DebugConfig.hh�����������������������������������������������������0000644�0000764�0000764�00000003113�10042222325�020014� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/config/DebugConfig.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef UTILITY__DEBUGCONFIG_HH__ #define UTILITY__DEBUGCONFIG_HH__ // Theese are debuging settings for GSMP. namespace Utility { typedef LogDeviceConfig UtilityLogDeviceConfig; typedef LogDestinationConfig UtilityLogDestinationConfig; typedef LogDevice<UtilityLogDeviceConfig> UtilityLogDevice; typedef LogDestination<UtilityLogDestinationConfig, UtilityLogDeviceConfig> UtilityLogDestination; #define UtilityLogContext "Utility" typedef WL_Warn DefaultLogging_Utility; } // end namespace Utility #endif // UTILITY__DEBUGCONFIG_HH__ �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Compiler.hh���������������������������������������������������������������0000644�0000764�0000764�00000002646�10311256605�016166� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/Compiler.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* Short Description: * Some compiler support stuff (e.g. macros) due to the limited * and ongoing changing compilers ... */ #define GCC_VERSION (__GNUC__ * 10000 \ + __GNUC_MINOR__ * 100 \ + __GNUC_PATCHLEVEL__) #define HAVE_GCC_VERSION(MAJOR, MINOR) \ (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR))) ������������������������������������������������������������������������������������������exact-image-0.9.1/utility/ArgumentList.cc�����������������������������������������������������������0000644�0000764�0000764�00000012571�11112032126�017004� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/src/ArgumentList.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René ’ebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include <sstream> #include "ArgumentList.hh" #include "template/ArgumentList.tcc" using namespace Utility; BasicArgument::BasicArgument (const std::string& i_sname, const std::string& i_lname, const std::string& i_desc, int i_min_count, int i_max_count, bool i_fragmented, bool i_reset) : list(true), count (0), pass_count (0) { sname = i_sname; lname = i_lname; desc = i_desc; min_count = i_min_count; max_count = i_max_count; fragmented = i_fragmented; reset = i_reset; // sanity check if (min_count > max_count) max_count = min_count; no_arg = max_count == 0; } BasicArgument::~BasicArgument () { } bool BasicArgument::Probe () { return count < max_count; } bool BasicArgument::Interrupt () { if (!no_arg && pass_count == 0) { std::cerr << "Error: No parameter for argument " << lname << " specified!" << std::endl; return false; } else if (!fragmented && count < min_count) { std::cerr << "Error: No fragmentation for argument " << lname << " allowed!" << std::endl << " At least " << min_count << " parameter required!" << std::endl; pass_count = 0; return false; } pass_count = 0; return InterruptImpl(); } bool BasicArgument::Finalize () { if (count < min_count) { std::cerr << "Error: Too few parameter for argument " << lname << ", at least " << min_count << " required!" << std::endl; return false; } return true; } ArgumentList::ArgumentList (bool i_residual) { residual = i_residual; } ArgumentList::~ArgumentList() { } void ArgumentList::Add (BasicArgument* arg) { short_content [arg->sname] = arg; long_content [arg->lname] = arg; } bool ArgumentList::Read (int argc, char** argv) { char** argv_end = argv + argc; int errors = 0; // skip the program name ... ++argv; BasicArgument* argument = 0; bool residual_gathering = false; // parse all arguments for (; argv != argv_end; ++argv) { std::string arg (*argv); std::string targ = arg; // temp. mangled argument BasicArgument* new_argument = 0; // match options, does it start with a '-' ? if (arg.size () >= 1 && arg[0] == '-') { // long? if (arg.size () >= 2 && arg[0] == '-' && arg[1] == '-') { targ.erase (0, 2); iterator it = long_content.find (targ); if (it != long_content.end () ) { new_argument = it->second; } } else { // match short targ.erase (0, 1); iterator it = short_content.find (targ); if (it != short_content.end () ) new_argument = it->second; } } if (new_argument) { if (argument && !argument->Interrupt () ) ++errors; argument = new_argument; argument->Start (); } // try to parse via the last matched argument // start residual gathering if not parseable else if (argument) { if (residual && !argument->Probe()) { argument = 0; residual_gathering = true; } else { if (!argument->Read (arg) ) ++errors; } } else if (residual) { argument = 0; residual_gathering = true; } // immediately throw into argument if it does not need parameters // (most often bools) if (argument && argument->no_arg) { if (!argument->Read () ) { argument = 0; ++errors; } } // warning if in residual_gathering mode if (residual_gathering) { residuals.push_back (arg); if (argument) std::cerr << "Warning: Residual parameter " << arg << " matches an argument" << std::endl; } else if (!argument) { std::cerr << "Error: Unrecognized argument: " << arg << std::endl; ++errors; } } // interrupt the last parsed argument if (argument && !argument->Interrupt () ) ++errors; // final checks for (iterator it = long_content.begin (); it != long_content.end (); ++it) { if (!it->second->Finalize()) ++errors; } return errors == 0; } const std::vector<std::string>& ArgumentList::Residuals () const { return residuals; } void ArgumentList::Usage (std::ostream& os) const { for (const_iterator it = long_content.begin (); it != long_content.end (); ++it) if (it->second->list) { if (! it->second->sname.empty() ) os << " -" << it->second->sname << ", "; else os << " "; os << "--" << it->second->lname << std::endl << "\t\t" << it->second->desc << std::endl; } } ���������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/template/�����������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664323�015714� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/template/SplitStreamBuffer.tcc��������������������������������������������0000644�0000764�0000764�00000002570�10071347615�022003� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/template/SplitStreamBuffer.tcc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef UTILITY__SPLITSTREAMBUFFER_TMPL__ #error "This file is included by .... " #error "Include that file instead." #endif namespace Utility { inline std::streambuf::int_type SplitStreamBuffer::overflow (int_type c) { if (c != EOF) { fw1.put (c); fw2.put (c); } return c; } } // end namespace Utility ����������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/template/Storage.tcc������������������������������������������������������0000644�0000764�0000764�00000003244�10310517300�017767� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/template/Storage.tcc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include "Compiler.hh" #if GCC_VERSION < 30300 || __INCLUDE_LEVEL__ == 1 #ifndef UTILITY__STORAGE_TCC__ #define UTILITY__STORAGE_TCC__ namespace Utility { template <> std::istream& Storage<bool>::Read (std::istream& is) { // TODO: error handling is >> value; if (is.fail () ) { is.clear (); std::string s; is >> s; if (s == "true") value = true; else if (s == "false") value = false; else std::cout << "Error: Unable to read boolean value for key \"" << name << "\"!"; } return is; } } // namespace Utility #endif // UTILITY__STORAGE_TCC__ #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/template/BinomiHeap2.tcc��������������������������������������������������0000644�0000764�0000764�00000016604�10353261515�020477� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/template/BinomiHeap.tcc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef BIN_HEAP_HH__ # error "This file is included by BinomiHeap.hh" # error "manual inclusion is nonsense" #endif // BIN_HEAP_HH__ template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: BinomiHeap () { heap.push_back (0); // insert pseudo element cur_size = 1; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: ~BinomiHeap () { } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> id_t BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: Insert (ITEM_T item, KEY_T key) { // init node data id_t id = node_data.size(); node_data.push_back (Node (item, key, cur_size)); // insert at end of heap unsigned int node_pos = id; if (cur_size > MaxElements()) heap.push_back (node_pos); else heap[cur_size] = node_pos; unsigned int pos = cur_size; cur_size++; DrownElement (pos, key); return id; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> ITEM_T BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: ExtractMin (KEY_T& val) { if (RANGE_CHECKING) if (Empty()) throw HeapEmptyException(); // remember root data Node& t_node = node_data[heap [1]]; ITEM_T r_item = t_node.item; val = t_node.key; // mark root as extracted t_node.map_position = 0; if (CurrentElements() > 1) { // insert last element as new root heap [1] = heap [--cur_size]; Node& new_root = node_data[heap [1]]; new_root.map_position = 1; // bubble element upwards unsigned int pos = 1; KEY_T key = new_root.key; unsigned int spos; while (spos = SmallestChildIndex (pos), node_data[heap [spos]].key < key) { ExchangeNodes (pos, spos); pos = spos; } } else cur_size--; return r_item; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> inline unsigned int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: TotalIDs () { return node_data.size(); } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> inline unsigned int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: CurrentElements () { return cur_size - 1; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> inline unsigned int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: MaxElements () { return heap.size() - 1; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> inline bool BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: Empty () { return CurrentElements() == 0; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> void BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: DecreaseKey (KEY_T new_key, id_t id) { CheckInQ (id); if (RANGE_CHECKING) if (node_data [id].key < new_key) throw InvalidKeyException(); node_data [id].key = new_key; unsigned int pos = (unsigned int) node_data[id].map_position; DrownElement (pos, new_key); } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> KEY_T BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: GetKey (id_t id) { CheckId (id); return node_data[id].key; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> ITEM_T BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: GetItem (id_t id) { CheckId (id); return node_data [id].item; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> inline bool BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: InHeap (id_t id) { CheckId(id); return (node_data[id].map_position > 0); } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> void BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: DrownElement (unsigned int pos, KEY_T key) { // drown element unsigned int mother; while (pos > 1 && (mother = MotherIndex(pos), node_data[heap [mother]].key > key)) { ExchangeNodes (pos, mother); pos = mother; } } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> inline void BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: ExchangeNodes (int i, int j) { unsigned int dummy = heap [i]; heap [i] = heap [j]; heap [j] = dummy; node_data[heap [i]].map_position = i; node_data[heap [j]].map_position = j; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> inline unsigned int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: LeftChildIndex (int index) { // child 1 on position [index * 2] return index << 1; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> inline unsigned int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: RightChildIndex (int index) { // child 2 on position [index * 2] + 1 return (index << 1) + 1; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> inline unsigned int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: SmallestChildIndex (int index) { unsigned int l = LeftChildIndex (index); unsigned int r = RightChildIndex (index); unsigned int elements=CurrentElements(); if (l > elements) return index; // node does not have any children else if (l == elements) return l; // node only features one children else return (node_data[heap [l]].key < node_data[heap [r]].key) ? l : r; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> inline unsigned int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: MotherIndex (int index) { // mother at position [index / 2] return index >> 1; } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> inline void BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: CheckId (id_t id) { if (RANGE_CHECKING) if (id >= TotalIDs()) throw InvalidIdException(); } template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> inline void BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: CheckInQ (id_t id) { if (!InHeap(id)) throw InvalidIdException(); } #ifdef HEAP_TESTING template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> void BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: PrintHeap (unsigned int pos, unsigned int spaces) { for (unsigned int i=0; i<spaces; i++) std::cout << "\t"; Node& node = node_data[heap[pos]]; std::cout << node.item << " : " << node.key << std::endl; unsigned int l = LeftChildIndex (pos); unsigned int r = RightChildIndex (pos); unsigned int elements=CurrentElements(); if (l > elements) ; // node does not have any children else if (l == elements) { // node only features one children PrintHeap (l, spaces+1); } else { PrintHeap (l, spaces+1); PrintHeap (r, spaces+1); } } #endif ����������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/template/BinomiHeap.tcc���������������������������������������������������0000644�0000764�0000764�00000023502�10071347615�020413� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/template/BinomiHeap.tcc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* Gruppe : * * Lars Siggelkow 157 721 * Ronald Kluth 158 561 * Valentin Ziegler 157 500 * */ #ifndef BIN_HEAP_HH__ # error "This file is included by BinomiHeap.hh" # error "manual inclusion is nonsense" #endif BIN_HEAP_HH__ /****************************************************** * * Implementation binaerer Heap mit fester Groesse * nach Definition der Klasse BinomiHeap in BinomiHeap.hh * ******************************************************/ // Constructor. [maximal_size] legt Groesse des Heaps fest template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: BinomiHeap (int maximal_size) { max_size = maximal_size; cur_size = 0; real_node_map = new (Node*) [max_size]; // Knotenvektor alloziieren. node_map = real_node_map - 1; // Pseudo-Vektor initialisieren id_map = new int [max_size]; // Assoziatives array initialisieren for (int i = 0; i < maximal_size; i++) id_map [i] = -1; // -1 bedeutet ID nicht enthalten } // Destructor template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: ~BinomiHeap () { // Speicher freigeben for (int i = 0; i < cur_size; i++) delete real_node_map [i]; delete [] real_node_map; delete [] id_map; } // Element [item] mit Schluessel [key] einfuegen. Zugriffs-ID [id]. // Bei Verwendung von BinomiHeap_Checking: // wirft InvalidIdException, falls id nicht innerhalb [ 0, Size ) // wirft DuplicateIdException, falls id bereits in Verwendung template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> void BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: Insert (ITEM_T item, KEY_T key, int id) { // Heap voll ? RANGE_CHECKING :: CheckFull (cur_size, max_size); cur_size++; // am Ende des Heaps einfuegen int pos = cur_size; InitNode (pos, item, key, id); // Element versickern while (pos > 1 && node_map [MotherIndex (pos)] -> key > key) { ExchangeNodes (pos, MotherIndex (pos)); pos = MotherIndex (pos); } } // Element mit minimalem Key zurueckliefern und aus Heap entfernen. // Bei Verwendung von BinomiHeap_Checking: // wirft HeapEmptyException, falls Heap leer. template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> ITEM_T BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: ExtractMin () { // Heap leer ? RANGE_CHECKING :: CheckEmpty (cur_size); Node* t_node = node_map [1]; ITEM_T r_item = t_node -> item; // letztes Element an Wurzel einfuegen node_map [1] = node_map [cur_size --]; id_map [node_map [1] -> id] = 1; // "Hochblubbern" der neuen Wurzel int pos = 1; KEY_T key = node_map [1] -> key; while (node_map [SmallestChildIndex (pos)] -> key < key) { int s_pos = SmallestChildIndex (pos); ExchangeNodes (pos, s_pos); pos = s_pos; } // Aufraeumen und min. Element zurueckgeben. id_map [t_node -> id] = -1; delete t_node; return r_item; } // liefert (statische) Groesse des Heaps zurueck template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> inline int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: Size () { return max_size; } // liefert momentane Anzahl enthaltener Elemente zurueck template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> inline int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: CurSize () { return cur_size; } // Heap leer ? template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> inline bool BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: Empty () { return cur_size == 0; } // Schluessel des Elementes mit ID [id] erniedrigen // Bei Verwendung von BinomiHeap_Checking: // wirft InvalidKeyException, falls neuer Schluessel groesser als alter template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> void BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: DecreaseKey (KEY_T new_key, int id) { // Sicherstellen, dass Element in Heap CheckId (id); int pos = id_map [id]; // Sicherstellen, dass neuer Key <= alter Key RANGE_CHECKING :: CheckDecrease (node_map [pos] -> key, new_key); node_map [pos] -> key = new_key; // Versickern while (pos > 1 && node_map [MotherIndex (pos)] -> key > new_key) { ExchangeNodes (pos, MotherIndex (pos)); pos = MotherIndex (pos); } } // Aktueller Schluessel des Elementes mit ID [id] // Bei Verwendung von BinomiHeap_Checking: // wirft InvalidIdException template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> KEY_T BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: GetKey (int id) { CheckId (id); return node_map [id_map [id]] -> key; } // Element der ID [id] // Bei Verwendung von BinomiHeap_Checking: // wirft InvalidIdException template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> ITEM_T BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: GetItem (int id) { CheckId (id); return node_map [id_map [id]] -> item; } template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> inline void BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: ExchangeNodes (int i, int j) { // Knoten im Vektor vertauschen Node* dummy = node_map [i]; node_map [i] = node_map [j]; node_map [j] = dummy; // assoziatives Array angleichen id_map [node_map [i] -> id] = i; id_map [node_map [j] -> id] = j; } template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> inline void BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: InitNode (int i, ITEM_T item, KEY_T key, int id) { // Gueltige ID ? RANGE_CHECKING :: CheckIDRange (id, max_size); // ID schon benutzt ? RANGE_CHECKING :: CheckDuplicateID (id_map [id]); // assoziatives Array anpassen id_map [id] = i; // Knoten einfuegen node_map [i] = new Node; node_map [i] -> item = item; node_map [i] -> key = key; node_map [i] -> id = id; } template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> inline int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: LeftChildIndex (int index) { // Kind 1 an Pos [index * 2] return index << 1; } template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> inline int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: RightChildIndex (int index) { // Kind 2 an Pos [(index * 2) + 1] return (index << 1) + 1; } template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> inline int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: SmallestChildIndex (int index) { int l = LeftChildIndex (index); int r = RightChildIndex (index); if (l > cur_size) return index; // Knoten kann keine Kinder haben else if (l == cur_size) return l; // Knoten kann nur ein Kind haben. else return (node_map [l] -> key < node_map [r] -> key) ? l : r; } template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> inline int BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: MotherIndex (int index) { // Mutter an Pos [index / 2] return index >> 1; } // Bei Verwendung von BinomiHeap_NoChecking wird diese Methode vom Compiler // wegoptimiert template <typename ITEM_T, typename KEY_T, typename RANGE_CHECKING> inline void BinomiHeap <ITEM_T, KEY_T, RANGE_CHECKING> :: CheckId (int id) { // Id ausserhalb Intervall [ 0, Size ) ? RANGE_CHECKING :: CheckIDRange (id, max_size); // Kein Element mit dieser Id im Heap ? RANGE_CHECKING :: CheckId (id_map [id]); } // Implemetation des RangeCheckings // Neutral, falls noch Platz im Heap. // wirft sonst HeapFullException. template <typename KEY_T> inline void BinomiHeap_Checking <KEY_T> :: CheckFull (int heap_cur_size, int heap_max_size) { if (heap_cur_size >= heap_max_size) throw HeapFullException (); } // Neutral, falls noch Elemente im Heap. // wirft sonst HeapEmptyException. template <typename KEY_T> inline void BinomiHeap_Checking <KEY_T> :: CheckEmpty (int heap_cur_size) { if (heap_cur_size == 0) throw HeapEmptyException (); } // Sicherstellen, dass neuer Key <= alter Key // wirft sonst InvalidKeyException. template <typename KEY_T> inline void BinomiHeap_Checking <KEY_T> :: CheckDecrease (KEY_T old_key, KEY_T new_key) { if (old_key < new_key) throw InvalidKeyException (); } // Sicherstellen, dass id in gueltigen Grenzen ist. // wirft ansonsten InvalidIdException. template <typename KEY_T> inline void BinomiHeap_Checking <KEY_T> :: CheckIDRange (int id, int heap_max_size) { if (id < 0 || id >= heap_max_size) throw InvalidIdException (); } // Sichherstellen, dass id unbenuzt. // wirft ansonsten DuplicateIdException. template <typename KEY_T> inline void BinomiHeap_Checking <KEY_T> :: CheckDuplicateID (int id_val) { if (id_val != -1) throw DuplicateIdException (); } // Neutral, falls [id] gueltige ID eines im Heap // enthaltenen Elementes ist. // wirft ansonsten InvalidIdException template <typename KEY_T> inline void BinomiHeap_Checking <KEY_T> :: CheckId (int id_val) { if (id_val == -1) throw InvalidIdException (); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/template/Logger.tcc�������������������������������������������������������0000644�0000764�0000764�00000014465�10071347615�017627� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/template/Logger.tcc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ // -*- c++ -*- #ifndef UTILITY__LOGGER_TMPL__ #error "This file is included by Logger.hh" #error "Include that file instead." #endif namespace Utility { inline bool BasicLogDevice::TimeStamp (direction d) { if (last_device != this) { last_device = this; last_direction = d; return true; } if (last_direction != d) { last_direction = d; return true; }; return false; } template <typename LDEVC> LogDevice<LDEVC>::LogDevice (std::ofstream& logfile) { log_file = 0; SwitchLogFile (logfile); }; template <typename LDEVC> LogDevice<LDEVC>::LogDevice () { log_file = 0; NoLogFile (); }; template <typename LDEVC> LogDevice<LDEVC>::~LogDevice () { if (log_file) DeallocateSplitStreams (); }; template <typename LDEVC> void LogDevice<LDEVC>::SwitchLogFile (std::ofstream& logfile) { if (log_file) DeallocateSplitStreams (); log_file = &logfile; AllocateSplitStreams (); if (LDEVC::print_log_prelude) PrintPrelude (); }; template <typename LDEVC> void LogDevice<LDEVC>::NoLogFile () { if (log_file) DeallocateSplitStreams (); log_file = 0; } template <typename LDEVC> BasicLogDevice::direction LogDevice<LDEVC>::DetermineDirection (const bool to_std, const bool to_file) { if (to_std || (!log_file)) { if (to_file && log_file) return both; else // file only or no logging at all return std; } else if (to_file) return file; return std; // no-log-at-all case : return std for savety. } template <typename LDEVC> template <typename LDESC> std::ostream& LogDevice<LDEVC>::SplitLog () { direction d = DetermineDirection (LDESC::echo_log_stdout, LDESC::log_to_file); std::ostream* r_stream = 0; switch (d) { case std: r_stream = &wrap_cout; break; case both: r_stream = split_stream_cout; break; case file: r_stream = log_file; } if (LDEVC::do_timestamping) if (TimeStamp (d)) PrintTimeStamp (r_stream); return *r_stream; } template <typename LDEVC> template <typename LDESC> std::ostream& LogDevice<LDEVC>::SplitWarn () { direction d = DetermineDirection (LDESC::echo_warn_stderr, LDESC::warn_to_file); std::ostream* r_stream = 0; switch (d) { case std: r_stream = &wrap_cerr; break; case both: r_stream = split_stream_cerr; break; case file: r_stream = log_file; } if (LDEVC::do_timestamping) if (TimeStamp (d)) PrintTimeStamp (r_stream); return *r_stream; } template <typename LDESC, typename LDEVC> LogDestination<LDESC, LDEVC>::LogDestination (std::string i_context, LogDevice <LDEVC>& i_device) : device (i_device) { context = i_context; } template <typename LDESC, typename LDEVC> std::ostream& LogDestination<LDESC, LDEVC>::Log () { std::ostream& r_stream = device.LogDevice<>::SplitLog<LDESC> (); if (LDESC::context_in_log) r_stream << context << ": "; return r_stream; } template <typename LDESC, typename LDEVC> std::ostream& LogDestination<LDESC, LDEVC>::Warn () { std::ostream& r_stream = device.LogDevice<>::SplitWarn<LDESC> (); if (LDESC::context_in_warn) r_stream << context << " warning : "; return r_stream; } template <typename LDESC, typename LDEVC, typename WL_TRAITS> Logger<LDESC, LDEVC, WL_TRAITS>::Logger(Destination& i_destination) : destination (i_destination) { } template <typename LDESC, typename LDEVC, typename WL_TRAITS> std::ostream& Logger<LDESC, LDEVC, WL_TRAITS>::Log (const char* pretty_function_name) { std::ostream& r_stream = destination.Log (); if (LDESC::function_names_in_log) r_stream << pretty_function_name << " "; return r_stream; } template <typename LDESC, typename LDEVC, typename WL_TRAITS> std::ostream& Logger<LDESC, LDEVC, WL_TRAITS>::Warn (const char* pretty_function_name) { std::ostream& r_stream = destination.Warn (); if (LDESC::function_names_in_warn) r_stream << pretty_function_name << " : "; return r_stream; } template <typename LDESC, typename LDEVC, typename WL_TRAITS, typename OBJ> ObjectLogger<LDESC, LDEVC, WL_TRAITS, OBJ>::ObjectLogger(Destination& i_destination, OBJ* i_parent) : Logger<LDESC, LDEVC, WL_TRAITS> (i_destination) { parent = i_parent; Q_LOG((*this)) << "new " << FilteredTypeName <OBJ> () << std::endl; } template <typename LDESC, typename LDEVC, typename WL_TRAITS, typename OBJ> ObjectLogger<LDESC, LDEVC, WL_TRAITS, OBJ>::~ObjectLogger() { Q_LOG((*this)) << "deleted" << std::endl; } template <typename LDESC, typename LDEVC, typename WL_TRAITS, typename OBJ> std::ostream& ObjectLogger<LDESC, LDEVC, WL_TRAITS, OBJ>::Log (const char* pretty_function_name) { std::ostream& r_stream = Logger<LDESC, LDEVC, WL_TRAITS>::Log (pretty_function_name); r_stream << parent << " "; return r_stream; } template <typename LDESC, typename LDEVC, typename WL_TRAITS, typename OBJ> std::ostream& ObjectLogger<LDESC, LDEVC, WL_TRAITS, OBJ>::Warn (const char* pretty_function_name) { std::ostream& r_stream = Logger<LDESC, LDEVC, WL_TRAITS>::Warn (pretty_function_name); r_stream << parent << " "; return r_stream; } } // end namespace Utility �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/template/ArgumentList.tcc�������������������������������������������������0000644�0000764�0000764�00000003301�11112032056�020774� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/template/ArgumentList.tcc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René ’Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include "Compiler.hh" #if GCC_VERSION < 30300 || __INCLUDE_LEVEL__ == 1 #ifndef UTILITY__ARGUMENTLIST_TCC__ #define UTILITY__ARGUMENTLIST_TCC__ namespace Utility { template <> bool Argument<bool>::Read () { // the ctor garuantees we have one value! values[0] = true; ++count; return true; } template <> bool Argument<bool>::Read (const std::string& arg) { std::cerr << "Error: No parameter allowed for boolean values!" << std::endl; return false; } template <> std::string Argument<std::string>::ReadImpl (const std::string& arg) { return arg; } } // namespace Utility #endif // UTILITY__ARGUMENTLIST_TCC__ #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/template/TypeInformation.tcc����������������������������������������������0000644�0000764�0000764�00000002702�10071347615�021526� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/template/TypeInformation.tcc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef UTILITY__TYPEINFORMATION_TMPL__ #error "This file is included by TypeInformation.hh." #error "Include that file instead." #endif namespace Utility { template <typename T> const char* SysTypeName () { T* fake = 0; return typeid(fake).name (); } template <typename T> std::string FilteredTypeName () { return FilteredName (SysTypeName <T> ()); } } // end namespace Utility ��������������������������������������������������������������exact-image-0.9.1/utility/BinomiHeap2.hh������������������������������������������������������������0000644�0000764�0000764�00000011167�10353261515�016511� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/include/BinomiHeap.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef BIN_HEAP_HH #define BIN_HEAP_HH #include <vector> /************************************************************ * * Binary heap of variable size * * Template with parameters * * ITEM_T : element type (references recommended) * KEY_T : key type * RANGE_CHECKING : set to true to enable range checking etc. * * KEY_T has to provide following operators: * operator < * operator > * operator = * KEY_T (const KEY_T&) * * For easy element access, an ID handle of id_t will be * returned for each element inserted * ***********************************************************/ // Exceptions (thrown when using range checking) class InvalidIdException {}; // invalid ID handle class HeapEmptyException {}; // ExtractMin called on emtpy heap class InvalidKeyException {}; // DecreaseKey called with new key > old key template <typename ITEM_T, typename KEY_T, bool RANGE_CHECKING> class BinomiHeap { public: typedef unsigned int id_t; BinomiHeap (); ~BinomiHeap (); //******************* Heap operations ************************/ id_t Insert (ITEM_T item, KEY_T key); // Extracts element with minimal key. Corresponding key will be // written to <val>. // may throw HeapEmtpyException if range checking enabled ITEM_T ExtractMin (KEY_T& val); // Decrease key of element with ID <id>. // will throw InvalidKeyException if range checking enabled and // new key > old key. // will throw InvalidIDException if element not in heap anymore void DecreaseKey (KEY_T new_key, id_t id); //********************* Information **************************/ // return number of elements ever inserted. inline unsigned int TotalIDs (); // returns number of elements within the heap. inline unsigned int CurrentElements (); // maximum number of elements that have been in heap // simultaneously. inline unsigned int MaxElements (); // Heap empty ? inline bool Empty (); // current key of element with ID <id> // may throw InvalidKeyException if range checking enabled KEY_T GetKey (id_t id); // returns element with ID <id> // may throw InvalidKeyException if range checking enabled ITEM_T GetItem (id_t id); // tells wether element with ID <id> is still in heap // may throw InvalidKeyException if range checking enabled inline bool InHeap (id_t id); // ************************************************************/ private: class Node { // represents element entry public: ITEM_T item; KEY_T key; unsigned int map_position; // associated with heap positions. equals to 0 // for elements not in heap anymore Node (ITEM_T i_item, KEY_T i_key, unsigned int insert_position) { item = i_item; key = i_key; map_position = insert_position; } }; std::vector <Node> node_data; // contains node data; std::vector <unsigned int> heap; // binomical element ordering unsigned int cur_size; // current heap usage (+1 for pseudo element at position 0) inline void DrownElement (unsigned int pos, KEY_T key); inline void ExchangeNodes (int i, int j); inline unsigned int LeftChildIndex (int index); inline unsigned int RightChildIndex (int index); inline unsigned int SmallestChildIndex (int index); inline unsigned int MotherIndex (int index); inline void CheckId (id_t id); inline void CheckInQ (id_t id); #ifdef HEAP_TESTING public: void PrintHeap (unsigned int pos=1, unsigned int spaces=0); #endif }; // Implementationsschablone einbinden #define BIN_HEAP_HH__ #include "template/BinomiHeap2.tcc" #undef BIN_HEAP_HH__ #endif // BIN_HEAP_HH ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Glob.hh�������������������������������������������������������������������0000644�0000764�0000764�00000001250�11014551722�015264� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� /* Copyright 2005 - 2007 René Rebe - ExactCODE GmbH */ #ifndef UTILITY__GLOB_HH__ #define UTILITY__GLOB_HH__ #include <glob.h> #include <string> namespace Utility { /* very lightweight glob wrapper ... */ class Glob { public: typedef char** iterator; Glob (const std::string& pattern, int flags = 0) { glob (pattern.c_str(), flags, NULL, &g); } ~Glob () { globfree (&g); } iterator begin() { return g.gl_pathv; } iterator end() { return g.gl_pathv + g.gl_pathc; } operator void*() { return g.gl_pathc == 0 ? 0 : this; } bool operator!() const { return g.gl_pathc == 0; } private: glob_t g; }; } #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/utility/Logging.cc����������������������������������������������������������������0000644�0000764�0000764�00000002430�10311256605�015757� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: utility/src/Logging.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include "Logging.hh" Utility::UtilityLogDevice Utility::UtilityLogDev; Utility::UtilityLogDestination Utility::UtilityLogDst (UtilityLogContext, Utility::UtilityLogDev); Utility::UtilityLogger <Utility::DefaultLogging_Utility> Utility::UtilityLog; ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/LICENSE���������������������������������������������������������������������������0000644�0000764�0000764�00000042553�11367575203�013410� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) 19yy <name of author> 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; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon>, 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. �����������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/Makefile��������������������������������������������������������������������������0000644�0000764�0000764�00000004241�11422053457�014025� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include config.make X_OUTARCH := ./objdir X_BUILD_IMPLICIT=0 include utility/Makefile X_BUILD_IMPLICIT=1 # -s silcently corrupts binaries on OS X, sigh -ReneR CFLAGS = -Wall -O2 CXXFLAGS = -Wall -O2 -Wno-sign-compare #CFLAGS = -Wall -O0 -ggdb #CXXFLAGS = -Wall -O0 -ggdb # for config.h CPPFLAGS += -I . # -frename-registers and -funroll-loops brings a lot performance on # my AMD Turion - about 20% time decrease (though it is included in -funroll-loops anyway) !!! # from the linux-kernel build system: cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) ifeq "$(X_ARCH)" "i686" CXXFLAGS += -march=i686 CXXFLAGS += $(call cc-option,-mtune=pentium4,) endif # TODO: improve to match i[3456]86 ifneq "$(X_ARCH)" "i686" CFLAGS += -fPIC CXXFLAGS += -fPIC endif ifeq "$(X_ARCH)" "sparc64" CXXFLAGS += -mcpu=ultrasparc CXXFLAGS += $(call cc-option,-mtune=niagara,) endif CXXFLAGS += -funroll-loops -fomit-frame-pointer CXXFLAGS += $(call cc-option,-funswitch-loops,) CXXFLAGS += $(call cc-option,-fpeel-loops,) CXXFLAGS += $(call cc-option,-ftracer,) CXXFLAGS += $(call cc-option,-funit-at-a-time,) CXXFLAGS += $(call cc-option,-frename-registers,) CXXFLAGS += $(call cc-option,-ftree-vectorize,) #CXXFLAGS += $(call cc-option,-mfpmath=sse,) # we have some unimplemented colorspaces in the Image::iterator :-( CXXFLAGS += $(call cc-option,-Wno-switch -Wno-switch-enum,) ifeq "$(STATIC)" "1" X_EXEFLAGS += -static endif MODULES = lib codecs bardecode frontends ContourMatching include $(addsuffix /Makefile,$(MODULES)) ifeq "$(WITHX11)" "1" ifeq "$(WITHEVAS)" "1" include gfx/Makefile include edisplay/Makefile endif endif ifeq "$(WITHSWIG)" "1" include api/Makefile ifeq "$(WITHLUA)" "1" include api/lua/Makefile endif ifeq "$(WITHPERL)" "1" include api/perl/Makefile endif ifeq "$(WITHPHP)" "1" include api/php/Makefile endif ifeq "$(WITHPYTHON)" "1" include api/python/Makefile endif ifeq "$(WITHRUBY)" "1" #include api/ruby/Makefile endif endif check: $(X_OUTARCH)/econvert/econvert$(X_EXEEXT) $(X_OUTARCH)/edentify/edentify$(X_EXEEXT) $(Q)cd testsuite; ./run ../$(X_OUTARCH)/econvert/econvert$(X_EXEEXT) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/README����������������������������������������������������������������������������0000644�0000764�0000764�00000000234�10301655055�013240� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� This will become a template based image manipulation library with fast, yet space efficient data-layout and algorithms. - Rene Rebe <rene@exactcode.de> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/build/����������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664332�013475� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/build/FreeBSD.make����������������������������������������������������������������0000644�0000764�0000764�00000000122�10515440021�015514� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������X_OBJEXT = .o X_LIBEXT = .a X_DYNEXT = .so X_EXEEXT = X_DYNFLAGS = -shared -fPIC ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/build/Linux.make������������������������������������������������������������������0000644�0000764�0000764�00000000122�10515440021�015401� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������X_OBJEXT = .o X_LIBEXT = .a X_DYNEXT = .so X_EXEEXT = X_DYNFLAGS = -shared -fPIC ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/build/bottom.make�����������������������������������������������������������������0000644�0000764�0000764�00000005420�11422053445�015624� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include build/$(X_SYSTEM).make X_SRCS = $(filter-out $(NOT_SRCS), $(notdir $(wildcard $(X_MODULE)/*.cc $(X_MODULE)/*.c $(X_MODULE)/*.m $(X_MODULE)/*.mm))) $(SRCS) $(X_MODULE)_OBJS := $(addsuffix $(X_OBJEXT),$(addprefix $($(X_MODULE)_OUTPUT)/,$(basename $(X_SRCS)))) $(DEPS) $(X_MODULE)_BINARY := $(addprefix $($(X_MODULE)_OUTPUT)/,$(BINARY))$(BINARY_EXT) X_DEP_FILES := $(addsuffix .d,$(addprefix $($(X_MODULE)_OUTPUT)/,$(basename $(X_SRCS)))) # $(DEPS) # include build/$(X_ARCH).make # include build/$(X_CC).make # dependencies ifneq ($(X_DEP_FILES),) -include $(X_DEP_FILES) endif # rules Q = @ ifneq ($(X_BUILD_IMPLICIT),0) ifneq ($(X_NO_INSTALL),1) all:: $($(X_MODULE)_BINARY) install:: $($(X_MODULE)_BINARY) $(Q)for x in $^; do \ case $$x in \ *$(X_DYNEXT) ) echo INSTALL DYNLIB $$x; mkdir -p $(DESTDIR)$(libdir)/; install $$x $(DESTDIR)$(libdir)/ ;; \ *$(X_LIBEXT) ) ;; \ *$(X_EXEEXT) ) echo INSTALL EXEC $$x; mkdir -p $(DESTDIR)$(bindir)/; install $$x $(DESTDIR)$(bindir)/ ;; \ esac ;\ done endif endif $(X_MODULE): $($(X_MODULE)_BINARY) $($(X_MODULE)_OUTPUT)/%.o: $(X_MODULE)/%.c @echo ' C $@' $(Q)$(COMPILE.c) $($(dir $@)CFLAGS) -MMD -MP -MF '$(patsubst %.o,%.d,$@)' -o '$@' '$<' $($(X_MODULE)_OUTPUT)/%.o: $(X_MODULE)/%.m @echo ' ObjC $@' $(Q)$(COMPILE.c) $($(dir $@)CFLAGS) -MMD -MP -MF '$(patsubst %.o,%.d,$@)' -o '$@' '$<' $($(X_MODULE)_OUTPUT)/%.o: $($(X_MODULE)_OUTPUT)/%.cc @echo ' C++ $@' $(Q)$(COMPILE.cc) $($(dir $@)CXXFLAGS) -MMD -MP -MF '$(patsubst %.o,%.d,$@)' -o '$@' '$<' $($(X_MODULE)_OUTPUT)/%.o: $(X_MODULE)/%.cc @echo ' C++ $@' $(Q)$(COMPILE.cc) $($(dir $@)CXXFLAGS) -MMD -MP -MF '$(patsubst %.o,%.d,$@)' -o '$@' '$<' $($(X_MODULE)_OUTPUT)/%.o: $(X_MODULE)/%.mm @echo ' ObjC++ $@' $(Q)$(COMPILE.cc) $($(dir $@)CXXFLAGS) -MMD -MP -MF '$(patsubst %.o,%.d,$@)' -o '$@' '$<' # only implicit rules if one binary per module ... ifeq ($(words $(BINARY)), 1) $($(X_MODULE)_OUTPUT)/$(BINARY)$(X_LIBEXT): $($(X_MODULE)_OBJS) @echo ' LINK LIB $@' $(Q)$(LD) -r -o '$@' $^ # # no AR anymore due to static initilizers # $(Q)$(AR) r '$@' $^ 2> /dev/null # $(Q)$(RANLIB) '$@' $($(X_MODULE)_OUTPUT)/$(BINARY)$(X_DYNEXT): $($(X_MODULE)_OBJS) @echo ' LINK DYN $@' $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $($(dir $@)CXXFLAGS) $(TARGET_ARCH) $(X_DYNFLAGS) -o '$@' $^ $(LDFLAGS) $($(dir $@)LDFLAGS) $($(X_MODULE)_OUTPUT)/$(BINARY)$(X_EXEEXT): $($(X_MODULE)_OBJS) @echo ' LINK EXEC $@' $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $($(dir $@)CXXFLAGS) $(TARGET_ARCH) $(X_EXEFLAGS) -o '$@' $^ $(LDFLAGS) $($(dir $@)LDFLAGS) endif $($(X_MODULE)_OUTPUT)/%: $($(X_MODULE)_OUTPUT)/%.o $(DEPS) @echo ' LINK EXEC $@' $(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $($(dir $@)CXXFLAGS) $(TARGET_ARCH) $(X_EXEFLAGS) -o '$@' $^ $(LDFLAGS) $($(dir $@)LDFLAGS) ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/build/top.make��������������������������������������������������������������������0000644�0000764�0000764�00000002060�10762350522�015121� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# only invoke uname and compute the output top-level dir once ifndef X_ALREADYLOADED .PHONY: all all:: X_SYSTEM := $(shell uname -s) ifndef X_ARCH X_ARCH := $(shell uname -m) endif #ifndef X_CPUS # X_CPUS := $(shell (ls -d /sys/devices/system/cpu/cpu* 2>/dev/null || grep '^processor[[:blank:]]:' /proc/cpuinfo) | wc -l) # ifeq ($(findstring -j,$(MAKEFLAGS)),) # #MAKEFLAGS += -j $(X_CPUS) # endif #endif X_OUTTOP ?= . ifndef X_OUTARCH X_OUTARCH := $(X_OUTTOP)/$(X_SYSTEM)-$(X_ARCH) endif endif # X_ALREADYLOADED # makefiles and module name we are in X_MAKEFILES := $(filter-out %$.make,$(MAKEFILE_LIST)) X_MODULE := $(patsubst %/,%,$(dir $(word $(words $(X_MAKEFILES)),$(X_MAKEFILES)))) # per module output dir $(X_MODULE)_OUTPUT := $(X_OUTARCH)/$(X_MODULE) # create that module output dir X_IGNORE := $(shell mkdir -p $($(X_MODULE)_OUTPUT)) # initialize SRCS := NOT_SRCS := # the global clean target just once ifndef X_ALREADYLOADED X_ALREADYLOADED = 1 .PHONY: clean clean:: @echo "CLEANING $(X_OUTARCH)" $(Q)rm -rf $(X_OUTARCH) .SUFFIXES: endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/build/help.make�������������������������������������������������������������������0000644�0000764�0000764�00000000245�10311235230�015236� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� .PHONY: printvars printvars: @$(foreach V,$(sort $(.VARIABLES)),$(if $(filter-out environment% default automatic,$(origin $V)),$(warning $V=$($V) ($(value $V))))) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/build/kde.make��������������������������������������������������������������������0000644�0000764�0000764�00000000416�10324501250�015053� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# rules for kde stuff # meta object creation MOCS := $(filter-out $(NOT_MOCS), $(notdir $(wildcard $(X_MODULE)/*.hh))) SRCS := $(SRCS) $(addsuffix .moc.cc, $(basename $(MOCS))) $($(X_MODULE)_OUTPUT)/%.moc.cc: $(X_MODULE)/%.hh @echo ' MOC $@' $(Q)moc $< > $@ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/build/Darwin.make�����������������������������������������������������������������0000644�0000764�0000764�00000000125�10515440021�015531� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������X_OBJEXT = .o X_LIBEXT = .a X_DYNEXT = .dylib X_EXEEXT = X_DYNFLAGS = -shared -fPIC �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/configure�������������������������������������������������������������������������0000755�0000764�0000764�00000006577�12467663163�014325� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env bash . config/functions with_options="x11 freetype evas libjpeg libtiff libpng libungif jasper openexr expat lcms bardecode lua swig perl python php ruby" feature_options="evasgl tga pcx static" TGA=1 # default to yes PCX=1 PACKAGE="exact-image" VERSION_MAJOR=0 VERSION_MINOR=9 VERSION_MICRO=1 init prefix="/usr/local" parse_options $* compile c++ available.c || status_error \ "A C++ compiler is not installed or does not work correctly. A C++ compiler is vital for exact-image - so you need to install it first." compile c++ stl.c template.c template-specialization.c \ partial-template-specialization.c function-template.c \ || status_error \ "At least one of the advanced ANSI C++ tests failed. Since these features are vital for exact-image you need to update to a more recent compiler first." headercheck c++ iostream string iostream sstream fstream || \ status_error "Not all tested STL headers are present - please install them." pkgcheck x11 compile X11 atleast 11.0 pkgcheck libagg pkg-config LIBAGG atleast 2.3 || status_error \ "Anti-Grain Geometry was not found, since it is vital (for vector objects and text) obtained it from: www.antigrain.com" # latest tested, even older ones /might/ work -ReneR if ! pkgcheck freetype2 pkg-config FREETYPE atleast 9.5.0; then cat <<-EOT Freetype2 was not found - font rendering is disabled. Freetype2 can be obtained from: www.freetype.org EOT fi if ! pkgcheck evas pkg-config EVAS atleast 0.9.9; then cat <<-EOT Enlightenment Evas was not found - edisplay is disabled. Evas can be obtained from: www.enlightenment.org EOT fi if headercheck "cc $EVASINCS " "Evas_Engine_GL_X11.h" then EVASGL=1 else EVASGL=0 fi pkgcheck libjpeg header LIBJPEG cc jconfig.h pkgcheck libtiff header LIBTIFF c++ tiffconf.h tiffio.h # tiffio.hxx pkgcheck libpng pkg-config LIBPNG atleast 1.2 pkgcheck libungif header LIBUNGIF c++ gif_lib.h pkgcheck jasper header JASPER c++ jasper/jasper.h if pkgcheck expat header EXPAT c++ expat.h; then # just for the SVG parser var_append EXPATLIBS " " "-lexpat" fi pkgcheck OpenEXR pkg-config OPENEXR atleast 1.2.0 #pkgcheck libopenraw-1.0 pkg-config LIBOPENRAW atleast 0.0.5 pkgcheck lcms pkg-config LCMS atleast 1.10 # this is PROPERITARY SOFTWARE - only use this if you have to ... if pkgcheck bardecode shell BARDECODE \ '[ -e external/bardecode.a -a -e external/barcode.h ] && echo yes'; then var_append BARDECODEINCS " " "-I external" var_append BARDECODELIBS " " "external/bardecode.a" else cat <<-EOT For optional, proprietary barcode recognition, place it in 'external/'. EOT fi # due to swig-1.3.32/Lib/perl5/perlstrings.swg:FromCharPtrAndSize fix -ReneR pkgcheck swig shell SWIG 'swig -version 2>/dev/null | sed -n "s/SWIG Version \(.*\)/\1/p"' atleast 1.3.32 # supported swig target languages so far pkgcheck lua pkg-config LUA atleast 5.1 pkgcheck perl shell PERL 'perl -version 2>/dev/null | sed -n "s/This is perl.*v\([0-9.]*\).*built.*/\1/p"' atleast 5.8.0 && PERLINCS="`perl -MExtUtils::Embed -e ccopts`" pkgcheck php -config PHP atleast 5.2.0 && PHPINCS="`php-config --includes`" pkgcheck python shell PYTHON 'python -V 2>&1 | sed -n "s/Python //p"' atleast 2.5.0 && PYTHONINCS="`python-config --includes`" pkgcheck ruby shell RUBY 'ruby --version 2>/dev/null | sed -n "s/ruby \([^ ]*\) .*/\1/p"' atleast 1.8.5 && RUBYINCS="-I/usr/lib64/ruby/1.8/x86_64-linux" # FIXME save ���������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/������������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664271�013151� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/api.cc������������������������������������������������������������������������0000644�0000764�0000764�00000055600�11215422361�014215� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * The ExactImage stable external API for use with SWIG. * Copyright (C) 2006 - 2009 René Rebe, ExactCODE GmbH * Copyright (C) 2006 - 2008 Archivista 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 <math.h> #include <string> #include <vector> #include <sstream> #include <iostream> #include <sstream> #include <Image.hh> #include <Codecs.hh> #include <rotate.hh> #include <scale.hh> #include <crop.hh> #include <Colorspace.hh> #include <optimize2bw.hh> #include <empty-page.hh> #include <ContourMatching.hh> #include "Tokenizer.hh" // barcode decoding #include "Scanner.hh" #include <vectorial.hh> #include "api.hh" // initializer static Image::iterator background_color; static Image::iterator foreground_color; struct it_color_init { it_color_init (Image::iterator& it, double r, double g, double b, double a) { it.type = Image::RGB8A; it.setRGBA(r, g, b, a); } }; static it_color_init bg_color_init (background_color, 0, 0, 0, 1); static it_color_init fg_color_init (foreground_color, 1, 1, 1, 1); Image* newImage () { return new Image; } Image* newImageWithTypeAndSize (unsigned int samplesPerPixel, unsigned int bitsPerSample, unsigned int width, unsigned int height, int fill) { Image* image = newImage(); image->spp = samplesPerPixel; image->bps = bitsPerSample; image->resize(width, height); // make sure it's clean initially, also because we only allow painting // OVER and thus not allowing to create transparency if (fill == 0) memset(image->getRawData(), 0, image->stride() * image->h); else { double r = 0, g = 0, b = 0, a = 0; background_color.getRGBA(r, g, b, a); Image::iterator it = image->begin(); // optimization: only set FP based values once, copy the rest it.setRGBA(r, g, b, a); for (Image::iterator it_end = image->end(); it != it_end; ++it) it.set(it); } return image; } void deleteImage (Image* image) { delete image; } Image* copyImage (Image* other) { Image* image = new Image; *image = *other; return image; } bool decodeImage (Image* image, const std::string& data) { std::istringstream stream (data); return ImageCodec::Read (&stream, *image); } bool decodeImage (Image* image, char* data, int n) { const std::string str (data, n); return decodeImage (image, str); } bool decodeImageFile (Image* image, const char* filename) { return ImageCodec::Read (filename, *image); } void encodeImage (char **s, int *slen, Image* image, const char* codec, int quality, const char* compression) { std::ostringstream stream (""); // empty string to start with ImageCodec::Write (&stream, *image, codec, "", quality, compression); stream.flush(); char* payload = (char*) malloc (stream.str().size()); memcpy (payload, stream.str().c_str(), stream.str().size()); *s = payload; *slen = stream.str().size(); } const std::string encodeImage (Image* image, const char* codec, int quality, const char* compression) { std::ostringstream stream (""); // empty string to start with ImageCodec::Write (&stream, *image, codec, "", quality, compression); stream.flush(); return stream.str(); } bool encodeImageFile (Image* image, const char* filename, int quality, const char* compression) { return ImageCodec::Write (filename, *image, quality, compression); } // image properties int imageChannels (Image* image) { return image->spp; } int imageChannelDepth (Image* image) { return image->bps; } int imageWidth (Image* image) { return image->w; } int imageHeight (Image* image) { return image->h; } int imageXres (Image* image) { return image->resolutionX(); } int imageYres (Image* image) { return image->resolutionY(); } const char* imageColorspace (Image* image) { return colorspace_name (*image); } void imageSetXres (Image* image, int xres) { image->setResolutionX(xres); } void imageSetYres (Image* image, int yres) { image->setResolutionY(yres); } // image manipulation void get(Image* image, unsigned int x, unsigned int y, double* r, double* g, double* b, double* a) { Image::iterator it = image->begin(); it = it.at(x, y); *it; it.getRGBA(*r, *g, *b, *a); } void set(Image* image, unsigned int x, unsigned int y, double r, double g, double b, double a) { Image::iterator it = image->begin(); it = it.at(x, y); it.setRGBA(r, g, b, a); it.set(it); // TODO: this should not be done so frequently, for every pixel image->setRawData(); } bool imageConvertColorspace (Image* image, const char* target_colorspace, int threshold) { return colorspace_by_name (*image, target_colorspace, threshold); } void imageResize (Image* image, int x, int y) { if (x < 0) x = 0; if (y < 0) y = 0; image->resize (x, y); } void imageRotate (Image* image, double angle) { rotate (*image, angle, background_color); } Image* copyImageCropRotate (Image* image, int x, int y, unsigned int w, unsigned int h, double angle) { return copy_crop_rotate (*image, x, y, w, h, angle, background_color); } void imageFlipX (Image* image) { flipX (*image); } void imageFlipY (Image* image) { flipY (*image); } void imageScale (Image* image, double factor, double yfactor) { scale (*image, factor, yfactor != .0 ? yfactor : factor); } void imageBoxScale (Image* image, double factor, double yfactor) { box_scale (*image, factor, yfactor != .0 ? yfactor : factor); } void imageNearestScale (Image* image, double factor, double yfactor) { nearest_scale (*image, factor, yfactor != .0 ? yfactor : factor); } void imageBilinearScale (Image* image, double factor, double yfactor) { bilinear_scale (*image, factor, yfactor != .0 ? yfactor : factor); } void imageThumbnailScale (Image* image, double factor, double yfactor) { thumbnail_scale (*image, factor, yfactor != .0 ? yfactor : factor); } void imageCrop (Image* image, unsigned int x, unsigned int y, unsigned int w, unsigned int h) { crop (*image, x, y, w, h); } void imageFastAutoCrop (Image* image) { fastAutoCrop (*image); } // color controls void setForegroundColor (double r, double g, double b, double a) { foreground_color.setRGBA(r, g, b, a); } void setBackgroundColor (double r, double g, double b, double a) { background_color.setRGBA(r, g, b, a); } // vector elements class drawStyle { public: drawStyle () : width (1) { } double width; std::vector <double> dash; } style; void setLineWidth (double width) { style.width = width; } void color_to_path (Path& p) { double r = 0, g = 0, b = 0, a = 0; foreground_color.getRGBA (r, g, b, a); p.setFillColor (r, g, b, a); } void imageDrawLine (Image* image, double x, double y, double x2, double y2) { Path path; path.moveTo (x, y); path.addLineTo (x2, y2); path.setLineWidth (style.width); path.setLineDash (0, style.dash); color_to_path(path); path.draw (*image); } void imageDrawRectangle (Image* image, double x, double y, double x2, double y2) { Path path; path.addRect (x, y, x2, y2); path.setLineWidth (style.width); path.setLineDash (0, style.dash); path.setLineJoin (agg::miter_join); color_to_path(path); path.draw (*image); } #if WITHFREETYPE == 1 void imageDrawText (Image* image, double x, double y, char* text, double height, const char* fontfile) { Path path; color_to_path(path); path.moveTo (x, y); path.drawText (*image, text, height, fontfile); } void imageDrawTextOnPath (Image* image, Path* path, char* text, double height, const char* fontfile) { color_to_path(*path); path->drawTextOnPath (*image, text, height, fontfile); } #endif Path* newPath() { return new Path; } void deletePath(Path* path) { delete path; } void pathClear(Path* path) { path->clear(); } void pathMoveTo(Path* path, double x, double y) { path->moveTo(x, y); } void pathLineTo(Path* path, double x, double y) { path->addLineTo(x, y); } void pathCurveTo(Path* path, double x, double y, double x2, double y2) { path->addCurveTo(x, y, x2, y2); } void pathQuadCurveTo(Path* path, double x, double y, double x2, double y2, double x3, double y3) { path->addCurveTo(x, y, x2, y2, x3, y3); } void pathClose(Path* path) { path->close(); } void pathStroke(Path* path, Image* image) { color_to_path(*path); path->setLineWidth (style.width); path->draw(*image, Path::fill_none); } void pathFill(Path* path, Image* image) { color_to_path(*path); path->draw(*image, Path::fill_non_zero); } void imageOptimize2BW (Image* image, int low, int high, int threshold, int radius, double sd, int target_dpi) { optimize2bw (*image, low, high, threshold, 0 /* sloppy thr */, radius, sd); if (target_dpi && image->resolutionX()) { double scale = (double)(target_dpi) / image->resolutionX(); if (scale < 1.0) box_scale (*image, scale, scale); else bilinear_scale (*image, scale, scale); } /* This does not look very dynamic, but it is - the real work is done inside the optimize2bw library - this just yields the final bi-level data */ if (!threshold) threshold = 200; if (image->bps > 1) colorspace_gray8_to_gray1 (*image, threshold); } bool imageIsEmpty (Image* image, double percent, int margin) { return detect_empty_page (*image, percent, margin); } Contours* newContours(Image* image, int low, int high, int threshold, int radius, double standard_deviation) { optimize2bw (*image, low, high, threshold, 0, radius, standard_deviation); if (threshold==0) threshold=200; FGMatrix m(*image, threshold); return new Contours(m); } void deleteContours(Contours* contours) { delete contours; } LogoRepresentation* newRepresentation(Contours* logo_contours, int max_feature_no, int max_avg_tolerance, int reduction_shift, double maximum_angle, double angle_step) { return new LogoRepresentation(logo_contours, max_feature_no, max_avg_tolerance, reduction_shift, maximum_angle, angle_step); } void deleteRepresentation(LogoRepresentation* representation) { delete representation; } double matchingScore(LogoRepresentation* representation, Contours* image_contours) { return representation->Score(image_contours); } // theese are valid after call to matchingScore() double logoAngle(LogoRepresentation* representation) { return representation->rot_angle; } int logoTranslationX(LogoRepresentation* representation) { return representation->logo_translation.first; } int logoTranslationY(LogoRepresentation* representation) { return representation->logo_translation.second; } int inverseLogoTranslationX(LogoRepresentation* representation, Image* image) { return representation->CalculateInverseTranslation(image->w/2, image->h/2).first; } int inverseLogoTranslationY(LogoRepresentation* representation, Image* image) { return representation->CalculateInverseTranslation(image->w/2, image->h/2).second; } void drawMatchedContours(LogoRepresentation* representation, Image* image) { int tx=representation->logo_translation.first; int ty=representation->logo_translation.second; double angle=M_PI * representation->rot_angle / 180.0; for (unsigned int i=0; i<representation->mapping.size(); i++) { double trash; Contours::Contour transformed; RotCenterAndReduce(*(representation->mapping[i].first), transformed, angle, 0, 0, trash, trash); DrawTContour(*image, transformed, tx, ty, 0,0,255); DrawContour(*image, *(representation->mapping[i].second), 0,255,0); } } void imageNormalize (Image* image) { normalize (*image); } void imageInvert (Image* image) { invert (*image); } void imageBrightnessContrastGamma (Image* image, double brightness, double contrast, double gamma) { brightness_contrast_gamma (*image, brightness, contrast, gamma); } void imageHueSaturationLightness (Image* image, double hue, double saturation, double lightness) { hue_saturation_lightness (*image, hue, saturation, lightness); } // barcode recognition #if WITHBARDECODE == 1 // barcode library extern "C" { // missing in the library header ... #include "barcode.h" typedef struct tagBITMAP { int bmType; int bmWidth; int bmHeight; int bmWidthBytes; unsigned char bmPlanes; unsigned char bmBitsPixel; void* bmBits; } BITMAP; // missing in the library header ... int STReadBarCodeFromBitmap (void *hBarcode, BITMAP *pBitmap, float resolution, char ***bc, char ***bc_type, short photometric); } char** imageDecodeBarcodesExt (Image* im, const char* c, unsigned int min_length, unsigned int max_length, int multiple, int dirs) { std::string codes = c; std::transform (codes.begin(), codes.end(), codes.begin(), tolower); std::vector<std::string> ret; { const bool debug = false; uint16_t i; // a copy we can mangle Image* image = new Image; *image = *im; // deep copy int xres = 300; if (image->resolutionX() != 0) xres = image->resolutionX(); // the barcode library does not support such a high bit-depth if (image->bps == 16) colorspace_16_to_8 (*image); // the library interface only handles one channel data if (image->spp == 3) // color crashes the library more often than not colorspace_rgb8_to_gray8 (*image); // the library does not appear to like 2bps ? if (image->bps == 2) colorspace_grayX_to_gray8 (*image); // now we have a 1, 4 or 8 bits per pixel GRAY image //ImageCodec::Write ("dump.tif", *image, 90, ""); // The bardecode library is documented to require a 4 byte row // allignment. To conform this a custom allocated bitmap would // be required which would either require a complete Image class // rewrite or a extremely costly allocation and copy at this // location. Depending on the moon this is required or not. uint8_t* malloced_data = image->getRawData(); { // required alignments const int base_align = 4; const int stride_align = 4; int stride = image->stride (); int new_stride = (stride + stride_align - 1) / stride_align * stride_align; // realloc the data to the maximal working set of memory we // might have to work with in the worst-case image->setRawDataWithoutDelete ((uint8_t*) realloc (image->getRawData(), new_stride * image->h + base_align)); malloced_data = image->getRawData(); uint8_t* new_data = (uint8_t*) (((long)image->getRawData() + base_align - 1) & ~(base_align-1)); if (debug) { std::cerr << " stride: " << stride << " aligned: " << new_stride << std::endl; std::cerr << " @: " << (void*) image->getRawData() << " aligned: " << (void*) new_data << std::endl; } if (stride != new_stride || image->getRawData() != new_data) { if (debug) std::cerr << " moving data ..." << std::endl; for (int y = image->h-1; y >= 0; --y) { memmove (new_data + y*new_stride, image->getRawData() + y*stride, stride); memset (new_data + y*new_stride + stride, 0xff, new_stride-stride); } // store new stride == width (@ 8bit gray) image->w = new_stride * 8 / image->bps; image->setRawDataWithoutDelete (new_data); } } // call into the barcode library void* hBarcode = STCreateBarCodeSession (); i = 0; STSetParameter (hBarcode, ST_READ_CODE39, &i); STSetParameter (hBarcode, ST_READ_CODE128, &i); STSetParameter (hBarcode, ST_READ_CODE25, &i); STSetParameter (hBarcode, ST_READ_EAN13, &i); STSetParameter (hBarcode, ST_READ_EAN8, &i); STSetParameter (hBarcode, ST_READ_UPCA, &i); STSetParameter (hBarcode, ST_READ_UPCE, &i); // parse the code list std::string c (codes); std::string::size_type it = 0; std::string::size_type it2; i = 1; do { it2 = c.find ('|', it); std::string code; if (it2 !=std::string::npos) { code = c.substr (it, it2-it); it = it2 + 1; } else code = c.substr (it); if (!code.empty()) { if (code == "code39") STSetParameter(hBarcode, ST_READ_CODE39, &i); else if (code == "code128") STSetParameter(hBarcode, ST_READ_CODE128, &i); else if (code == "code25") STSetParameter(hBarcode, ST_READ_CODE25, &i); else if (code == "ean13") STSetParameter(hBarcode, ST_READ_EAN13, &i); else if (code == "ean8") STSetParameter(hBarcode, ST_READ_EAN8, &i); else if (code == "upca") STSetParameter(hBarcode, ST_READ_UPCA, &i); else if (code == "upce") STSetParameter(hBarcode, ST_READ_UPCE, &i); else if (code == "any") { STSetParameter (hBarcode, ST_READ_CODE39, &i); STSetParameter (hBarcode, ST_READ_CODE128, &i); STSetParameter (hBarcode, ST_READ_CODE25, &i); STSetParameter (hBarcode, ST_READ_EAN13, &i); STSetParameter (hBarcode, ST_READ_EAN8, &i); STSetParameter (hBarcode, ST_READ_UPCA, &i); STSetParameter (hBarcode, ST_READ_UPCE, &i); } else std::cerr << "Unrecognized barcode type: " << code << std::endl; } } while (it2 != std::string::npos); // only set if non-zero, otherwise CODE39 with chars does // not appear to work quite right if (min_length) { i = min_length; STSetParameter (hBarcode, ST_MIN_LEN, &i); } if (max_length) { i = max_length; STSetParameter (hBarcode, ST_MAX_LEN, &i); } // 90 degree angles differ from public API SPEC and EI built-ins i = (dirs & 1) | (dirs & 2) << 2 | (dirs & 4) | (dirs & 8) >> 2; STSetParameter(hBarcode, ST_ORIENTATION_MASK, &i); if (false) // the library has defaults? { i = 20; STSetParameter(hBarcode, ST_NOISEREDUCTION, &i); i = 1; STSetParameter(hBarcode, ST_DESPECKLE, &i); i = 166; STSetParameter(hBarcode, ST_CONTRAST, &i); } i = multiple; STSetParameter(hBarcode, ST_MULTIPLE_READ, &i); BITMAP bbitmap; bbitmap.bmType = 1; // bitmap type version, fixed v1 bbitmap.bmWidth = image->w; bbitmap.bmHeight = image->h; bbitmap.bmWidthBytes = image->stride(); bbitmap.bmPlanes = 1; // the library is documented to only take 1 bbitmap.bmBitsPixel = image->bps * image->spp; // 1, 4 and 8 appeared to work bbitmap.bmBits = image->getRawData(); // our class' bitmap data if (debug) std::cerr << " @: " << (void*) image->getRawData() << ", w: " << image->w << ", h: " << image->h << ", spp: " << image->spp << ", bps: " << image->bps << ", stride: " << image->stride() << ", res: " << xres << std::endl; char** bar_codes; char** bar_codes_type; // 0 == photometric min is black, but this appears to be inverted? int photometric = 1; int bar_count = STReadBarCodeFromBitmap (hBarcode, &bbitmap, xres, &bar_codes, &bar_codes_type, photometric); for (i = 0; i < bar_count; ++i) { uint32 TopLeftX, TopLeftY, BotRightX, BotRightY ; STGetBarCodePos (hBarcode, i, &TopLeftX, &TopLeftY, &BotRightX, &BotRightY); //printf ("%s[%s]\n", bar_codes[i], bar_codes_type[i]); ret.push_back (bar_codes[i]); ret.push_back (bar_codes_type[i]); } STFreeBarCodeSession (hBarcode); // as this one needs to be free'd image->setRawDataWithoutDelete (malloced_data); delete (image); image = 0; } char** cret = (char**)malloc (sizeof(char*) * (ret.size()+1)); int i = 0; for (std::vector<std::string>::iterator it = ret.begin(); it != ret.end(); ++it) cret[i++] = strdup (it->c_str()); cret[i] = 0; return (char**)cret; } #endif using namespace BarDecode; namespace { struct comp { bool operator() (const scanner_result_t& a, const scanner_result_t& b) const { if (a.type < b.type) return true; else if (a.type > b.type) return false; else return (a.code < b.code); } }; std::string filter_non_printable(const std::string& s) { std::string result; for (size_t i = 0; i < s.size(); ++i) { if ( std::isprint(s[i]) ) result.push_back(s[i]); } return result; } } char** imageDecodeBarcodes (Image* image, const char* codestr, unsigned int min_length, unsigned int max_length, int multiple, unsigned int line_skip, int dirs) { codes_t codes = 0; // parse the code list std::string c (codestr); std::transform (c.begin(), c.end(), c.begin(), tolower); std::string::size_type it = 0; std::string::size_type it2; do { it2 = c.find ('|', it); std::string code; if (it2 !=std::string::npos) { code = c.substr (it, it2-it); it = it2 + 1; } else code = c.substr (it); if (!code.empty()) { if (code == "code39") codes |= code39; else if (code == "code128") codes |= code128 | gs1_128; else if (code == "code25") codes |= code25i; else if (code == "ean13") codes |= ean13; else if (code == "ean8") codes |= ean8; else if (code == "upca") codes |= upca; else if (code == "upce") codes |= upce; else if (code == "any") { codes |= ean|code128|gs1_128|code39|code25i; } else std::cerr << "Unrecognized barcode type: " << code << std::endl; } } while (it2 != std::string::npos); const int threshold = 150; const directions_t directions = (directions_t)dirs; const int concurrent_lines = 4; std::map<scanner_result_t,int,comp> retcodes; if ( directions&(left_right|right_left) ) { BarDecode::BarcodeIterator<> it(image, threshold, codes, directions, concurrent_lines, line_skip); while (! it.end() ) { ++retcodes[*it]; ++it; } } if ( directions&(top_down|down_top) ) { directions_t dir = (directions_t) ((directions&(top_down|down_top))>>1); BarDecode::BarcodeIterator<true> it(image, threshold, codes, dir, concurrent_lines, line_skip); while (! it.end() ) { ++retcodes[*it]; ++it; } } std::vector<std::string> ret; for (std::map<scanner_result_t,int>::const_iterator it = retcodes.begin(); it != retcodes.end(); ++it) { if (it->first.type || it->second > 1) { const std::string cont = filter_non_printable(it->first.code); if (min_length && cont.size() < min_length) continue; if (max_length && cont.size() > max_length) continue; ret.push_back (cont); std::stringstream s; s << it->first.type; ret.push_back (s.str()); } } char** cret = (char**)malloc (sizeof(char*) * (ret.size()+1)); int i = 0; for (std::vector<std::string>::iterator it = ret.begin(); it != ret.end(); ++it) cret[i++] = strdup (it->c_str()); cret[i] = 0; return (char**)cret; } ��������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/perl/�������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664271�014113� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/perl/Makefile�����������������������������������������������������������������0000644�0000764�0000764�00000001461�11117436573�015546� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include build/top.make BINARY = ExactImage BINARY_EXT = $(X_DYNEXT) DEPS = $(lib_BINARY) $(bardecode_BINARY) $(codecs_BINARY) $(api_BINARY) $($(X_MODULE)_OUTPUT)/api-perl-wrap.cc objdir/api/perl/CXXFLAGS := -I api $(PERLINCS) $($(X_MODULE)_OUTPUT)/api-perl-wrap.cc: $(X_MODULE)/../api.hh $(X_MODULE)/../api-swig.hh $(Q)echo " SWIG $(dir $@)" $(Q)swig -perl -c++ -outdir $(dir $@) -o '$@' $(X_MODULE)/../api-swig.hh # we have an own install _X_BUILD_IMPLICIT := $(_X_BUILD_IMPLICIT) X_BUILD_IMPLICIT := 0 include build/bottom.make X_BUILD_IMPLICIT := $(_X_BUILD_IMPLICIT) # install all:: $($(X_MODULE)_BINARY) install:: $($(X_MODULE)_BINARY) $(Q)echo "INSTALL PERL module $^" $(Q)mkdir -p $(DESTDIR)$(libdir)/perl5/site_perl/ $(Q)install $^ $(dir $^)/ExactImage.pm $(DESTDIR)$(libdir)/perl5/site_perl/ ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/lua/��������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664271�013732� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/lua/Makefile������������������������������������������������������������������0000644�0000764�0000764�00000001531�11076324117�015355� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include build/top.make BINARY = ExactImage BINARY_EXT = $(X_DYNEXT) DEPS = $(lib_BINARY) $(bardecode_BINARY) $(codecs_BINARY) $(api_BINARY) $($(X_MODULE)_OUTPUT)/api-lua-wrap.cc objdir/api/lua/CXXFLAGS := -I api $(LUAINCS) -fno-strict-aliasing $($(X_MODULE)_OUTPUT)/api-lua-wrap.cc: $(X_MODULE)/../api.hh $(X_MODULE)/../api-swig.hh $(Q)echo " SWIG $(dir $@)" $(Q)swig -lua -c++ -outdir $(dir $@) -o '$@' $(X_MODULE)/../api-swig.hh # we have an own install _X_BUILD_IMPLICIT := $(_X_BUILD_IMPLICIT) X_BUILD_IMPLICIT := 0 include build/bottom.make X_BUILD_IMPLICIT := $(_X_BUILD_IMPLICIT) api/lua/libdir := $(shell pkg-config lua --variable INSTALL_CMOD) # install all:: $($(X_MODULE)_BINARY) install:: $($(X_MODULE)_BINARY) $(Q)echo "INSTALL LUA module $^" $(Q)mkdir -p $(DESTDIR)$(api/lua/libdir) $(Q)install $^ $(DESTDIR)$(api/lua/libdir) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/api-swig.hh�������������������������������������������������������������������0000644�0000764�0000764�00000001666�11160440733�015203� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * The ExactImage stable external API for use with SWIG. * Copyright (C) 2006 - 2009 René Rebe, ExactCODE GmbH * Copyright (C) 2006 René Rebe, Archivista * * 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. * */ %module ExactImage %include "typemaps.i" %include "cstring.i" %include "std_string.i" # manually include it, otherwise SWIG will not source it %include "config.h" %{ #include "api.hh" %} /* Parse the header file to generate wrappers */ %include "api.hh" ��������������������������������������������������������������������������exact-image-0.9.1/api/Makefile����������������������������������������������������������������������0000644�0000764�0000764�00000000477�11014554154�014602� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include build/top.make BINARY = api BINARY_EXT = $(X_LIBEXT) DEPS = ifeq "$(WITHBARDECODE)" "1" CPPFLAGS += $(BARDECODEINCS) LDFLAGS += $(BARDECODELIBS) endif # we have an own install _X_BUILD_IMPLICIT := $(_X_BUILD_IMPLICIT) X_BUILD_IMPLICIT := 0 include build/bottom.make X_BUILD_IMPLICIT := $(_X_BUILD_IMPLICIT) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/ruby/�������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664271�014132� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/ruby/Makefile�����������������������������������������������������������������0000644�0000764�0000764�00000001527�11076324117�015562� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include build/top.make BINARY = ExactImage BINARY_EXT = $(X_DYNEXT) DEPS = $(lib_BINARY) $(bardecode_BINARY) $(codecs_BINARY) $(api_BINARY) $($(X_MODULE)_OUTPUT)/api-ruby-wrap.cc objdir/api/ruby/CXXFLAGS := -I api $(RUBYINCS) $($(X_MODULE)_OUTPUT)/api-ruby-wrap.cc: $(X_MODULE)/../api.hh $(X_MODULE)/../api-swig.hh $(Q)echo " SWIG $(dir $@)" $(Q)swig -ruby -c++ -outdir $(dir $@) -o '$@' $(X_MODULE)/../api-swig.hh # we have an own install _X_BUILD_IMPLICIT := $(_X_BUILD_IMPLICIT) X_BUILD_IMPLICIT := 0 include build/bottom.make X_BUILD_IMPLICIT := $(_X_BUILD_IMPLICIT) # install all:: $($(X_MODULE)_BINARY) install:: $($(X_MODULE)_BINARY) $(Q)echo "INSTALL PERL module $($(X_MODULE)_OUTPUT)/..." $(Q)mkdir -p $(DESTDIR)$(libdir)/ruby/... $(Q)install $($(X_MODULE)_OUTPUT)/ExactImage.pm $($(X_MODULE)_BINARY) $(DESTDIR)$(libdir)/ruby/... �������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/api.hh������������������������������������������������������������������������0000644�0000764�0000764�00000026167�11215422361�014235� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * The ExactImage stable external API for use with SWIG. * Copyright (C) 2006 - 2009 René Rebe, ExactCODE GmbH * Copyright (C) 2006 - 2008 Archivista 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. */ /* * This header defines the public, supposedly stable, API that can * even be used from C as well as SWIG script language bindings. * * We decided to map the library internals in an non-OO (Object * Oriented) way in order to archive the most flexible external * language choice possible and not to hold of refactoring from * time to time. * * (People demanding a detailed and Object Oriented interface * can still choose to use the fine grained intern C++ API * [which however is not set in stone {at least not yet}].) */ #include <string> #include "config.h" class Image; // just forward, never ever care about the internal layout // instanciate new image class Image* newImage (); // instanciate new imgae class with specified sample cound, bit-depth // and width and height - if fill is 0 the image will be pre-filled // with RGBA(0,0,0,0), if fill is 1 the current background color will // be used. Image* newImageWithTypeAndSize (unsigned int samplesPerPixel, // e.g. 3 unsigned int bitsPerSample, // e.g. 8 unsigned int width, unsigned int height, int fill = 0); // destroy image instance void deleteImage (Image* image); // copy the image's pixel and meta data Image* copyImage (Image* image); Image* copyImageCropRotate (Image* image, int x, int y, unsigned int w, unsigned int h, double angle); // decode image from memory data of size n #if defined(SWIG) && !defined(SWIG_CSTRING_UNIMPL) %apply (char *STRING, int LENGTH) { (char *data, int n) }; #endif #if !defined(SWIG) || (defined(SWIG) && !defined(SWIG_CSTRING_UNIMPL)) bool decodeImage (Image* image, char* data, int n); #endif #if !defined(SWIG) || (defined(SWIG) && defined(SWIG_CSTRING_UNIMPL)) bool decodeImage (Image* image, const std::string& data); #endif // decode image from given filename bool decodeImageFile (Image* image, const char* filename); // encode image to memory, the data is newly allocated and returned // return 0 i the image could not be decoded #if defined(SWIG) && !defined(SWIG_CSTRING_UNIMPL) %cstring_output_allocate_size(char ** s, int *slen, free(*$1)) #endif #if !defined(SWIG) || (defined(SWIG) && !defined(SWIG_CSTRING_UNIMPL)) void encodeImage (char **s, int *slen, Image* image, const char* codec, int quality = 75, const char* compression = ""); #endif #if !defined(SWIG) || (defined(SWIG) && defined(SWIG_CSTRING_UNIMPL)) const std::string encodeImage (Image* image, const char* codec, int quality = 75, const char* compression = ""); #endif // encode image into specified filename bool encodeImageFile (Image* image, const char* filename, int quality = 75, const char* compression = ""); // image properties int imageChannels (Image* image); int imageChannelDepth (Image* image); int imageWidth (Image* image); int imageHeight (Image* image); // returns the name of the image colorspace such as gray, gray2, gray4, rgb8, rgb16, cymk8, cymk16 ... const char* imageColorspace (Image* image); // returns X and Y resolution int imageXres (Image* image); int imageYres (Image* image); // set X and Y resolution void imageSetXres (Image* image, int xres); void imageSetYres (Image* image, int yres); // image manipulation // single pixel access, attention: slow - just for testing / drafting #ifdef SWIG %apply double *OUTPUT { double* r, double* g, double* b, double* a }; #endif void get(Image* image, unsigned int x, unsigned int y, double* r, double* g, double* b, double* a); void set(Image* image, unsigned int x, unsigned int y, double r, double g, double b, double a = 1.0); // transforms the image into a new target colorspace - the names are the same as returned by // imageColorspace, might return false if the conversion was not possible // the threshold is used while converting to black&white (1 bit) data bool imageConvertColorspace (Image* image, const char* target_colorspace, int threshold = 127); void imageResize (Image* image, int x, int y); void imageRotate (Image* image, double angle); void imageFlipX (Image* image); void imageFlipY (Image* image); // best scale (or thru the codec (e.g. JPEG)) or explicit algorithm // if yfactor is not specified, the same factor is used for both directions void imageScale (Image* image, double factor, double yfactor = .0); void imageNearestScale (Image* image, double factor, double yfactor = .0); void imageBoxScale (Image* image, double factor, double yfactor = .0); void imageBilinearScale (Image* image, double factor, double yfactor = .0); void imageThumbnailScale (Image* image, double factor, double yfactor = .0); void imageCrop (Image* image, unsigned int x, unsigned int y, unsigned int w, unsigned int h); // fast auto crop by equal background color // (currently only crops the bottom, might be expanded in the // future to allow top, left, right as well with always just // the bottom crop enabled by default) void imageFastAutoCrop (Image* image); // color controls void setForegroundColor (double r, double g, double b, double a = 1.0); void setBackgroundColor (double r, double g, double b, double a = 1.0); void imageNormalize (Image* image); void imageInvert (Image* image); void imageBrightnessContrastGamma (Image* image, double brightness, double contrast, double gamma); void imageHueSaturationLightness (Image* image, double hue, double saturation, double lightness); // vector elements void setLineWidth (double width); void imageDrawLine (Image* image, double x, double y, double x2, double y2); void imageDrawRectangle (Image* image, double x, double y, double x2, double y2); class Path; // external path Path* newPath(); void deletePath(Path* path); void pathClear(Path* path); // removes existing path elements void pathMoveTo(Path* path, double x, double y); void pathLineTo(Path* path, double x, double y); void pathCurveTo(Path* path, double x, double y, double x2, double y2); void pathQuadCurveTo(Path* path, double x, double y, double x2, double y2, double x3, double y3); void pathClose(Path* path); void pathStroke(Path* path, Image* image); void pathFill(Path* path, Image* image); #if WITHFREETYPE == 1 void imageDrawText(Image* image, double x, double y, char* text, double height, const char* fontfile = NULL); void imageDrawTextOnPath(Image* image, Path* path, char* text, double height, const char* fontfile = NULL); #endif // advanced all-in-one algorithms void imageOptimize2BW (Image* image, int low = 0, int high = 255, int threshold = 170, int radius = 3, double standard_deviation = 2.3, int target_dpi = 0); // remeber: the margin will be rounded down to a multiple of 8, ... bool imageIsEmpty (Image* image, double percent, int margin); #if WITHBARDECODE == 1 // commercial bardecode // codes is the string of barcode to look for, | seperated, like: // CODE39|CODE128|CODE25|EAN13|EAN8|UPCA|UPCE // case doesn't matter // // returned is an alternating array of codes and types, like // "1234", "EAN", "5678", "CODE128", ... #ifdef SWIG #ifdef SWIGPERL5 // Creates a new Perl array and places a NULL-terminated char ** into it %typemap(out) char** { AV *myav; SV **svs; int i = 0,len = 0; /* Figure out how many elements we have */ while ($1[len]) len++; svs = (SV **) malloc(len*sizeof(SV *)); for (i = 0; i < len ; i++) { svs[i] = sv_newmortal(); sv_setpv((SV*)svs[i],$1[i]); free ($1[i]); }; myav = av_make(len,svs); free(svs); free($1); $result = newRV((SV*)myav); sv_2mortal($result); argvi++; } #endif #endif /* directions bitfield of directions to be scanned: 1: left-to-right, 0 degree to image data 2: top-down, 90 degree to image data 4: right-to-left, 180 degree to image data 8: down-to-top, -90 degree to image data */ char** imageDecodeBarcodesExt (Image* image, const char* codes, unsigned int min_length = 0, unsigned int max_length = 0, int multiple = 0, int directions = 0xf); #endif #ifdef SWIG #ifdef SWIGPERL5 // Creates a new Perl array and places a NULL-terminated char ** into it %typemap(out) char** { AV *myav; SV **svs; int i = 0,len = 0; /* Figure out how many elements we have */ while ($1[len]) len++; svs = (SV **) malloc(len*sizeof(SV *)); for (i = 0; i < len ; i++) { svs[i] = sv_newmortal(); sv_setpv((SV*)svs[i],$1[i]); free ($1[i]); }; myav = av_make(len,svs); free(svs); free($1); $result = newRV((SV*)myav); sv_2mortal($result); argvi++; } #endif #ifdef SWIGLUA // Creates a new Lua table and places a NULL-terminated char ** into it %typemap(out) char** { lua_newtable(L); int i = 0,len = 0; /* Figure out how many elements we have */ while ($1[len]) len++; for (i = 0; i < len ; i++) { lua_pushnumber(L, 1.+i); lua_pushstring(L, $1[i]); lua_settable(L, -3); free ($1[i]); }; free($1); return 1; } #endif #endif /* directions bitfield of directions to be scanned: 1: left-to-right, 0 degree to image data 2: top-down, 90 degree to image data 4: right-to-left, 180 degree to image data 8: down-to-top, -90 degree to image data */ char** imageDecodeBarcodes (Image* image, const char* codes, unsigned int min_length = 0, unsigned int max_length = 0, int multiple = 0, unsigned int line_skip = 8, int directions = 0xf); /* contour matching functions * attention: * this part of the api is in an evaluation phase and not yet written in stone !! */ class Contours; class LogoRepresentation; Contours* newContours(Image* image, int low = 0, int high = 0, int threshold = 0, int radius = 3, double standard_deviation = 2.1); void deleteContours(Contours* contours); LogoRepresentation* newRepresentation(Contours* logo_contours, int max_feature_no=10, int max_avg_tolerance=20, int reduction_shift=3, double maximum_angle=0.0, double angle_step=0.0); void deleteRepresentation(LogoRepresentation* representation); double matchingScore(LogoRepresentation* representation, Contours* image_contours); // theese are valid after call to MatchingScore() double logoAngle(LogoRepresentation* representation); int logoTranslationX(LogoRepresentation* representation); int logoTranslationY(LogoRepresentation* representation); int inverseLogoTranslationX(LogoRepresentation* representation, Image* image); int inverseLogoTranslationY(LogoRepresentation* representation, Image* image); void drawMatchedContours(LogoRepresentation* representation, Image* image); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/python/�����������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664271�014472� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/python/Makefile���������������������������������������������������������������0000644�0000764�0000764�00000001631�11401140312�016077� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include build/top.make BINARY = _ExactImage BINARY_EXT = $(X_DYNEXT) DEPS = $(lib_BINARY) $(bardecode_BINARY) $(codecs_BINARY) $(api_BINARY) $($(X_MODULE)_OUTPUT)/api-python-wrap.cc objdir/api/python/CXXFLAGS := -I api $(PYTHONINCS) $($(X_MODULE)_OUTPUT)/api-python-wrap.cc: $(X_MODULE)/../api.hh $(X_MODULE)/../api-swig.hh $(Q)echo " SWIG $(dir $@)" $(Q)swig -python -c++ -outdir $(dir $@) -o '$@' $(X_MODULE)/../api-swig.hh # we have an own install _X_BUILD_IMPLICIT := $(_X_BUILD_IMPLICIT) X_BUILD_IMPLICIT := 0 include build/bottom.make X_BUILD_IMPLICIT := $(_X_BUILD_IMPLICIT) PYTHON_LIBDIR := $(shell python -c 'from distutils.sysconfig import get_python_lib; print get_python_lib()') # install all:: $($(X_MODULE)_BINARY) install:: $($(X_MODULE)_BINARY) $(Q)echo "INSTALL PYTHON module $^" $(Q)mkdir -p $(DESTDIR)$(PYTHON_LIBDIR) $(Q)install $(dir $^)/ExactImage.py $^ $(DESTDIR)$(PYTHON_LIBDIR)/ �������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/php/��������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664271�013740� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/api/php/Makefile������������������������������������������������������������������0000644�0000764�0000764�00000001452�11076324117�015365� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include build/top.make BINARY = ExactImage BINARY_EXT = $(X_DYNEXT) DEPS = $(lib_BINARY) $(bardecode_BINARY) $(codecs_BINARY) $(api_BINARY) $($(X_MODULE)_OUTPUT)/api-php-wrap.cc objdir/api/php/CXXFLAGS := -I api $(PHPINCS) -fno-strict-aliasing $($(X_MODULE)_OUTPUT)/api-php-wrap.cc: $(X_MODULE)/../api.hh $(X_MODULE)/../api-swig.hh $(Q)echo " SWIG $(dir $@)" $(Q)swig -php5 -c++ -outdir $(dir $@) -o '$@' $(X_MODULE)/../api-swig.hh # we have an own install _X_BUILD_IMPLICIT := $(_X_BUILD_IMPLICIT) X_BUILD_IMPLICIT := 0 include build/bottom.make X_BUILD_IMPLICIT := $(_X_BUILD_IMPLICIT) # install all:: $($(X_MODULE)_BINARY) install:: $($(X_MODULE)_BINARY) $(Q)echo "INSTALL PHP module $^" $(Q)mkdir -p $(DESTDIR)$(libdir)/php/ $(Q)install $^ $(dir $^)/ExactImage.php $(DESTDIR)$(libdir)/php/ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/examples/�������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664272�014217� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/examples/fuzz.pl������������������������������������������������������������������0000644�0000764�0000764�00000002550�11215423364�015535� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ExactImage Perl Example # Copyright (C) 2008 Rene Rebe, ExactCODE GmbH use strict; # the ExactImage module use lib './objdir/api/perl'; use Math::Trig; use ExactImage; # create an ExactImage my $image = ExactImage::newImage (); # easy use, use on-disc files: if (ExactImage::decodeImageFile ($image, "testsuite/tif/4.2.04.tif")) { print "image decoded all fine.\n"; } else { print "something went wrong ...\n"; exit; } my $width = ExactImage::imageWidth($image); my $height = ExactImage::imageHeight($image); my $i = 0; # TODO: a loop over all common color spaces # ExactImage::imageConvertColorspace($image, "gray1"); for (my $n = 100; $n > 0; $n--, $i++) { my $x = int rand(2 * $width) - $width; my $y = int rand(2 * $height) - $height; my $w = int rand($width); my $h = int rand($height); my $a = rand(2*pi) - pi; print ("crop: $x $y $w $h $a\n"); my $newimage = ExactImage::copyImageCropRotate($image, $x, $y, $w, $h, $a); if (ExactImage::encodeImageFile ($newimage, "fuzz-out-$i.pnm")) { print "image written all fine.\n"; } else { print "something went wrong writing the image ...\n"; exit; } ExactImage::deleteImage ($newimage); } # we do not want to leak memory, always delete the image # when you are done with it! ExactImage::deleteImage ($image); print "ok, here the example ends (for now) ...\n"; ��������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/examples/test.php�����������������������������������������������������������������0000644�0000764�0000764�00000002603�11444457016�015676� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/php -d extension_dir=./objdir/api/php <?php # ExactImage PHP Example # Copyright (C) 2008 - 2010 Rene Rebe, ExactCODE GmbH ini_set("include_path", "./objdir/api/php/"); //ini_set("extension_dir", "./objdir/api/php/"); // does not work here // load the module include("ExactImage.php"); $image = newImage(); if (decodeImageFile ($image, "testsuite/tif/4.2.04.tif")) { print "image decoded all fine.\n"; } else { print "something went wrong ...\n"; exit; } if (encodeImageFile ($image, "test.jpg", 80, "")) { print "image written all fine.\n"; } else { print "something went wrong writing the image ...\n"; exit; } # advanced use, use in memory locations $image_bits=`cat testsuite/tif/5.1.13.tif`; if (decodeImage ($image, $image_bits)) { print "image read from RAM.\n"; } else { print "something went wrong decoding the RAM\n"; exit; } # image properties print "Width: " . imageWidth ($image) . "\n"; print "Height: " . imageHeight ($image) . "\n"; print "Xres: " . imageXres ($image) . "\n"; print "Yres: " . imageYres ($image) . "\n"; print "Channels: " . imageChannels ($image) . "\n"; print "Channel depth: " . imageChannelDepth ($image). "\n"; # setable as well imageSetXres ($image, 144); imageSetYres ($image, 144); print "Xres: " . imageXres ($image) . "\n"; print "Yres: " . imageYres ($image) . "\n"; deleteImage($image); ?> �����������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/examples/test.py������������������������������������������������������������������0000644�0000764�0000764�00000003165�11444457016�015543� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ExactImage Python Example # Copyright (C) 2008 - 2010 Rene Rebe, ExactCODE GmbH import sys sys.path.append('./objdir/api/python') import ExactImage image = ExactImage.newImage() if ExactImage.decodeImageFile (image, "testsuite/tif/4.2.04.tif"): print "image decoded all fine." else: print "something went wrong ..." exit if ExactImage.encodeImageFile (image, "test.jpg", 80, ""): print "image written all fine." else: print "something went wrong writing the image ..." exit # advanced use, use in memory locations f = open("testsuite/tif/5.1.13.tif") try: image_bits = f.read() finally: f.close() if ExactImage.decodeImage (image, image_bits): print "image read from RAM." else: print "something went wrong decoding the RAM\n"; exit # image properties print "Width: ", ExactImage.imageWidth (image) print "Height: ", ExactImage.imageHeight (image) print "Xres: ", ExactImage.imageXres (image) print "Yres: ", ExactImage.imageYres (image) print "Channels: ", ExactImage.imageChannels (image) print "Channel depth: ", ExactImage.imageChannelDepth (image) # setable as well ExactImage.imageSetXres (image, 144); ExactImage.imageSetYres (image, 144); print "Xres: ", ExactImage.imageXres (image) print "Yres: ", ExactImage.imageYres (image) # image data manipulation ExactImage.imageRotate (image, 90); ExactImage.imageScale (image, 4); ExactImage.imageBoxScale (image, .5); image_bits = ExactImage.encodeImage (image, "jpeg", 80, ""); print "size: ", len(image_bits) f = open("python.jpg", "w") try: image_bits = f.write(image_bits) finally: f.close() ExactImage.deleteImage(image) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/examples/test.pl������������������������������������������������������������������0000644�0000764�0000764�00000007377�11444457016�015537� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# ExactImage Perl Example # Copyright (C) 2006 - 2010 Rene Rebe, ExactCODE GmbH use strict; # the ExactImage module use lib './objdir/api/perl'; use ExactImage; # create an ExactImage my $image = ExactImage::newImage (); # easy use, use on-disc files: if (ExactImage::decodeImageFile ($image, "testsuite/tif/4.2.04.tif")) { print "image decoded all fine.\n"; } else { print "something went wrong ...\n"; exit; } if (ExactImage::encodeImageFile ($image, "test.jpg", 80, "")) { print "image written all fine.\n"; } else { print "something went wrong writing the image ...\n"; exit; } # advanced use, use in memory locations my $image_bits=`cat testsuite/tif/5.1.13.tif`; if (ExactImage::decodeImage ($image, $image_bits)) { print "image read from RAM.\n"; } else { print "something went wrong decoding the RAM\n"; exit; } # image properties print "Width: " . ExactImage::imageWidth ($image) . "\n"; print "Height: " . ExactImage::imageHeight ($image) . "\n"; print "Xres: " . ExactImage::imageXres ($image) . "\n"; print "Yres: " . ExactImage::imageYres ($image) . "\n"; print "Channels: " . ExactImage::imageChannels ($image) . "\n"; print "Channel depth: " . ExactImage::imageChannelDepth ($image). "\n"; # setable as well ExactImage::imageSetXres ($image, 144); ExactImage::imageSetYres ($image, 144); print "Xres: " . ExactImage::imageXres ($image) . "\n"; print "Yres: " . ExactImage::imageYres ($image) . "\n"; # image data manipulation ExactImage::imageRotate ($image, 90); ExactImage::imageScale ($image, 4); ExactImage::imageBoxScale ($image, .5); $image_bits = ExactImage::encodeImage ($image, "jpeg", 80, ""); print "size: " . length($image_bits) . "\n"; if (length($image_bits) > 0) { print "image encoded all fine.\n"; } else { print "something went wrong encoding the image into RAM\n"; exit; } # write the file to disc using Perl open (IMG, ">perl.jpg"); print IMG $image_bits; close IMG; # complex all-in-one function if (ExactImage::decodeImageFile ($image, "testsuite/tif/4.2.04.tif")) { my $image_copy = ExactImage::copyImage ($image); ExactImage::imageOptimize2BW ($image, 0, 0, 170, 3, 2.1); ExactImage::encodeImageFile ($image, "optimize.tif", 0, ""); my $is_empty = ExactImage::imageIsEmpty ($image, 0.02, 16); if ($is_empty) { print "Image is empty\n"; } else { print "Image is not empty, too many pixels ...\n"; } # the image is bw, now - but we still have a copy ExactImage::encodeImageFile ($image_copy, "copy.tif", 0, ""); # and do not forget the free the copy, otherwise it is leaked ExactImage::deleteImage ($image_copy); } else { printf "Error loading testsuite/deskew/01.tif\n"; } if (ExactImage::decodeImageFile ($image, "testsuite/empty-page/empty.tif")) { my $is_empty = ExactImage::imageIsEmpty ($image, 0.02, 16); if ($is_empty) { print "Image is empty\n"; } else { print "Image is not empty, too many pixels ...\n"; } } else { printf "Error loading testsuite/empty-page/empty.tif\n"; } # barcode decoding while (<testsuite/barcodes/Scan-001-4.tif>) { printf "looking for barcodes in $_\n"; if (ExactImage::decodeImageFile ($image, "$_")) { my $barcodes = ExactImage::imageDecodeBarcodes ($image, "code39|CODE128|CODE25|EAN13|EAN8|UPCA|UPCE", 3, # min length 10); # max length for (my $i;$i< scalar(@$barcodes);$i+=2) { print "@$barcodes[$i] @$barcodes[$i+1]\n"; } } else { printf "Error loading $_\n"; } } # we do not want to leak memory, always delete the image # when you are done with it! ExactImage::deleteImage ($image); print "ok, here the example ends (for now) ...\n"; �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/examples/test.lua�����������������������������������������������������������������0000644�0000764�0000764�00000007713�11444457016�015677� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/lua -- ExactImage Lua Example -- Copyright (C) 2008 - 2010 Rene Rebe, ExactCODE GmbH package.cpath = "./objdir/api/lua/?.so;" .. package.cpath require "ExactImage" -- create an ExactImage image = ExactImage.newImage () -- easy use, use on-disc files: if ExactImage.decodeImageFile (image, "testsuite/tif/4.2.04.tif") then print "image decoded all fine." else print "something went wrong ..." os.exit(1) end if ExactImage.encodeImageFile (image, "test.jpg", 80, "") then print "image written all fine." else print "something went wrong writing the image ..." os.exit(1) end -- advanced use, use in memory locations f = io.open ("testsuite/tif/4.2.04.tif") image_bits = f:read("*all") if ExactImage.decodeImage (image, image_bits) then print "image read from RAM." else print "something went wrong decoding the RAM ..." os.exit(1) end f:close() -- image properties print ("Width: " .. ExactImage.imageWidth (image)) print ("Height: " .. ExactImage.imageHeight (image)) print ("Xres: " .. ExactImage.imageXres (image)) print ("Yres: " .. ExactImage.imageYres (image)) print ("Channels: " .. ExactImage.imageChannels (image)) print ("Channel depth: " .. ExactImage.imageChannelDepth (image)) -- setable as well ExactImage.imageSetXres (image, 144); ExactImage.imageSetYres (image, 144); print ("Xres: " .. ExactImage.imageXres (image)) print ("Yres: " .. ExactImage.imageYres (image)) -- image data manipulation --[[ ExactImage.imageRotate (image, 90) ExactImage.imageScale (image, 4) ExactImage.imageBoxScale (image, .5) ]]-- for y = 0, ExactImage.imageHeight(image) - 1 do for x = 0, ExactImage.imageWidth(image) - 1 do local r, g, b, a = ExactImage.get(image, x, y) ExactImage.set(image, x, y, 1-r, 1-g, 1-b, 1-a) -- x / 256, y / 256, x*y / 256, 1) end end image_bits = ExactImage.encodeImage (image, "jpeg", 80, "") print ("size: " .. string.len(image_bits)) if string.len(image_bits) > 0 then print "image encoded all fine." else print "something went wrong encoding the image into RAM ..." os.exit(1) end -- write the file to disc natively f = io.open ("lua.jpg", "w"); f:write (image_bits) f:close () -- complex all-in-one function if ExactImage.decodeImageFile (image, "testsuite/tif/4.2.04.tif") then image_copy = ExactImage.copyImage (image); ExactImage.imageOptimize2BW (image, 0, 0, 170, 3, 2.1); ExactImage.encodeImageFile (image, "optimize.tif", 0, ""); is_empty = ExactImage.imageIsEmpty (image, 0.02, 16); if is_empty then print "Image is empty" else print "Image is not empty, too many pixels ...\n"; end -- the image is bw, now - but we still have a copy ExactImage.encodeImageFile (image_copy, "copy.tif", 0, ""); -- and do not forget the free the copy, otherwise it is leaked ExactImage.deleteImage (image_copy); else printf "Error loading testsuite/deskew/01.tif" end if ExactImage.decodeImageFile (image, "testsuite/empty-page/empty.tif") then is_empty = ExactImage.imageIsEmpty (image, 0.02, 16); if is_empty then print "Image is empty"; else print "Image is not empty, too many pixels ...\n"; end else print "Error loading testsuite/empty-page/empty.tif" end -- barcode decoding --while (<Scan-001-4.tif>) f = "testsuite/barcodes/Scan-001-4.tif" print ("looking for barcodes in " .. f) if ExactImage.decodeImageFile (image, f) then barcodes = ExactImage.imageDecodeBarcodes (image, "code39|CODE128|CODE25|EAN13|EAN8|UPCA|UPCE", 3, -- min length 10) -- max length print ("type: " .. type(barcodes)) --for (my $i;$i< scalar(@$barcodes);$i+=2) { -- print "@$barcodes[$i] @$barcodes[$i+1]\n"; --} else print ("Error loading " .. f) end --end -- we do not want to leak memory, always delete the image -- when you are done with it! ExactImage.deleteImage (image); print "ok, here the example ends (for now) ..." �����������������������������������������������������exact-image-0.9.1/CODING����������������������������������������������������������������������������0000644�0000764�0000764�00000000167�10400640341�013243� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� The code should be written in modern, template and STL based C++. Due to rapid prototyping this is not the case yet. ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/edisplay/�������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664272�014213� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/edisplay/edisplay.cc��������������������������������������������������������������0000644�0000764�0000764�00000045463�11737001226�016327� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * The ExactImage library's displayy compatible command line frontend. * Copyright (C) 2006 - 2012 René Rebe * * 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 "config.h" #include <X11/Xutil.h> #include <X11/keysym.h> #include "Evas.h" #include "Evas_Engine_Software_X11.h" #if EVASGL == 1 #include "Evas_Engine_GL_X11.h" #endif #include <endian.h> #include <algorithm> #include <iostream> #include <sstream> #include <unistd.h> #include "ArgumentList.hh" using namespace Utility; // imaging stuff #include "Codecs.hh" #include "Colorspace.hh" #include "rotate.hh" #include "edisplay.hh" #include "Endianess.hh" using std::cout; using std::cerr; using std::endl; static uint32_t evas_bgr_image_data[] = { 0x999999, 0x666666, 0x666666, 0x999999}; int Viewer::Window2ImageX (int x) { return (x - evas_image->X() ) * 100 / zoom; } int Viewer::Window2ImageY (int y) { return (y - evas_image->Y() ) * 100 / zoom; } void Viewer::Zoom (double f) { // to keep the view centered int xcent = Window2ImageX (evas->OutputWidth()/2); int ycent = Window2ImageY (evas->OutputHeight()/2); int z = zoom; zoom = (int) (f * zoom); if (f > 1.0 && zoom == z) ++zoom; else if (zoom <= 0) zoom = 1; SetOSDZoom (); Evas_Coord w = (Evas_Coord) (zoom * image->w / 100); Evas_Coord h = (Evas_Coord) (zoom * image->h / 100); evas_bgr_image->Resize (w, h); // recenter view for (std::vector<EvasImage*>::iterator it = evas_content.begin(); it != evas_content.end(); ++it) { (*it)->Resize (w, h); (*it)->ImageFill (0, 0, w, h); (*it)->Move (- (xcent * zoom / 100 - (evas->OutputWidth() / 2)), - (ycent * zoom / 100 - (evas->OutputHeight() / 2)) ); } // limit / clip accordingly Move (0, 0); if (true) { // resize X window accordingly X11Window::Resize (dpy, win, std::min(w, X11Window::Width(dpy, 0)), std::min(h, X11Window::Height(dpy, 0))); } } void Viewer::Move (int _x, int _y) { Evas_Coord x = evas_image->X() + _x; Evas_Coord y = evas_image->Y() + _y; Evas_Coord w = evas_image->Width(); Evas_Coord h = evas_image->Height(); // limit if (x + w < evas->OutputWidth() ) x = evas->OutputWidth() - w; if (x > 0) x = 0; if (y + h < evas->OutputHeight() ) y = evas->OutputHeight() - h; if (y > 0) y = 0; for (std::vector<EvasImage*>::iterator it = evas_content.begin(); it != evas_content.end(); ++it) (*it)->Move (x, y); } void Viewer::UpdateOSD (const std::string& str1, const std::string& str2) { evas_osd_text1->Text (str1); evas_osd_text2->Text (str2); evas_osd_rect->Resize (std::max(evas_osd_text1->Width(), evas_osd_text2->Width()) + 4, evas_osd_text1->Height() + evas_osd_text2->Height() + 8); AlphaOSD (0xFF); osd_timer.Reset (); } void Viewer::AlphaOSD (int a) { evas_osd_text1->Color (0xFF, 0xFF, 0xFF, a); evas_osd_text2->Color (0xFF, 0xFF, 0xFF, a); evas_osd_rect->Color (0x40, 0x40, 0x40, std::max (a-92, 0)); } void Viewer::TickOSD () { const int d = osd_timer.Delta (); const int ps = osd_timer.PerSecond (); if (d > ps && d <= 2*ps) { int a = std::max (0xFF - (d - ps) * 0xff / ps, 0); AlphaOSD (a); } } void Viewer::SetOSDZoom () { std::stringstream s1, s2; s1 << "Zoom: " << zoom << "%"; s2 << "Anti-alias: " << (evas_image->SmoothScale() ? "yes" : "no"); UpdateOSD (s1.str(), s2.str()); } int Viewer::Run (bool opengl) { // TODO: move to the X11Helper ... XSetWindowAttributes attr; XClassHint chint; #if 0 XSizeHints szhints; #endif dpy = XOpenDisplay (NULL); if (!dpy) { return false; } scr = DefaultScreen (dpy); Window root = RootWindow(dpy, scr); attr.backing_store = NotUseful; attr.border_pixel = 0; attr.background_pixmap = None; attr.event_mask = ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | StructureNotifyMask; attr.bit_gravity = ForgetGravity; /* attr.override_redirect = 1; */ visual = DefaultVisual (dpy, scr); depth = DefaultDepth(dpy, scr); attr.colormap = DefaultColormap(dpy, scr); int win_w = 1; int win_h = 1; win = XCreateWindow (dpy, root, (X11Window::Width(dpy, 0) - win_w) / 2, (X11Window::Height(dpy, 0) - win_h) / 2, win_w, win_h, 0, depth, InputOutput, visual, /*CWOverrideRedirect | */ CWBackingStore | CWColormap | CWBackPixmap | CWBorderPixel | CWBitGravity | CWEventMask, &attr); XStoreName (dpy, win, "edisplay"); chint.res_name = "edisplay"; chint.res_class = "Main"; XSetClassHint (dpy, win, &chint); #if 0 szhints.flags = PMinSize | PMaxSize | PSize | USSize; szhints.min_width = szhints.max_width = win_w; szhints.min_height = szhints.max_height = win_h; XSetWMNormalHints(dpy, win, &szhints); #endif XSync(dpy, False); evas = new EvasCanvas (); if (!opengl) { evas->OutputMethod ("software_x11"); evas->OutputSize (win_w, win_h); evas->OutputViewport (0, 0, win_w, win_h); Evas_Engine_Info_Software_X11* einfo; einfo = (Evas_Engine_Info_Software_X11*) evas->EngineInfo (); /* the following is specific to the engine */ #ifdef WITHEVAS_X11_CONNECTION einfo->info.connection = dpy; #else einfo->info.display = dpy; #endif einfo->info.visual = visual; einfo->info.colormap = attr.colormap; einfo->info.drawable = win; einfo->info.depth = depth; einfo->info.rotation = 0; einfo->info.debug = 0; evas->EngineInfo ( (Evas_Engine_Info*)einfo ); } #if EVASGL == 1 else { evas->OutputMethod ("gl_x11"); evas->OutputSize (win_w, win_h); evas->OutputViewport (0, 0, win_w, win_h); Evas_Engine_Info_GL_X11* einfo; einfo = (Evas_Engine_Info_GL_X11*) evas->EngineInfo (); /* the following is specific to the engine */ einfo->info.display = dpy; #ifdef WITHEVAS_X11_SCREEN einfo->info.screen = DefaultScreen(dpy); einfo->info.visual = einfo->func.best_visual_get(einfo); einfo->info.colormap = einfo->func.best_colormap_get(einfo); #else einfo->info.visual = einfo->func.best_visual_get(dpy, DefaultScreen(dpy)); einfo->info.colormap = einfo->func.best_colormap_get(dpy, DefaultScreen(dpy)); #endif einfo->info.drawable = win; einfo->info.depth = depth; evas->EngineInfo ( (Evas_Engine_Info*)einfo ); } #endif /* Setup */ evas->FontPathPrepend ("/usr/X11/lib/X11/fonts/TTF/"); evas->FontPathPrepend ("/usr/X11/lib/X11/fonts/TrueType/"); evas->FontPathPrepend ("/opt/e17/share/evas/data/"); evas->FontPathPrepend ("/usr/X11/share/fonts/TTF/"); if (true) { evas->ImageCache (1024 * 1024); evas->FontCache (256 * 1024); } else { evas->ImageCache (0); evas->FontCache (0); } evas_bgr_image = new EvasImage (*evas); evas_bgr_image->SmoothScale (false); evas_bgr_image->Layer (0); evas_bgr_image->Move (0,0); evas_bgr_image->ImageSize (2,2); evas_bgr_image->ImageFill (0,0,24,24); evas_bgr_image->Resize (win_w,win_h); evas_bgr_image->DataUpdateAdd (0,0,2,2); evas_bgr_image->SetData ((uint8_t*)evas_bgr_image_data); evas_bgr_image->Show (); // OSD evas_osd_text1 = new EvasText (*evas); evas_osd_text1->Layer (10); evas_osd_text1->Move (4,4); evas_osd_text1->Font ("Vera", 10); evas_osd_text1->Show (); evas_osd_text2 = new EvasText (*evas); evas_osd_text2->Layer (10); evas_osd_text2->Move (4,8 + evas_osd_text1->Height()); evas_osd_text2->Font ("Vera", 10); evas_osd_text2->Show (); evas_osd_rect = new EvasRectangle (*evas); evas_osd_rect->Layer (5); evas_osd_rect->Move (2,2); evas_osd_rect->Show (); AlphaOSD (0); bool image_loaded; image_loaded = Load (); if (!image_loaded) image_loaded = Next (); XMapWindow (dpy, win); bool quit = false; Utility::Timer timer; int dnd_x = 0, dnd_y = 0; bool dnd_moved = false; while (image_loaded && !quit) { // process X11 events ... // TODO: move into X11 Helper ... XEvent ev; while (XCheckMaskEvent (dpy, ExposureMask | StructureNotifyMask | KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask, &ev)) { Evas_Button_Flags flags = EVAS_BUTTON_NONE; switch (ev.type) { case ButtonPress: { //evas->EventFeedMouseMove (ev.xbutton.x, ev.xbutton.y); //evas->EventFeedMouseDown (ev.xbutton.button, flags); dnd_moved = false; switch (ev.xbutton.button) { case 1: dnd_x = ev.xbutton.x; dnd_y = ev.xbutton.y; break; case 4: if (ev.xbutton.state & ControlMask) Zoom (1.1); else Move (0, 40); break; case 5: if (ev.xbutton.state & ControlMask) Zoom (1.0/1.1); else Move (0, -40); break; case 6: Move (40, 0); break; case 7: Move (-40, 0); break; } } break; case ButtonRelease: if (!dnd_moved) ImageClicked(Window2ImageX (ev.xmotion.x), Window2ImageY (ev.xmotion.y), ev.xbutton.button); break; case MotionNotify: // evas->EventFeedMouseMove (ev.xmotion.x, ev.xmotion.y); // dragged around: dnd_moved = true; if (ev.xmotion.state & Button1Mask) { int dx = ev.xmotion.x - dnd_x; int dy = ev.xmotion.y - dnd_y; dnd_x = ev.xmotion.x; dnd_y = ev.xmotion.y; Move (dx, dy); } else // no handled button, update OSD { std::stringstream s1, s2; int x = Window2ImageX (ev.xmotion.x); int y = Window2ImageY (ev.xmotion.y); if (x <= image->w && y <= image->h) { uint16_t r = 0, g = 0, b = 0; Image::iterator it = image->begin(); it = it.at (x, y); (*it).getRGB (&r, &g, &b); s1 << "x: " << x << ", y: " << y; s2 << "r: " << std::hex << r << ", g: " << g << ", b: " << b; } else { s1 << "x: , y:"; s2 << "r: , g: , b:"; } UpdateOSD (s1.str(), s2.str()); } break; case KeyPress: KeySym ks; XLookupString ((XKeyEvent*)&ev, 0, 0, &ks, NULL); if (ImageKey(ks)) break; //cout << "key: " << ev.xkey.keycode << endl; //cout << "sym: " << ks << endl; switch (ks) { case XK_1: zoom = 100; Zoom (1); break; case XK_plus: Zoom (2); break; case XK_minus: Zoom (.5); break; case XK_Left: Move (40, 0); break; case XK_Right: Move (-40, 0); break; case XK_Up: Move (0, 40); break; case XK_Down: Move (0, -40); break; case XK_Page_Up: Move (0, 160); break; case XK_Page_Down: Move (0, -160); break; case XK_space: image_loaded = Next (); break; case XK_BackSpace: image_loaded = Previous (); break; case XK_ISO_Left_Tab: channel -= 2; // +1 below ... case XK_Tab: ++channel; if (channel > 6) channel = 0; else if (channel < 0) channel = 6; ImageToEvas (); { std::string s1, s2; s1 = "Color channel"; switch (channel) { case 1: s2 = "just R"; break; case 2: s2 = "just G"; break; case 3: s2 = "just B"; break; case 4: s2 = "R intensity"; break; case 5: s2 = "G intensity"; break; case 6: s2 = "B intensity"; break; default: s2 = "NONE"; } s2 = "dropout: " + s2; UpdateOSD (s1, s2); } break; case XK_a: evas_image->SmoothScale (!evas_image->SmoothScale()); // schedule the update evas->DamageRectangleAdd (0, 0, evas->OutputWidth(), evas->OutputHeight()); SetOSDZoom (); break; case XK_i: invert (*image); ImageToEvas (); AlphaOSD (0); break; case XK_greater: rotate (*image, 90, image->begin()); ImageToEvas (); AlphaOSD (0); break; case XK_less: rotate (*image, -90, image->begin()); ImageToEvas (); AlphaOSD (0); break; case XK_q: quit = true; break; } break; case Expose: evas->DamageRectangleAdd (ev.xexpose.x, ev.xexpose.y, ev.xexpose.width, ev.xexpose.height); break; case ConfigureNotify: evas_bgr_image->Resize (ev.xconfigure.width, ev.xconfigure.height); evas->OutputSize (ev.xconfigure.width, ev.xconfigure.height); evas->OutputViewport (0, 0, ev.xconfigure.width, ev.xconfigure.height); // limit/clip Move (0, 0); break; default: break; } } TickOSD (); evas->Render (); XFlush (dpy); usleep (10000); } if (evas_image) { delete evas_image; evas_image = 0; } delete evas_osd_text1; evas_osd_text1 = 0; delete evas_osd_text2; evas_osd_text2 = 0; delete evas_osd_rect; evas_osd_rect = 0; delete evas_bgr_image; evas_bgr_image = 0; delete evas; evas = 0; return 0; } bool Viewer::Next () { std::vector<std::string>::const_iterator ref_it = it; do { ++it; if (it == images.end()) it = images.begin(); if (Load ()) return true; } while (it != ref_it); return false; } bool Viewer::Previous () { std::vector<std::string>::const_iterator ref_it = it; do { if (it == images.begin()) it = images.end(); --it; if (Load ()) return true; } while (it != ref_it); return false; } bool Viewer::Load () { image->setRawData(0); // reset channel filter channel = 0; if (!ImageCodec::Read(*it, *image)) { // TODO: fix to gracefully handle this cerr << "Error loading file: " << *it << endl; return false; } // notify early to allow sub-class to make modifications ImageLoaded (); if (false) cerr << "Loaded: '" << *it << "', " << image->w << "x" << image->h << " @ " << image->resolutionX() << "x" << image->resolutionY() << " dpi - spp: " << image->spp << ", bps: " << image->bps << endl; // convert colorspace if (image->bps == 16) colorspace_16_to_8 (*image); // convert any gray to RGB if (image->spp == 1) colorspace_grayX_to_rgb8 (*image); if (image->bps != 8 || (image->spp != 3 && image->spp != 4)) { cerr << "Unsupported colorspace. bps: " << image->bps << ", spp: " << image->spp << endl; cerr << "If possible please send a test image to rene@exactcode.de." << endl; return false; } if (!image->getRawData()) { cerr << "image data not loaded?"<< endl; return false; } ImageToEvas (); std::string title = *it; title.insert (0, "edisplay: "); XStoreName (dpy, win, title.c_str()); return true; } void Viewer::ImageToEvas () { if (!evas_image) { evas_image = new EvasImage (*evas); evas_image->SmoothScale (false); evas_image->Layer (1); evas_image->Move (0, 0); evas_image->Resize (image->w,image->h); evas_content.push_back(evas_image); } else { evas_image->SetData (0); } evas_image = ImageToEvas (image, evas_image); // position and resize, keep zoom if (false) { zoom = 100; } Zoom (1.0); } EvasImage* Viewer::ImageToEvas (Image* image, EvasImage* eimage) { uint8_t* evas_data = 0; if (!eimage) { eimage = new EvasImage (*evas); eimage->SmoothScale (false); eimage->Layer (1); eimage->Move (0, 0); eimage->Resize (image->w,image->h); } else { eimage->SetData (0); } evas_data = (uint8_t*) realloc (evas_data, image->w*image->h*4); uint8_t* src_ptr = image->getRawData(); uint8_t* dest_ptr = evas_data; const int spp = image->spp; if (channel == 0) { for (int y=0; y < image->h; ++y) for (int x=0; x < image->w; ++x, dest_ptr +=4, src_ptr += spp) { if (!Exact::NativeEndianTraits::IsBigendian) { dest_ptr[0] = src_ptr[2]; dest_ptr[1] = src_ptr[1]; dest_ptr[2] = src_ptr[0]; if (spp == 4) dest_ptr[3] = src_ptr[3]; // alpha } else { dest_ptr[1] = src_ptr[0]; dest_ptr[2] = src_ptr[1]; dest_ptr[3] = src_ptr[2]; if (spp == 4) dest_ptr[0] = src_ptr[3]; // alpha } } } else { bool intensity = channel > 3; int ch = (channel-1) % 3; for (int y=0; y < image->h; ++y) for (int x=0; x < image->w; ++x, dest_ptr +=4, src_ptr += spp) { if (!Exact::NativeEndianTraits::IsBigendian) { dest_ptr[0] = dest_ptr[1] = dest_ptr[2] = intensity ? src_ptr[ch] : 0; if (!intensity) dest_ptr[2-ch] = src_ptr[ch]; } else { dest_ptr[1] = dest_ptr[2] = dest_ptr[3] = intensity ? src_ptr[ch] : 0; if (!intensity) dest_ptr[1+ch] = src_ptr[ch]; } } } eimage->Alpha (spp == 4); eimage->Resize (image->w, image->h); eimage->ImageSize (image->w, image->h); eimage->ImageFill (0, 0, image->w,image->h); eimage->SetData (evas_data); eimage->DataUpdateAdd (0, 0, image->w,image->h); eimage->Show (); return eimage; } Viewer* __attribute__ ((weak)) createViewer(const std::vector<std::string>& args) { return new Viewer(args); } int main (int argc, char** argv) { ArgumentList arglist (true); // enable residual gathering // setup the argument list Argument<bool> arg_help ("", "help", "display this help text and exit"); arglist.Add (&arg_help); #if EVASGL == 1 Argument<bool> arg_gl ("", "gl", "Utilize OpenGL for rendering"); arglist.Add (&arg_gl); #endif // parse the specified argument list - and maybe output the Usage if (!arglist.Read (argc, argv) || arg_help.Get() == true || arglist.Residuals().empty()) { cerr << "Exact image viewer (edisplay)." << endl << "Version " VERSION << " - Copyright (C) 2006 - 2010 by René Rebe" << std::endl << "Usage:" << endl; arglist.Usage (cerr); return 1; } Viewer* viewer= createViewer(arglist.Residuals()); int ret = viewer->Run ( #if EVASGL == 1 arg_gl.Get() #else false #endif ); delete viewer; viewer = 0; return ret; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/edisplay/Makefile�����������������������������������������������������������������0000644�0000764�0000764�00000001020�11457064256�015636� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� include build/top.make BINARY = edisplay BINARY_EXT = $(X_EXEEXT) CPPFLAGS += -I . -I lib -I gfx CPPFLAGS += $(shell pkg-config evas --atleast-version 0.9.9.050 && echo -D WITHEVAS_X11_CONNECTION) CPPFLAGS += $(shell pkg-config evas --atleast-version 0.9.9.49898 && echo -D WITHEVAS_X11_SCREEN) DEPS += $(X_OUTARCH)/gfx/X11Helper$(X_OBJEXT) $(X_OUTARCH)/gfx/EvasHelper$(X_OBJEXT) $(X_OUTARCH)/utility/Timer$(X_OBJEXT) $(X_OUTARCH)/utility/ArgumentList$(X_OBJEXT) $(lib_BINARY) $(codecs_BINARY) include build/bottom.make ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/edisplay/edisplay.hh��������������������������������������������������������������0000644�0000764�0000764�00000004713�11161456720�016336� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * The ExactImage library's displayy compatible command line frontend. * Copyright (C) 2006 - 2009 René Rebe * * 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. */ #ifndef EDISPLAY_HH #define EDISPLAY_HH #include "Image.hh" // display stuff #include "X11Helper.hh" #include "EvasHelper.hh" #include "Timer.hh" #include <string> #include <vector> class Viewer { public: Viewer(const std::vector<std::string>& _images) : images(_images), evas_data(0), zoom(100), evas_image(0) { it = images.begin(); image = new Image; } virtual ~Viewer() { if (evas_data) { delete (evas_data); evas_data = 0; } delete (image); image = 0; } bool Load (); bool Next (); bool Previous (); int Run (bool opengl = false); protected: void ImageToEvas (); EvasImage* ImageToEvas (Image*, EvasImage* = 0); void Zoom (double factor); void Move (int _x, int _y); int Window2ImageX (int x); int Window2ImageY (int y); void UpdateOSD (const std::string& str1, const std::string& str2); void AlphaOSD (int a); void TickOSD (); void SetOSDZoom (); virtual void ImageLoaded () {}; virtual void ImageClicked (unsigned int x, unsigned int y, int button) {}; virtual bool ImageKey(KeySym keysym) { return false; }; private: const std::vector<std::string>& images; std::vector<std::string>::const_iterator it; // Image protected: Image* image; private: uint8_t* evas_data; // on screen display EvasRectangle* evas_osd_rect; EvasText* evas_osd_text1; EvasText* evas_osd_text2; Utility::Timer osd_timer; int zoom; int channel; // X11 stuff Display* dpy; int scr; Visual* visual; Window win; int depth; // evas EvasCanvas* evas; EvasImage* evas_image; EvasImage* evas_bgr_image; protected: // real canvas payload std::vector<EvasImage*> evas_content; }; #endif // EDISPLAY_HH �����������������������������������������������������exact-image-0.9.1/gfx/������������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664356�013170� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/gfx/EvasHelper.hh�����������������������������������������������������������������0000644�0000764�0000764�00000017266�10743722054�015544� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: gfx/include/EvasHelper.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2008 * Valentin Ziegler and Renebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef __EVASHELPER__ #define __EVASHELPER__ #include <Evas.h> #include <inttypes.h> #include <string> class EvasCanvas { public: EvasCanvas (); ~EvasCanvas (); bool OutputMethod (const std::string& method); Evas_Engine_Info* EngineInfo (); void EngineInfo (Evas_Engine_Info* info) { evas_engine_info_set (ob, info); }; void OutputSize (int w, int h) { evas_output_size_set (ob, w, h); } int OutputWidth () { int w, h; evas_output_size_get (ob, &w, &h); return w; } int OutputHeight () { int w, h; evas_output_size_get (ob, &w, &h); return h; } void OutputViewport (int x, int y, int w, int h) { evas_output_viewport_set (ob, x, y, w, h); } void ImageCacheFlush () { evas_image_cache_flush (ob); } void ImageCacheReload () { evas_image_cache_reload (ob); } void ImageCache (int size = 1024) { evas_image_cache_set (ob, size); } void FontPathClear () { evas_font_path_clear (ob); } void FontPathAppend (const std::string& path) { evas_font_path_append (ob, path.c_str () ); } void FontPathPrepend (const std::string& path) { evas_font_path_prepend (ob, path.c_str () ); } void FontCacheFlush () { evas_font_cache_flush (ob); } void FontCache (int size = 1024) { evas_font_cache_set (ob, size); } // -- Re-(*)draw handling -- void DamageRectangleAdd (int x, int y, int w, int h) { evas_damage_rectangle_add (ob, x, y, w, h); } void ObscuredRectangleAdd (int x, int y, int w, int h) { evas_obscured_rectangle_add (ob, x, y, w, h); } void Render () { evas_render (ob); } // -- Event stuff -- /* void EventFeedMouseDown (int b, Evas_Button_Flags flags) { evas_event_feed_mouse_down (ob, b, flags, NULL); }; void EventFeedMouseUp (int b, Evas_Button_Flags flags) { evas_event_feed_mouse_up (ob, b, flags, NULL); }; void EventFeedMouseMove (int x, int y) { evas_event_feed_mouse_move (ob, x, y, NULL); }; void EventFeedmouseIn () { evas_event_feed_mouse_in (ob, NULL); }; */ /* void EventFeedKeyDown (const char *keyname, const char *keysymbol, const char *key_compose) { evas_event_feed_key_down (ob, keyname, keysymbol, key_compose, NULL, NULL); }; void EventFeedKeyUp (const char *keyname, const char *keysymbol, const char *key_compose) { evas_event_feed_key_up (ob, keyname, keysymbol, key_compose, NULL, NULL); }; */ Evas* c_obj () { return ob; } private: Evas* ob; }; class EvasBase { public: void Move (Evas_Coord x, Evas_Coord y) { evas_object_move (ob, x, y); } void Resize (Evas_Coord w, Evas_Coord h) { evas_object_resize (ob, w, h); } Evas_Coord X () { Evas_Coord x, y, w, h; evas_object_geometry_get (ob, &x, &y, &w, &h); return x; } Evas_Coord Y () { Evas_Coord x, y, w, h; evas_object_geometry_get (ob, &x, &y, &w, &h); return y; } Evas_Coord Width () { Evas_Coord x, y, w, h; evas_object_geometry_get (ob, &x, &y, &w, &h); return w; } Evas_Coord Height () { Evas_Coord x, y, w, h; evas_object_geometry_get (ob, &x, &y, &w, &h); return h; } void Color (int r, int g, int b, int a) { #ifdef WITHEVAS_COLOR_PREMUL evas_color_argb_premul (a, &r, &g, &b); #endif evas_object_color_set (ob, r, g, b, a); } void GetColor (int* r, int* g, int* b, int* a) { evas_object_color_get (ob, r, g, b, a); } void Layer (int l) { evas_object_layer_set (ob, l); } int Layer () { return evas_object_layer_get (ob); } void Raise () { evas_object_raise (ob); } void Lower () { evas_object_lower (ob); } void Show () { evas_object_show (ob); } void Hide () { evas_object_hide (ob); } bool IsVisible () { return evas_object_visible_get (ob); } Evas_Object* c_obj () { return ob; } protected: EvasBase (bool i_owner); virtual ~EvasBase (); Evas_Object* ob; bool owner; }; class EvasImage : public EvasBase { public: EvasImage (EvasCanvas& evas); EvasImage (Evas_Object* i_ob); virtual ~EvasImage (); void ImageSize (int w, int h) { evas_object_image_size_set (ob, w, h); } int ImageWidth () { int w, h; evas_object_image_size_get (ob, &w, &h); return w; } int ImageHeight () { int w, h; evas_object_image_size_get (ob, &w, &h); return h; } void Alpha (bool alpha) { evas_object_image_alpha_set (ob, alpha); } bool IsAlpha () { return evas_object_image_alpha_get (ob); } void ImageFill (Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h) { evas_object_image_fill_set (ob, x, y, w, h); } Evas_Coord ImageFillX () { Evas_Coord x, y, w, h; evas_object_image_fill_get (ob, &x, &y, &w, &h); return w; } Evas_Coord ImageFillY () { Evas_Coord x, y, w, h; evas_object_image_fill_get (ob, &x, &y, &w, &h); return h; } Evas_Coord ImageFillWidth () { Evas_Coord x, y, w, h; evas_object_image_fill_get (ob, &x, &y, &w, &h); return w; } Evas_Coord ImageFillHeight () { Evas_Coord x, y, w, h; evas_object_image_fill_get (ob, &x, &y, &w, &h); return h; } void SmoothScale (bool smooth) { evas_object_image_smooth_scale_set (ob, smooth); } bool SmoothScale () { return evas_object_image_smooth_scale_get (ob); } unsigned char* Data () { return (unsigned char*) evas_object_image_data_get (ob, 1); } void DataUpdateAdd (int x, int y, int w, int h) { evas_object_image_data_update_add (ob,x,y,w,h); } void SetData (unsigned char* data) { #ifdef WITHEVAS_COLOR_PREMUL if (IsAlpha() && data) evas_data_argb_premul ((unsigned int*)data, ImageWidth() * ImageHeight()); #endif evas_object_image_data_set (ob, data); } // our helper bool SmartLoad (const std::string& fname); void ApplyAlpha (uint8_t alpha); protected: int cached_w, cached_h; }; class EvasText : public EvasBase { public: EvasText (EvasCanvas& evas); EvasText (Evas_Object* i_ob); virtual ~EvasText (); void Font (const std::string& font, int height = 10) { evas_object_text_font_set (ob, font.c_str (), height); } void Text (const std::string& text) { evas_object_text_text_set (ob, text.c_str () ); } std::string GetText () { return std::string (evas_object_text_text_get (ob)); } // TODO: set height and font family ... protected: }; class EvasRectangle : public EvasBase { public: EvasRectangle (EvasCanvas& evas); EvasRectangle (Evas_Object* i_ob); virtual ~EvasRectangle (); protected: }; #endif // __EVASHELPER__ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/gfx/Makefile����������������������������������������������������������������������0000644�0000764�0000764�00000002374�10643157505�014621� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� # --- GSMP-COPYRIGHT-NOTE-BEGIN --- # # This copyright note is auto-generated by ./scripts/Create-CopyPatch. # Please add additional copyright information _after_ the line containing # the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by # the ./scripts/Create-CopyPatch script. Do not edit this copyright text! # # GSMP: gfx/src/Makefile # General Sound Manipulation Program is Copyright (C) 2000 - 2004 # Valentin Ziegler and René Rebe # # 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. # # --- GSMP-COPYRIGHT-NOTE-END --- include build/top.make BINARY = libgsmpgfx BINARY_EXT = $(X_LIBEXT) CPPFLAGS += $(X11INCS) $(EVASINCS) -Igfx $(shell pkg-config evas --atleast-version 0.9.9.027 && echo -D WITHEVAS_COLOR_PREMUL) LDFLAGS += $(X11LIBS) -lXrender $(EVASLIBS) include build/bottom.make ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/gfx/X11Helper.cc������������������������������������������������������������������0000644�0000764�0000764�00000023711�11000236032�015154� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: gfx/src/X11Helper.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* * The window capturing was taken from the xscreensaver package - and * quite modified. The WindowStayOnTop handling was taken from the * xosd package. -ReneR */ #include <string.h> #include <stdlib.h> #include <iostream> #include "X11Helper.hh" #include <X11/extensions/Xrender.h> Visual* find_argb_visual (Display* dpy, int scr) { XVisualInfo *xvi; XVisualInfo templ; int nvi; int i; XRenderPictFormat *format; Visual *visual; templ.screen = scr; templ.depth = 32; templ.c_class = TrueColor; xvi = XGetVisualInfo (dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nvi); if (!xvi) return 0; visual = 0; for (i = 0; i < nvi; i++) { format = XRenderFindVisualFormat (dpy, xvi[i].visual); if (format->type == PictTypeDirect && format->direct.alphaMask) { visual = xvi[i].visual; break; } } XFree (xvi); return visual; } int X11Window::Width (Display* dpy, Window window) { if (window == 0) window = DefaultRootWindow(dpy); XWindowAttributes xgwa; XGetWindowAttributes (dpy, window, &xgwa); return xgwa.width; } int X11Window::Height (Display* dpy, Window window) { if (window == 0) window = DefaultRootWindow(dpy); XWindowAttributes xgwa; XGetWindowAttributes (dpy, window, &xgwa); return xgwa.height; } bool X11Window::Move (Display* dpy, Window window, int x, int y) { XWindowChanges changes; changes.x = x; changes.y = y; XConfigureWindow (dpy, window, CWX | CWY, &changes); return true; } bool X11Window::Resize (Display* dpy, Window window, int w, int h) { XWindowChanges changes; changes.width = w; changes.height = h; XConfigureWindow (dpy, window, CWWidth | CWHeight, &changes); return true; } int X11Window::Depth (Display* dpy, Window window) { if (window == 0) window = DefaultRootWindow(dpy); XWindowAttributes xgwa; XGetWindowAttributes (dpy, window, &xgwa); return xgwa.depth; } Visual* X11Window::ColorVisual (Display* dpy, Window window) { if (window == 0) window = DefaultRootWindow(dpy); XWindowAttributes xgwa; XGetWindowAttributes (dpy, window, &xgwa); return xgwa.visual; } Evas_Object* X11Window::CaptureIntoEvasImage (Evas* evas, Display* dpy, Window window, int x, int y, int w, int h) { // create the new Evas object ;-) Evas_Object* ob = evas_object_image_add(evas); evas_object_resize (ob, w, h); CaptureIntoEvasImage (ob, dpy, window, x, y, w, h); return ob; } void X11Window::CaptureIntoEvasImage (Evas_Object* ob, Display* dpy, Window window, int x, int y, int w, int h) { if (window == 0) window = DefaultRootWindow(dpy); XColor *colors = 0; // places content of a rectangle from drawable into an image XImage* ximage = XGetImage (dpy, window, x, y, w, h, ~0L, ZPixmap); // only needed to get valid r,g,b masks - I do not why ximage // does ont include those ... XImage* ximage2 = XCreateImage (dpy, X11Window::ColorVisual (dpy, window), 32, ZPixmap, 0, 0, w, h, 32, 0); // resize the Evas image to the proper size ... evas_object_image_size_set (ob, w, h); // !must be first! evas_object_image_fill_set(ob, 0, 0, w, h); // !and don't move me, too! uint8_t* data = (uint8_t*) evas_object_image_data_get (ob, 1); // Get Colormap Screen *dscreen = DefaultScreenOfDisplay (dpy); Visual *dvisual = DefaultVisualOfScreen (dscreen); if (X11Window::visual_class (dscreen, dvisual) == PseudoColor || X11Window::visual_class (dscreen, dvisual) == GrayScale) { Colormap cmap = DefaultColormapOfScreen(dscreen); int ncolors = X11Window::visual_cells (dscreen, dvisual); int i; std::cout << "ncolors: " << ncolors << std::endl; colors = (XColor*) calloc (sizeof (*colors), ncolors+1); for (i = 0; i < ncolors; i++) colors[i].pixel = i; XQueryColors (dpy, cmap, colors, ncolors); } // Translate the server-ordered image to a client-ordered image. uint32_t srmsk = ximage2->red_mask; uint32_t sgmsk = ximage2->green_mask; uint32_t sbmsk = ximage2->blue_mask; if (!srmsk && !sgmsk && !sbmsk) { srmsk = 0xf800; sgmsk = 0x7e0; sbmsk = 0x1f; } int8_t srpos = first_bit_set (srmsk); int8_t sgpos = first_bit_set (sgmsk); int8_t sbpos = first_bit_set (sbmsk); int8_t srscl = 8 - bits_set (srmsk); int8_t sgscl = 8 - bits_set (sgmsk); int8_t sbscl = 8 - bits_set (sbmsk); uint32_t* data_ptr = (uint32_t*) data; for (int y = 0; y < h; ++y) for (int x = 0; x < w; ++x) { uint32_t sp = XGetPixel (ximage, x, y); uint8_t sr, sg, sb; if (colors) { sr = colors[sp].red; sg = colors[sp].green; sb = colors[sp].blue; } else { sr = ((sp & srmsk) >> srpos) << srscl; sg = ((sp & sgmsk) >> sgpos) << sgscl; sb = ((sp & sbmsk) >> sbpos) << sbscl; } *data_ptr++ = 0xff << 24 | sr << 16 | sg << 8 | sb; } evas_object_image_data_update_add (ob, 0, 0, w, h); // !we got updated! evas_object_image_data_set (ob, data); // !and set the data! (?) if (colors) { free (colors); colors = 0; } XDestroyImage (ximage2); XDestroyImage (ximage); } int X11Window::screen_number (Screen *screen) { Display *dpy = DisplayOfScreen (screen); int i; for (i = 0; i < ScreenCount (dpy); i++) if (ScreenOfDisplay (dpy, i) == screen) return i; std::cerr << "Error w/ ScreenOfDisplay" << std::endl; return 0; } int X11Window::visual_class (Screen *screen, Visual *visual) { Display *dpy = DisplayOfScreen (screen); XVisualInfo vi_in, *vi_out; int out_count, c; vi_in.screen = screen_number (screen); vi_in.visualid = XVisualIDFromVisual (visual); vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask, &vi_in, &out_count); if (! vi_out) std::cerr << "Error w/ XGetVisualInfo" << std::endl; c = vi_out [0].c_class; // hail to C ... XFree ((char *) vi_out); return c; } int X11Window::visual_cells (Screen *screen, Visual *visual) { Display *dpy = DisplayOfScreen (screen); XVisualInfo vi_in, *vi_out; int out_count, c; vi_in.screen = screen_number (screen); vi_in.visualid = XVisualIDFromVisual (visual); vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask, &vi_in, &out_count); if (! vi_out) abort (); c = vi_out [0].colormap_size; XFree ((char *) vi_out); return c; } // WindowStayOnTop code void X11Window::StayOnTop (Display* dpy, Window win) { Window root = DefaultRootWindow(dpy); if (!gnome_stay_on_top (dpy, root, win)) netwm_stay_on_top (dpy, root, win); XRaiseWindow(dpy, win); } bool X11Window::gnome_stay_on_top (Display* dpy, Window root, Window win) { Atom type; int format; unsigned long nitems, bytesafter; unsigned char *args = NULL; static Atom gnome; static Atom gnome_layer; const int WIN_LAYER_ONTOP = 6; XClientMessageEvent xev; gnome = XInternAtom(dpy, "_WIN_SUPPORTING_WM_CHECK", False); gnome_layer = XInternAtom(dpy, "_WIN_LAYER", False); // gnome compliant if (Success != XGetWindowProperty (dpy, root, gnome, 0, (65536 / sizeof(long)), False, AnyPropertyType, &type, &format, &nitems, &bytesafter, &args) || nitems == 0) { std::cerr << "Error tring to stay on top the Gnome way." << std::endl; return false; } memset(&xev, 0, sizeof(xev)); xev.type = ClientMessage; xev.window = win; xev.message_type = gnome_layer; xev.format = 32; xev.data.l[0] = WIN_LAYER_ONTOP; XSendEvent(dpy, root, False, SubstructureNotifyMask, (XEvent *)&xev); XFree(args); return true; } bool X11Window::netwm_stay_on_top (Display* dpy, Window root, Window win) { Atom type; int format; unsigned long nitems, bytesafter; unsigned char *args = NULL; const int _NET_WM_STATE_ADD = 1; // add/set property static Atom net_wm; static Atom net_wm_state; static Atom net_wm_top; XEvent e; net_wm = XInternAtom(dpy, "_NET_SUPPORTED", False); net_wm_state = XInternAtom(dpy, "_NET_WM_STATE", False); net_wm_top = XInternAtom(dpy, "_NET_WM_STATE_STAYS_ON_TOP", False); // netwm compliant if (Success != XGetWindowProperty (dpy, root, net_wm, 0, (65536 / sizeof(long)), False, AnyPropertyType, &type, &format, &nitems, &bytesafter, &args) && nitems > 0) { std::cerr << "Error tring to stay on top the Netwm way." << std::endl; return false; } e.xclient.type = ClientMessage; e.xclient.message_type = net_wm_state; e.xclient.display = dpy; e.xclient.window = win; e.xclient.format = 32; e.xclient.data.l[0] = _NET_WM_STATE_ADD; e.xclient.data.l[1] = net_wm_top; e.xclient.data.l[2] = 0l; e.xclient.data.l[3] = 0l; e.xclient.data.l[4] = 0l; XSendEvent(dpy, root, False, SubstructureRedirectMask, &e); XFree(args); return true; } �������������������������������������������������������exact-image-0.9.1/gfx/X11Helper.hh������������������������������������������������������������������0000644�0000764�0000764�00000005243�10402357275�015210� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: gfx/include/X11Helper.hh * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #ifndef __X11HELPER__ #define __X11HELPER__ #include <X11/Xlib.h> #include <X11/Xutil.h> #include "Evas.h" #include "Evas_Engine_Software_X11.h" // int types #include <inttypes.h> template <class T> int first_bit_set (T v) { unsigned int i; for (i = 0; i < sizeof (T) * 8; ++i) { if (v & (1L << i)) break; } return i; } template <class T> int bits_set (T v) { unsigned int i, c = 0; for (i = 0; i < sizeof(T) * 8; ++i) { if (v & (1L << i)) ++c; } return c; } Visual* find_argb_visual (Display* dpy, int scr); // Based uppon xscreensavers grab-ximage.c class X11Window { public: static int Width (Display* dpy, Window window); static int Height (Display* dpy, Window window); static bool Move (Display* dpy, Window window, int x, int y); static bool Resize (Display* dpy, Window window, int w, int h); static int Depth (Display* dpy, Window window); static Visual* ColorVisual (Display* dpy, Window window); static Evas_Object* CaptureIntoEvasImage (Evas* evas, Display* dpy, Window window, int x, int y, int w, int h); static void CaptureIntoEvasImage (Evas_Object* ob, Display* dpy, Window window, int x, int y, int w, int h); static void StayOnTop (Display* dpy, Window win); private: static int screen_number (Screen* screen); static int visual_class (Screen* screen, Visual* visual); static int visual_cells (Screen* screen, Visual* visual); // on top stuff static bool gnome_stay_on_top (Display* dpy, Window root, Window win); static bool netwm_stay_on_top(Display* dpy, Window root, Window win); }; #endif // __X11HELPER__ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/gfx/EvasHelper.cc�����������������������������������������������������������������0000644�0000764�0000764�00000007206�11001434405�015507� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: gfx/src/EvasHelper.cc * General Sound Manipulation Program is Copyright (C) 2000 - 2007 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ #include <iostream> #include "EvasHelper.hh" EvasCanvas::EvasCanvas () { evas_init (); ob = evas_new (); } EvasCanvas::~EvasCanvas () { evas_free (ob); } bool EvasCanvas::OutputMethod (const std::string& method) { int renderer = evas_render_method_lookup (method.c_str () ); if (renderer > 0) { evas_output_method_set (ob, renderer); return true; } std::cout << "Error: failed to set output method!" << std::endl; return false; } Evas_Engine_Info* EvasCanvas::EngineInfo () { Evas_Engine_Info* info = evas_engine_info_get (ob); if (!info) std::cout << "Warning: Obtained Evas engine info is INVALID!" << std::endl; return info; }; // --- EvasBase::EvasBase (bool i_owner) : owner (i_owner) { } EvasBase::~EvasBase () { if (owner) { evas_object_del (ob); } } // --- EvasImage::EvasImage (EvasCanvas& evas) : EvasBase (true) { ob = evas_object_image_add (evas.c_obj () ); } EvasImage::EvasImage (Evas_Object* i_ob) : EvasBase (false) { ob = i_ob; } EvasImage::~EvasImage () { } bool EvasImage::SmartLoad (const std::string& fname) { evas_object_image_file_set(ob, fname.c_str (), NULL); int err = evas_object_image_load_error_get (ob); if (err) { std::cout << "Error: loading image: " << err << std::endl; return false; } evas_object_image_size_get (ob, &cached_w, &cached_h); // Yeah - don't ask why Evas doesn't do this ... ?!? evas_object_image_fill_set (ob, 0, 0, cached_w, cached_h); evas_object_resize (ob, cached_w, cached_h); return true; } void EvasImage::ApplyAlpha (uint8_t alpha) { int iw ,ih; evas_object_image_size_get (ob, &iw, &ih); evas_object_image_fill_set (ob, 0, 0, iw, ih); uint8_t* data = (uint8_t*) evas_object_image_data_get (ob, 1); uint8_t* data_ptr = data; uint8_t* data_end = data + (iw * ih * 4); while (data_ptr < data_end) { *data_ptr = (*data_ptr * alpha) >> 8; data_ptr++; *data_ptr = (*data_ptr * alpha) >> 8; data_ptr++; *data_ptr = (*data_ptr * alpha) >> 8; data_ptr++; *data_ptr = (*data_ptr * alpha) >> 8; data_ptr++; } evas_object_image_data_update_add (ob, 0, 0, iw, ih); evas_object_image_data_set (ob, data); } // --- EvasText::EvasText (EvasCanvas& evas) : EvasBase (true) { ob = evas_object_text_add (evas.c_obj () ); } EvasText::EvasText (Evas_Object* i_ob) : EvasBase (false) { ob = i_ob; } EvasText::~EvasText () { } // ... EvasRectangle::EvasRectangle (EvasCanvas& evas) : EvasBase (true) { ob = evas_object_rectangle_add (evas.c_obj () ); } EvasRectangle::EvasRectangle (Evas_Object* i_ob) : EvasBase (false) { ob = i_ob; } EvasRectangle::~EvasRectangle () { } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/������������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664267�013153� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/riemersma.h�������������������������������������������������������������������0000644�0000764�0000764�00000001565�12156365130�015275� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * A Balanced Dithering Technique * Copyright (C) 2006 - 2013 René Rebe, ExactCOD GmbH Germany * * 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. * * Based uppon: * C/C++ Users Journal, December 1998: Thiadmer Riemersma */ #include "Image.hh" void Riemersma(Image& image, int shades); �������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/Matrix.cc���������������������������������������������������������������������0000644�0000764�0000764�00000017342�12453270555�014721� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Convolution Matrix. * Copyright (C) 2006 - 2015 René Rebe, ExactCODE GmbH Germany * Copyright (C) 2007 Valentin Ziegler, ExactCODE GmbH Germany * Copyright (C) 2007 Susanne Klaus, ExactCODE GmbH Germany * Copyright (C) 2006 Archivista * * 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 "Matrix.hh" #include "ImageIterator2.hh" #ifdef _MSC_VER #include <vector> #endif template <typename T> struct convolution_matrix_template { void operator() (Image& image, const matrix_type* matrix, int xw, int yw, matrix_type divisor) { Image orig_image; orig_image.copyTransferOwnership (image); image.resize (image.w, image.h); T dst_it (image); T src_it (orig_image); const int xr = xw / 2; const int yr = yw / 2; // top & bottom for (int y = 0; y < image.h; ++y) { for (int x = 0; x < image.w;) { dst_it.at (x, y); typename T::accu a; const matrix_type* _matrix = matrix; for (int ym = 0; ym < yw; ++ym) { int image_y = y-yr+ym; if (image_y < 0) image_y = 0 - image_y; else if (image_y >= image.h) image_y = image.h - (image_y - image.h) - 1; for (int xm = 0; xm < xw; ++xm) { int image_x = x-xr+xm; if (image_x < 0) image_x = 0 - image_x; else if (image_x >= image.w) image_x = image.w - (image_x - image.w) - 1; a += *(src_it.at(image_x, image_y)) * *_matrix; ++src_it; ++_matrix; } } a /= divisor; a.saturate (); dst_it.set (a); ++dst_it; ++x; if (x == xr && y >= yr && y < image.h - yr) x = image.w - xr; } } //image area without border for (int y = yr; y < image.h - yr; ++y) { dst_it.at (xr, y); for (int x = xr; x < image.w - xr; ++x) { typename T::accu a; const matrix_type* _matrix = matrix; for (int ym = 0; ym < yw; ++ym) { src_it.at (x - xr, y - yr + ym); for (int xm = 0; xm < xw; ++xm) { a += *src_it * *_matrix; ++src_it; ++_matrix; } } a /= divisor; a.saturate(); dst_it.set (a); ++dst_it; } } } }; void convolution_matrix (Image& image, const matrix_type* m, int xw, int yw, matrix_type divisor) { codegen<convolution_matrix_template> (image, m, xw, yw, divisor); } template <typename T> struct decomposable_sym_convolution_matrix_template { void operator() (Image& image, const matrix_type* h_matrix, const matrix_type* v_matrix, int xw, int yw, matrix_type src_add) { T img_it (image); typename T::accu a; const int width = image.width(); const int height = image.height(); const int spp = image.samplesPerPixel(); const int stride = width * spp; // our stride #ifndef _MSC_VER matrix_type line_data[std::max(stride, height)]; matrix_type tmp_data[stride * (1 + 2 * yw)]; #else std::vector<matrix_type> line_data(std::max(stride, height)); std::vector<matrix_type> tmp_data(stride * (1 + 2 * yw)); #endif matrix_type* tmp_ptr; // main transform loop for (int y = 0; y < height + yw; ++y) { // horizontal transform if (y < height) { img_it.at(0, y); tmp_ptr = &tmp_data[(y % (1 + 2 * yw)) * stride]; matrix_type val = h_matrix[0]; for (int x = 0, _ = 0; x < width; ++x, ++img_it) { a = *img_it; for (int i = 0; i < spp; ++i, ++_) { line_data[_] = a.v[i]; tmp_ptr[_] = val * a.v[i]; } } for (int i = 1; i <= xw; ++i) { int pi = spp * i; int dstart = pi; int dend = stride - pi; int end = stride; int l = pi; int r = 0; val = h_matrix[i]; // left border for (int x = 0; x < dstart; x++, l++) tmp_ptr[x] += val * line_data[l]; // middle for (int x = dstart; x < dend; x++, l++, r++) tmp_ptr[x] += val * (line_data[l] + line_data[r]); // right border for (int x = dend; x < end; x++, r++) tmp_ptr[x] += val * line_data[r]; } } // now do the vertical transform of a block of lines and write back to src const int dsty = y - yw; if (dsty >= 0) { img_it.at(0, dsty); matrix_type val = (matrix_type)src_add; if (val != (matrix_type)0) { for (int x = 0, _ = 0; x < width; ++x, ++img_it) { a = *img_it; for (int i = 0; i < spp; ++i, ++_) { line_data[_] = val * a.v[i]; } } } else { for (int x = 0; x < stride; ++x) line_data[x] = 0; } for (int i = 0; i <= yw; i++) { val = v_matrix[i]; if (i == 0 || (dsty - i < 0) || (dsty + i >= height) ) { int tmpy = (dsty - i < 0) ? dsty + i : dsty - i; tmp_ptr = &tmp_data[(tmpy % (1 + 2 * yw)) * stride]; for (int x = 0; x < stride; ++x) line_data[x] += val * tmp_ptr[x]; } else { tmp_ptr = &tmp_data[((dsty - i) % (1 + 2 * yw)) * stride]; matrix_type* tmp_ptr2 = &tmp_data[((dsty + i) % (1 + 2 * yw)) * stride]; for (int x = 0; x < stride; ++x) line_data[x] += val * (tmp_ptr[x] + tmp_ptr2[x]); } } img_it.at(0, dsty); for (int x = 0, _ = 0; x < width; ++x, ++img_it) { for (int i = 0; i < spp; ++i, ++_) a.v[i] = line_data[_]; a.saturate(); img_it.set(a); } } } image.setRawData(); // invalidate as altered } }; // h_matrix contains entrys m[0]...m[xw]. It is assumed, that m[-i]=m[i]. Same for v_matrix. void decomposable_sym_convolution_matrix (Image& image, const matrix_type* h_matrix, const matrix_type* v_matrix, int xw, int yw, matrix_type src_add) { codegen<decomposable_sym_convolution_matrix_template> (image, h_matrix, v_matrix, xw, yw, src_add); } void decomposable_convolution_matrix (Image& image, const matrix_type* h_matrix, const matrix_type* v_matrix, int xw, int yw, matrix_type src_add) { uint8_t* data = image.getRawData(); matrix_type* tmp_data = (matrix_type*) malloc (image.w * image.h * sizeof(matrix_type)); const int xr = xw / 2; const int yr = yw / 2; const int xmax = image.w - ((xw+1)/2); const int ymax = image.h - ((yw+1)/2); uint8_t* src_ptr = data; matrix_type* tmp_ptr = tmp_data; // valentin 2007-10-01: i think horizontal and vertical are accidentally switched in those comments ??? // transform the vertical convolution strip with h_matrix, leaving out the left/right borders for (int y = 0; y < image.h; ++y) { src_ptr = &data[(y * image.w) - xr]; tmp_ptr = &tmp_data[y * image.w]; for (int x = xr; x < xmax; ++x) { tmp_ptr[x] = .0; for (int dx = 0; dx < xw; ++dx) tmp_ptr[x] += ((matrix_type)src_ptr[x + dx]) * h_matrix[dx]; } } // transform the horizontal convolution strip with v_matrix, leaving out all borders for (int x = xr; x < xmax; ++x) { src_ptr = &data[x + (yr * image.w)]; tmp_ptr = &tmp_data[x]; int offs = 0; for (int y = yr; y < ymax; ++y) { int doffs = offs; matrix_type sum = src_add * ((matrix_type)src_ptr[offs]); for (int dy = 0; dy < yw; ++dy) { sum += tmp_ptr[doffs] * v_matrix[dy]; doffs += image.w; } uint8_t z = (uint8_t)(sum > 255 ? 255 : sum < 0 ? 0 : sum); src_ptr[offs] = z; offs += image.w; } } image.setRawData(); // invalidate as altered free (tmp_data); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/riemersma.cc������������������������������������������������������������������0000644�0000764�0000764�00000011532�12160562430�015423� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * A Balanced Dithering Technique * Copyright (C) 2006 - 2013 René Rebe, ExactCOD GmbH Germany * * 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. * * Based uppon: * C/C++ Users Journal, December 1998: Thiadmer Riemersma */ #include "riemersma.h" #include <math.h> #include <string.h> // substitutes "log2(n)", which is apparently not available on BSD, OS X static inline double priv_log2(double n) { return log(n) / log(2); } enum direction_t { NONE, UP, LEFT, DOWN, RIGHT, }; // variables needed for the Riemersma dither algorithm static int cur_x = 0, cur_y = 0; static int img_width = 0, img_height = 0; static int img_bytes = 0; static float img_factor; static uint8_t* img_ptr; #define SIZE 16 // queue size: number of pixels remembered #define MAX 16 // relative weight of youngest pixel in the // queue, versus the oldest pixel static int weights[SIZE]; // weights for the errors of recent pixels static void init_weights(int a[], int size, int max) { double m = exp(log(max) / (size-1)); double v; int i; for (i = 0, v = 1.0; i < size; i++) { a[i] = (int)(v + 0.5); // store rounded value v *= m; // next value } } static void dither_pixel(uint8_t *pixel) { static int error[SIZE]; // queue with error values of recent pixels int err = 0L; for (int i = 0; i < SIZE; i++) err += error[i] * weights[i]; float pvalue = *pixel + err / MAX; pvalue = floor (pvalue * img_factor + 0.5) / img_factor; if (pvalue > 255) pvalue = 255; else if (pvalue < 0) pvalue = 0; memmove(error, error + 1, (SIZE - 1) * sizeof error[0]); // shift queue error[SIZE - 1] = *pixel - (uint8_t)(pvalue + 0.5); *pixel = (uint8_t)(pvalue + 0.5); } static void move(direction_t direction) { // dither the current pixel if (cur_x >= 0 && cur_x < img_width && cur_y >= 0 && cur_y < img_height) dither_pixel(img_ptr); // move to the next pixel switch (direction) { case LEFT: --cur_x; img_ptr -= img_bytes; break; case RIGHT: ++cur_x; img_ptr += img_bytes; break; case UP: --cur_y; img_ptr -= img_width * img_bytes; break; case DOWN: ++cur_y; img_ptr += img_width * img_bytes; break; } } void hilbert_level(int level, direction_t direction) { if (level == 1) { switch (direction) { case LEFT: move(RIGHT); move(DOWN); move(LEFT); break; case RIGHT: move(LEFT); move(UP); move(RIGHT); break; case UP: move(DOWN); move(RIGHT); move(UP); break; case DOWN: move(UP); move(LEFT); move(DOWN); break; } } else { switch (direction) { case LEFT: hilbert_level(level - 1, UP); move(RIGHT); hilbert_level(level - 1, LEFT); move(DOWN); hilbert_level(level - 1, LEFT); move(LEFT); hilbert_level(level - 1, DOWN); break; case RIGHT: hilbert_level(level - 1, DOWN); move(LEFT); hilbert_level(level - 1, RIGHT); move(UP); hilbert_level(level - 1, RIGHT); move(RIGHT); hilbert_level(level - 1, UP); break; case UP: hilbert_level(level - 1, LEFT); move(DOWN); hilbert_level(level - 1, UP); move(RIGHT); hilbert_level(level - 1, UP); move(UP); hilbert_level(level - 1, RIGHT); break; case DOWN: hilbert_level(level - 1, RIGHT); move(UP); hilbert_level(level - 1, DOWN); move(LEFT); hilbert_level(level - 1, DOWN); move(DOWN); hilbert_level(level - 1, LEFT); break; } } } void Riemersma(Image& image, int shades) { uint8_t* raw = image.getRawData(); img_width = image.w; img_height = image.h; img_bytes = image.spp; // determine the required order of the Hilbert curve const int size = img_width > img_height ? img_width : img_height; for (int ch = 0; ch < img_bytes; ++ch) { int level = (int) priv_log2 (size); if ((1L << level) < size) ++level; init_weights (weights, SIZE,MAX); img_factor = (-1.0 + shades) / 255.0; cur_x = 0; cur_y = 0; img_ptr = raw + ch; if (level > 0) hilbert_level(level, UP); move(NONE); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/canvas.cc���������������������������������������������������������������������0000644�0000764�0000764�00000002477�11556323200�014720� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2009-2011 René Rebe, ExactCODE GmbH Germany. * * 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 "canvas.hh" #include "Colorspace.hh" #include <string.h> void append (Image& image, Image& other) { // TODO: currently we support images with the same with if (image.w != other.w) { std::cerr << "image append: different image width unimplemented" << std::endl; return; } // must be in the same colorspace colorspace_by_name(other, colorspace_name(image)); // resize height const unsigned int old_height = image.h; image.resize(image.w, image.h + other.h); // copy raw content memcpy(image.getRawData() + image.stride() * old_height, other.getRawData(), other.stride() * other.h); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/crop.cc�����������������������������������������������������������������������0000644�0000764�0000764�00000007414�12467367544�014431� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Canvas cropping. * Copyright (C) 2006 - 2015 René Rebe, ExactCODE * * 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 <string.h> // memmove #include <iostream> #include <algorithm> #ifndef _MSC_VER #include <vector> #endif #include "Image.hh" #include "Codecs.hh" #include "Colorspace.hh" #include "crop.hh" void crop (Image& image, int x, int y, unsigned int w, unsigned int h) { // limit to valid boundaries if (x < 0) { w += x; x = 0; }; if (y < 0) { h += y; y = 0; }; x = std::min (x, image.w-1); y = std::min (y, image.h-1); w = std::min (w, (unsigned)image.w-x); h = std::min (h, (unsigned)image.h-y); // something to do? if (x == 0 && y == 0 && w == (unsigned int)image.w && h == (unsigned int)image.h) return; if (!image.isModified() && image.getCodec()) if (image.getCodec()->crop(image, x, y, w, h)) return; /* std::cerr << "after limiting: " << x << " " << y << " " << w << " " << h << std::endl; */ // truncate the height, this is optimized for the "just height" case // (of e.g. fastAutoCrop) if (x == 0 && y == 0 && w == (unsigned int)image.w) { image.setRawData (); // invalidate image.h = h; return; } // bit shifting is too expensive, crop at least byte-wide int orig_bps = image.bps; if (orig_bps < 8) colorspace_grayX_to_gray8 (image); int stride = image.stride(); int cut_stride = stride * w / image.w; uint8_t* dst = image.getRawData (); uint8_t* src = dst + stride * y + (stride * x / image.w); for (unsigned int i = 0; i < h; ++i) { memmove (dst, src, cut_stride); dst += cut_stride; src += stride; } image.setRawData (); // invalidate image.w = w; image.h = h; switch (orig_bps) { case 1: colorspace_gray8_to_gray1 (image); break; case 2: colorspace_gray8_to_gray2 (image); break; case 4: colorspace_gray8_to_gray4 (image); break; default: ; } } // auto crop just the bottom of an image filled in the same, solid color // optimization: for sub-byte depth we compare a 8bit pattern unit at-a-time void fastAutoCrop (Image& image) { if (!image.getRawData()) return; const int stride = image.stride(); const unsigned int bytes = (image.spp * image.bps + 7) / 8; int h = image.h - 1; uint8_t* data = image.getRawData() + stride * h; // which value to compare against, first pixel of the last line #ifndef _MSC_VER uint8_t v[bytes]; #else std::vector<uint8_t> v(bytes); #endif memcpy(&v[0], data, bytes); for (; h >= 0; --h, data -= stride) { // data row int i = 0; for (; i < stride; i += bytes) { if (data[i] != v[0] || (bytes > 1 && memcmp(&data[i+1], &v[1], bytes - 1) != 0)) { break; // pixel differs, break out } } if (i != stride) break; // non-solid line, break out } if (h == 0) // do not crop if the image is totally empty return; // We could just tweak the image height here, but using the generic // code we benefit from possible optimization, such as lossless // jpeg cropping. // We do not explicitly check if we crop, the crop function will optimize // a NOP crop away for all callers. return crop (image, 0, 0, image.w, h); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/ContourMatching.cc������������������������������������������������������������0000644�0000764�0000764�00000031150�10767440606�016554� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <cmath> #include <algorithm> #include <iostream> #include "ContourMatching.hh" const unsigned int logo_trans_before_rot=10000; // TODO: calculate useful value !! class LengthSorter { public: const std::vector <Contours::Contour*>& contours; LengthSorter(const std::vector <Contours::Contour*>& contour_list) : contours(contour_list) {} bool operator() (unsigned int i, unsigned int j) { return contours[i]->size() > contours[j]->size(); } }; class MatchSorter { public: bool operator() (const LogoRepresentation::Match* a, const LogoRepresentation::Match* b) { return a->score > b->score; } }; LogoRepresentation::LogoRepresentation(Contours* logo_contours, unsigned int max_feature_no, unsigned int max_avg_tolerance, unsigned int reduction_shift, double maximum_angle, double angle_step) { source=logo_contours; tolerance=max_avg_tolerance; shift=reduction_shift; rot_max=maximum_angle; rot_step=angle_step; total_contour_length=0; logo_set_count=source->contours.size(); logo_set_map.resize(logo_set_count); for (unsigned int i=0; i<logo_set_count; i++) logo_set_map[i]=i; if (logo_set_count > max_feature_no) { std::sort(logo_set_map.begin(), logo_set_map.end(), LengthSorter(source->contours)); logo_set_count=max_feature_no; } centerx=.0; centery=.0; unsigned int count=0; for (unsigned int i=0; i<logo_set_count; i++) { count+=source->contours[logo_set_map[i]]->size(); for (unsigned int j=0; j<source->contours[logo_set_map[i]]->size(); j++) { centerx += (*(source->contours[logo_set_map[i]]))[j].first; centery += (*(source->contours[logo_set_map[i]]))[j].second; } } centerx/=(double)count; centery/=(double)count; double angle=.0; rot_max=std::min(359.9, fabs(rot_max)); rot_step=std::max(rot_step, 0.5); do { logo_sets.push_back(std::vector <LogoContourData> (logo_set_count)); for (unsigned int c=0; c<logo_set_count; c++) { LogoContourData& data=logo_sets.back()[c]; data.contour=new Contours::Contour(); if (angle==0) { CenterAndReduce(*(source->contours[logo_set_map[c]]), *data.contour, shift, data.rx, data.ry); total_contour_length+=source->contours[logo_set_map[c]]->size(); } else RotCenterAndReduce(*(source->contours[logo_set_map[c]]), *data.contour, M_PI*angle / 180.0, logo_trans_before_rot, shift, data.rx, data.ry); } if (angle > 0) { angle=-angle; } else { angle=-angle+rot_step; } } while (angle <= rot_max); } LogoRepresentation::~LogoRepresentation() { for (unsigned int s=0; s<logo_sets.size(); s++) for (unsigned int j=0; j<logo_set_count; j++) delete logo_sets[s][j].contour; } double LogoRepresentation::Score(Contours* image) { unsigned int image_set_count=image -> contours.size(); if (image_set_count==0 || logo_set_count==0) { std::cerr << "Warning: nothing to match..." << std::endl; return 0.0; } // build image set image_set.resize(image_set_count); for (unsigned int c=0; c<image_set_count; c++) { ImageContourData& data=image_set[c]; data.contour=new Contours::Contour(); CenterAndReduce(*(image->contours[c]), *data.contour, shift, data.rx, data.ry); } // calculate 1 to 1 matching scores for (unsigned int s=0; s<logo_sets.size(); s++) for (unsigned int j=0; j<logo_set_count; j++) { logo_sets[s][j].matches.resize(image_set_count); for (unsigned int i=0; i<image_set_count; i++) logo_sets[s][j].matches[i]=new Match(image_set[i], logo_sets[s][j], tolerance, shift, source->contours[logo_set_map[j]]->size(), image->contours[i]); } // calculate heuristic n to m matching double score=.0; unsigned int best_set=0; unsigned int best_pivot=0; for (unsigned int s=0; s<logo_sets.size(); s++) { unsigned int pivot=0; double current=N_M_Match(s, pivot); if (current > score) { score=current; best_set=s; best_pivot=pivot; } } // starting parameters optained from heuristic score=(score/ (double) total_contour_length) / (double) tolerance; std::cout << "heuristic score: " << score << std::endl; const LogoContourData& result=logo_sets[best_set][best_pivot]; logo_translation.first=(int)result.matches[result.n_to_n_match_index]->transx; logo_translation.second=(int)result.matches[result.n_to_n_match_index]->transy; if (best_set==0) rot_angle=.0; else { logo_translation.first+=logo_trans_before_rot; logo_translation.second+=logo_trans_before_rot; rot_angle=rot_step*(double)((best_set+1)/2); if (best_set%2==0) rot_angle=-rot_angle; } mapping.resize(logo_set_count); for (unsigned int i=0; i<logo_set_count; i++) { mapping[i]=std::pair <Contours::Contour*, Contours::Contour*> (source->contours[logo_set_map[i]], logo_sets[best_set][i].matches[logo_sets[best_set][i].n_to_n_match_index]->cimg); } // adjust translation // (this is a quick workaround to the shifted-centroid phenomenon) Contours::Contour tmp; double rax=.0; double ray=.0; double rbx=.0; double rby=.0; RotCenterAndReduce(*(mapping[best_pivot].first), tmp, M_PI*rot_angle/180.0, logo_trans_before_rot, 0, rax, ray); rax-=(double)logo_trans_before_rot; ray-=(double)logo_trans_before_rot; tmp.clear(); const Contours::Contour& second=*(mapping[best_pivot].second); for (unsigned int i=0; i<second.size(); i++) { rbx+=second[i].first; rby+=second[i].second; } rbx/=(double)second.size(); rby/=(double)second.size(); int newtx=(int)(rbx-rax); int newty=(int)(rby-ray); std::cout << "adjusting translation: " << logo_translation.first << "\t" << logo_translation.second << "\t->\t" << newtx << "\t" << newty << std::endl; logo_translation.first=newtx; logo_translation.second=newty; // optimize score=PrecisionScore(); //#if false /* double oldrx=.0; double oldry=.0; double newrx=.0; double newry=.0; RotatedCentroidPosition(oldrx, oldry); rot_angle-=10; RotatedCentroidPosition(newrx, newry); logo_translation.first+=(int)(oldrx-newrx); logo_translation.second+=(int)(oldry-newry); */ bool improved=true; unsigned int precision_iterations=4; //if (false) for (unsigned int run=0; run <= precision_iterations && improved ; run++) { std::cout << score << "\t" << logo_translation.first << "\t" << logo_translation.second << "\t" << rot_angle << std::endl; improved=false; if (run < precision_iterations) { improved=Optimize(score); } } //#endif // clean up for (unsigned int s=0; s<logo_sets.size(); s++) for (unsigned int j=0; j<logo_set_count; j++) { for (unsigned int i=0; i<image_set_count; i++) delete logo_sets[s][j].matches[i]; logo_sets[s][j].matches.clear(); } for (unsigned int j=0; j<image_set_count; j++) delete image_set[j].contour; image_set.clear(); return score; } const std::pair<int, int>& LogoRepresentation::CalculateInverseTranslation(int rx, int ry) { double x=(double)logo_translation.first - rx; double y=(double)logo_translation.second - ry; double c=cos(-M_PI*rot_angle/180.0); double s=sin(-M_PI*rot_angle/180.0); double xx=c*x - s*y; double yy=s*x + c*y; inverse_translation.first=rx+(int)xx; inverse_translation.second=ry+(int)yy; return inverse_translation; } double LogoRepresentation::N_M_Match(unsigned int set, unsigned int& pivot) { std::vector <LogoContourData>& data=logo_sets[set]; for (unsigned int i=0; i<logo_set_count; i++) { std::sort(data[i].matches.begin(), data[i].matches.end(), MatchSorter()); //std::cout << "BEST\t" << data[i].matches[0]->score << std::endl; } unsigned int image_set_count=data[0].matches.size(); const unsigned int depth=5; const unsigned int counterdepth=1000; int mdepth=std::min(image_set_count, depth); int ndepth=std::min(image_set_count, counterdepth); double bestsum=.0; pivot=0; unsigned int tmpbest[logo_set_count]; for (unsigned int base=0; base < logo_set_count; base++) for (int m=0; m < mdepth; m++) { double sum=data[base].matches[m]->score; double tx=data[base].matches[m]->transx; double ty=data[base].matches[m]->transy; tmpbest[base]=m; for (unsigned int counter=0; counter < logo_set_count; counter++) if (counter != base) { double best=.0; tmpbest[counter]=0; for (int n=0; n < ndepth; n++){ double current=data[counter].matches[n]->TransScore(tx, ty); if (current > best) { best=current; tmpbest[counter]=n; } } sum+=best; } if (sum > bestsum) { bestsum=sum; pivot=base; for (unsigned int i=0; i<logo_set_count; i++) data[i].n_to_n_match_index=tmpbest[i]; } } //std::cout << pivot << std::endl; return bestsum; } double LogoRepresentation::PrecisionScore() { Contours::Contour tmp; double trash; //double sum=(double)tolerance*(double)total_contour_length; double sum=.0; unsigned int length=0; double tx=(double)logo_translation.first-(double)logo_trans_before_rot; double ty=(double)logo_translation.second-(double)logo_trans_before_rot; for (unsigned int i=0; i<logo_set_count; i++) { tmp.clear(); RotCenterAndReduce(*mapping[i].first, tmp, M_PI*rot_angle/180.0, logo_trans_before_rot, 0, trash, trash); double current=(double)tolerance*(double)tmp.size(); length+=tmp.size(); current-=L1Dist(tmp, *mapping[i].second, 0.0, 0.0, tx, ty, 0, trash, trash); //std::cout << "match " << i << "\t" << current << std::endl; sum+=std::max(0.0, current); } sum=(sum/ (double)length) / (double) tolerance; return sum; }; void LogoRepresentation::RotatedCentroidPosition(double& rx, double& ry) { double c=cos(M_PI*rot_angle/180.0); double s=sin(M_PI*rot_angle/180.0); rx=c*centerx - s*centery; ry=s*centerx + c*centery; // std::cout << centerx << "\t" << centery << "\t\t" << rx << "\t" << ry <<std::endl; } bool LogoRepresentation::OptimizeAngle(double& score, double delta) { double oldrx=.0; double oldry=.0; double newrx=.0; double newry=.0; std::pair<int, int> o_translation=logo_translation; double o_angle=rot_angle; RotatedCentroidPosition(oldrx, oldry); rot_angle+=delta; RotatedCentroidPosition(newrx, newry); logo_translation.first+=(int)(oldrx-newrx); logo_translation.second+=(int)(oldry-newry); double new_score=PrecisionScore(); if (new_score > score) { score=new_score; return true; } logo_translation=o_translation; rot_angle=o_angle; return false; } bool LogoRepresentation::OptimizeHTranslation(double& score, int delta) { logo_translation.first+=delta; double new_score=PrecisionScore(); if (new_score > score) { score=new_score; return true; } logo_translation.first-=delta; return false; } bool LogoRepresentation::OptimizeVTranslation(double& score, int delta) { logo_translation.second+=delta; double new_score=PrecisionScore(); if (new_score > score) { score=new_score; return true; } logo_translation.second-=delta; return false; } bool LogoRepresentation::Optimize(double& score) { bool improvement=false; const double start_angle_delta=2.0; const double end_angle_delta=0.01; // was 0.1 -ReneR 2007-08-06 double delta=start_angle_delta; do { bool success=false; while (OptimizeAngle(score, delta)) success=true; if (!success) while (OptimizeAngle(score, -delta)) success=true; improvement |= success; delta /= 2.0; } while (delta >= end_angle_delta ); bool successh=false; while (OptimizeHTranslation(score, +1)) successh=true; if (!successh) while (OptimizeHTranslation(score, -1)) successh=true; improvement |= successh; bool successv=false; while (OptimizeVTranslation(score, +1)) successv=true; if (!successv) while (OptimizeVTranslation(score, -1)) successv=true; improvement |= successv; return improvement; }; LogoRepresentation::Match::Match(const ImageContourData& image, const LogoContourData& logo, int tolerance, int shift, unsigned int original_logo_length, Contours::Contour* icimg) { length=original_logo_length; cimg=icimg; score=(double)tolerance*(double)length; score-=L1Dist(*logo.contour, *image.contour, logo.rx, logo.ry, image.rx, image.ry, shift, transx, transy); if (score < 0.0) score=.0; } double LogoRepresentation::Match::TransScore(double tx, double ty) { return std::max(.0, score - 0.5*((double)length*(fabs(tx-transx)+fabs(ty-transy)))); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/vectorial.hh������������������������������������������������������������������0000644�0000764�0000764�00000006243�11575633144�015456� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Vector element rasterization, via Agg. * Copyright (C) 2007 - 2011 Rene Rebe, ExactCODE GmbH * Copyright (C) 2007 Susanne Klaus, 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. */ #ifndef VECTORIAL_HH #define VECTORIAL_HH #include "Image.hh" #include <vector> #include "config.h" #include "agg_math_stroke.h" #include "agg_path_storage.h" #include "agg_trans_affine.h" class Path { public: Path (); ~Path (); void moveTo (double x, double y); void addLine (double x, double y); void addLineTo (double x, double y); void addRect (double x, double y, double x2, double y2); // the first is relative, the second to an an absolute 2nd point void addArc (double rx, double ry, double angle, double dx, double dy); void addArcTo (double rx, double ry, double angle, double x2, double y2); /* TODO: - addEllipse */ void addCurveTo (double, double, double, double); // or explicitly differentiate by naming this one QuadCurve ??? void addCurveTo (double, double, double, double, double, double); void end (); void close (); void clear (); // path data, not the style void setFillColor (double r, double g, double b, double a = 1.0); void setLineWidth (double width); void setLineDash (double offset, const std::vector<double>& dashes); void setLineDash (double offset, const double* dashes, int n); typedef agg::line_cap_e line_cap_t; void setLineCap (line_cap_t cap); typedef agg::line_join_e line_join_t; void setLineJoin (line_join_t join); /* TODO: - clip - control anti-aliasing (- gradients) */ enum filling_rule_t { fill_non_zero = agg::fill_non_zero, fill_even_odd = agg::fill_even_odd, fill_none = 0xff }; void draw (Image& image, filling_rule_t fill = fill_none); // TODO: sophisticated text API, including font to use, // kerning, hinting, transform, etc. // void addText (char* text, double height); // temp. simple text draw method bool drawText (Image& image, const char* text, double height, const char* fontfile = 0, agg::trans_affine mtx = agg::trans_affine(), filling_rule_t fill = fill_non_zero, double* w = 0, double* h = 0, double* dx = 0, double* dy = 0); bool drawTextOnPath (Image& image, const char* text, double height, const char* fontfile = 0); // TODO: , filling_rule_t fill = fill_non_zero); protected: agg::path_storage path; // quick hack ("for now") double r, g, b, a, line_width, dashes_start_offset; std::vector <double> dashes; line_cap_t line_cap; line_join_t line_join; }; #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/DataMatrix.hh�����������������������������������������������������������������0000644�0000764�0000764�00000003126�11054774166�015523� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Valentin Ziegler, ExactCODE GmbH Germany. * * 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. */ #ifndef DATA_MATRIX_HH__ #define DATA_MATRIX_HH__ template <typename T> class DataMatrix { public: DataMatrix(unsigned int iw, unsigned int ih) { w=iw; h=ih; master=true; data=new T*[w]; for (unsigned int x=0; x<w; x++) data[x]=new T[h]; } DataMatrix(const DataMatrix<T>& source, unsigned int ix, unsigned int iy, unsigned int iw, unsigned int ih) { w=iw; h=ih; master=false; data=new T*[w]; for (unsigned int x=0; x<w; x++) data[x]=source.data[x+ix]+iy; } virtual ~DataMatrix() { if (master) for (unsigned int x=0; x<w; x++) delete[] data[x]; delete[] data; } unsigned int w; unsigned int h; T** data; bool master; const T& operator() (unsigned int x, unsigned int y) const { return data[x][y]; } T& operator() (unsigned int x, unsigned int y) { return data[x][y]; } }; #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/Colorspace.hh�����������������������������������������������������������������0000644�0000764�0000764�00000005133�12273425232�015546� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Colorspace conversions. * Copyright (C) 2006 - 2014 René Rebe, ExactCOD GmbH Germany * Copyright (C) 2007 Susanne Klaus, ExactCODE * * 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. */ #ifndef COLORSPACE_HH #define COLORSPACE_HH #include "Image.hh" #include <vector> void normalize (Image& image, uint8_t low = 0, uint8_t high = 0); std::vector<std::vector<unsigned int> > histogram(Image& image, int bins = 256); void colorspace_rgba8_to_rgb8 (Image& image); void colorspace_argb8_to_rgb8 (Image& image); void colorspace_cmyk_to_rgb8 (Image& image); void colorspace_rgb8_to_gray8 (Image& image, const int bytes = 3, const int wR = 28, const int wG = 59, const int wB = 11); void colorspace_rgb8_to_rgb8a (Image& image, uint8_t alpha=0xff); void colorspace_gray8_threshold (Image& image, uint8_t threshold = 127); void colorspace_gray8_denoise_neighbours (Image &image, bool gross = false); void colorspace_gray8_to_gray1 (Image& image, uint8_t threshold = 127); void colorspace_gray8_to_gray2 (Image& image); void colorspace_gray8_to_gray4 (Image& image); void colorspace_gray1_to_gray2 (Image& image); void colorspace_gray1_to_gray4 (Image& image); void colorspace_grayX_to_gray8 (Image& image); void colorspace_gray8_to_rgb8 (Image& image); void colorspace_grayX_to_rgb8 (Image& image); void colorspace_16_to_8 (Image& image); void colorspace_8_to_16 (Image& image); // the threshold is used during conversion to b/w formats bool colorspace_convert (Image& image, int spp, int bps, uint8_t threshold = 127); bool colorspace_by_name (Image& image, const std::string& target_colorspace, uint8_t threshold = 127); const char* colorspace_name (Image& image); void brightness_contrast_gamma (Image& image, double b, double c, double g); void hue_saturation_lightness (Image& image, double h, double s, double v); void invert (Image& image); // "internal" helper (for image loading) void colorspace_de_palette (Image& image, int table_entries, uint16_t* rmap, uint16_t* gmap, uint16_t* bmap, uint16_t* amap = 0); #endif �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/segmentation.cc���������������������������������������������������������������0000644�0000764�0000764�00000006123�10712335442�016136� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Image Segmentation * Copyright (C) 2007 Valentin Ziegler and René Rebe * * 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. * */ #include "vectorial.hh" #include "segmentation.hh" Segment::Segment(unsigned int ix, unsigned int iy, unsigned int iw, unsigned int ih, Segment* iparent) { x=ix; y=iy; w=iw; h=ih; parent=iparent; } Segment::~Segment() { for (unsigned int i=0; i<children.size(); i++) delete children[i]; } bool Segment::Subdivide(const FGMatrix& img, double tolerance, unsigned int min_length, bool horizontal) { unsigned int* counts=Count(img, horizontal); unsigned int end=horizontal ? h : w; unsigned int max_pixels=(unsigned int) (tolerance*(double)(horizontal ? w : h)); unsigned int length=0; unsigned int last_start=0; for (unsigned int n=0; n<end; n++) { if (counts[n] <= max_pixels) { length++; } else { if (length >= min_length || length==n) { if (length < n) InsertChild(last_start, n-length, horizontal); last_start=n; } length=0; } } if (last_start > 0) InsertChild(last_start, end-length, horizontal); delete[] counts; return (children.size() > 0); } void Segment::Draw(Image& output, uint16_t r, uint16_t g, uint16_t b) { Path path; path.setFillColor ((double)r/255, (double)g/255, (double)b/255); path.addRect (x, y, x+w-1, y+h-1); path.draw (output); } void Segment::InsertChild(unsigned int start, unsigned int end, bool horizontal) { if (horizontal) children.push_back(new Segment(x, y+start, w, end-start, this)); else children.push_back(new Segment(x+start, y, end-start, h, this)); } // count foreground pixels in horizontal/vertical lines unsigned int* Segment::Count(const FGMatrix& img, bool horizontal) { FGMatrix subimg(img, x, y, w, h); unsigned int* counts=new unsigned int[horizontal ? h : w]; for (unsigned int n=0; n<(horizontal ? h : w) ; n++) counts[n]=0; for (unsigned int px=0; px<w; px++) for (unsigned int py=0; py<h; py++) if (subimg(px,py)) counts[horizontal ? py : px]++; return counts; } void segment_recursion(Segment* s, const FGMatrix& img, double tolerance, unsigned int min_w, unsigned int min_h, bool horizontal) { if (s->Subdivide(img, tolerance, horizontal ? min_h : min_w, horizontal)) for (unsigned int i=0; i<s->children.size(); i++) segment_recursion(s->children[i], img, tolerance, min_w, min_h, !horizontal); } Segment* segment_image(const FGMatrix& img, double tolerance, unsigned int min_w, unsigned int min_h) { Segment* top=new Segment(0, 0, img.w, img.h); segment_recursion(top, img, tolerance, min_w, min_h, true); return top; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/ImageIterator2.hh�������������������������������������������������������������0000644�0000764�0000764�00000070055�12452515010�016270� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2008 - 2015 René Rebe, ExactCODE GmbH Germany. * * 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. */ #ifndef IMAGE_ITERATOR2_HH #define IMAGE_ITERATOR2_HH #include "Image.hh" #include <algorithm> class rgb_iterator { public: uint8_t* ptr; uint8_t* ptr_begin; const Image& image; const int stride; class accu { public: typedef int32_t vtype; static const int samples = 3; vtype v[samples]; accu () { v[0] = v[1] = v[2] = 0; } static accu one () { accu a; a.v[0] = a.v[1] = a.v[2] = 0xff; return a; } accu& abs() { v[0] = std::abs(v[0]); v[1] = std::abs(v[1]); v[2] = std::abs(v[2]); return *this; } void saturate () { v[0] = std::min (std::max (v[0], (vtype)0), (vtype)0xff); v[1] = std::min (std::max (v[1], (vtype)0), (vtype)0xff); v[2] = std::min (std::max (v[2], (vtype)0), (vtype)0xff); } accu& operator*= (vtype f) { v[0] *= f; v[1] *= f; v[2] *= f; return *this; } accu operator* (vtype f) const { accu a = *this; return a *= f; } accu& operator+= (vtype f) { v[0] += f; v[1] += f; v[2] += f; return *this; } accu operator+ (vtype f) const { accu a = *this; return a += f; } accu& operator/= (vtype f) { v[0] /= f; v[1] /= f; v[2] /= f; return *this; } accu operator/ (vtype f) const { accu a = *this; a /= f; return a; } accu& operator+= (const accu& other) { v[0] += other.v[0]; v[1] += other.v[1]; v[2] += other.v[2]; return *this; } accu operator+ (const accu& other) const { accu a = *this; a += other; return a; } accu& operator-= (const accu& other) { v[0] -= other.v[0]; v[1] -= other.v[1]; v[2] -= other.v[2]; return *this; } accu& operator= (const Image::iterator& background) { double r = 0, g = 0, b = 0; background.getRGB(r, g, b); v[0] = (vtype)(r * 0xff); v[1] = (vtype)(g * 0xff); v[2] = (vtype)(b * 0xff); return *this; } void getRGB (vtype& r, vtype& g, vtype& b) { r = v[0]; g = v[1]; b = v[2]; } void getL (vtype& l) { l = (11 * v[0] + 16 * v[1] + 5 * v[2]) / 32; } void setRGB (vtype r, vtype g, vtype b) { v[0] = r; v[1] = g; v[2] = b; } }; rgb_iterator (Image& _image) : ptr_begin(_image.getRawData()), image (_image), stride(_image.stride()) { ptr = ptr_begin; } rgb_iterator& at (int x, int y) { ptr = ptr_begin + y * stride + x * 3; return *this; } rgb_iterator& operator++ () { ptr += 3; return *this; } rgb_iterator& operator-- () { ptr -= 3; return *this; } accu operator* () { accu a; a.v[0] = ptr[0]; a.v[1] = ptr[1]; a.v[2] = ptr[2]; return a; } rgb_iterator& set (const accu& a) { ptr[0] = a.v[0]; ptr[1] = a.v[1]; ptr[2] = a.v[2]; return *this; } }; class rgba_iterator { public: uint8_t* ptr; uint8_t* ptr_begin; const Image& image; const int stride; class accu { public: typedef int32_t vtype; static const int samples = 4; vtype v[samples]; accu () { v[0] = v[1] = v[2] = v[3] = 0; } static accu one () { accu a; a.v[0] = a.v[1] = a.v[2] = a.v[3] = 0xff; return a; } accu& abs() { v[0] = std::abs(v[0]); v[1] = std::abs(v[1]); v[2] = std::abs(v[2]); v[3] = std::abs(v[3]); return *this; } void saturate () { v[0] = std::min (std::max (v[0], (vtype)0), (vtype)0xff); v[1] = std::min (std::max (v[1], (vtype)0), (vtype)0xff); v[2] = std::min (std::max (v[2], (vtype)0), (vtype)0xff); v[3] = std::min (std::max (v[3], (vtype)0), (vtype)0xff); } accu& operator*= (vtype f) { v[0] *= f; v[1] *= f; v[2] *= f; v[3] *= f; return *this; } accu operator* (vtype f) const { accu a = *this; return a *= f; } accu& operator+= (vtype f) { v[0] += f; v[1] += f; v[2] += f; v[3] += f; return *this; } accu operator+ (vtype f) const { accu a = *this; return a += f; } accu& operator/= (vtype f) { v[0] /= f; v[1] /= f; v[2] /= f; v[3] /= f; return *this; } accu operator/ (vtype f) const { accu a = *this; a /= f; return a; } accu& operator+= (const accu& other) { v[0] += other.v[0]; v[1] += other.v[1]; v[2] += other.v[2]; v[3] += other.v[3]; return *this; } accu operator+ (const accu& other) const { accu a = *this; a += other; return a; } accu& operator-= (const accu& other) { v[0] -= other.v[0]; v[1] -= other.v[1]; v[2] -= other.v[2]; v[3] -= other.v[3]; return *this; } accu& operator= (const Image::iterator& background) { double r = 0, g = 0, b = 0, a = 0; background.getRGBA(r, g, b, a); v[0] = (vtype)(r * 0xff); v[1] = (vtype)(g * 0xff); v[2] = (vtype)(b * 0xff); v[3] = (vtype)(a * 0xff); return *this; } void getRGB (vtype& r, vtype& g, vtype& b) { r = v[0]; g = v[1]; b = v[2]; } void getL (vtype& l) { l = (11 * v[0] + 16 * v[1] + 5 * v[2]) / 32; } void setRGB (vtype r, vtype g, vtype b) { v[0] = r; v[1] = g; v[2] = b; v[2] = 0xff; } }; rgba_iterator (Image& _image) : ptr_begin(_image.getRawData()), image (_image), stride(_image.stride()) { ptr = ptr_begin; } rgba_iterator& at (int x, int y) { ptr = ptr_begin + y * stride + x * 4; return *this; } rgba_iterator& operator++ () { ptr += 4; return *this; } rgba_iterator& operator-- () { ptr -= 4; return *this; } accu operator* () { accu a; a.v[0] = ptr[0]; a.v[1] = ptr[1]; a.v[2] = ptr[2]; a.v[3] = ptr[3]; return a; } rgba_iterator& set (const accu& a) { ptr[0] = a.v[0]; ptr[1] = a.v[1]; ptr[2] = a.v[2]; ptr[3] = a.v[3]; return *this; } }; class rgb16_iterator { public: uint16_t* ptr; uint16_t* ptr_begin; const Image& image; const int stride; class accu { public: typedef int64_t vtype; static const int samples = 3; vtype v[samples]; accu () { v[0] = v[1] = v[2] = 0; } static accu one () { accu a; a.v[0] = a.v[1] = a.v[2] = 0xffff; return a; } accu& abs() { v[0] = std::abs(v[0]); v[1] = std::abs(v[1]); v[2] = std::abs(v[2]); return *this; } void saturate () { v[0] = std::min (std::max (v[0], (vtype)0), (vtype)0xffff); v[1] = std::min (std::max (v[1], (vtype)0), (vtype)0xffff); v[2] = std::min (std::max (v[2], (vtype)0), (vtype)0xffff); } accu& operator*= (vtype f) { v[0] *= f; v[1] *= f; v[2] *= f; return *this; } accu operator* (vtype f) const { accu a = *this; return a *= f; } accu& operator+= (vtype f) { v[0] += f; v[1] += f; v[2] += f; return *this; } accu operator+ (vtype f) const { accu a = *this; return a += f; } accu& operator/= (vtype f) { v[0] /= f; v[1] /= f; v[2] /= f; return *this; } accu operator/ (vtype f) const { accu a = *this; a /= f; return a; } accu& operator+= (const accu& other) { v[0] += other.v[0]; v[1] += other.v[1]; v[2] += other.v[2]; return *this; } accu operator+ (const accu& other) const { accu a = *this; a += other; return a; } accu& operator-= (const accu& other) { v[0] -= other.v[0]; v[1] -= other.v[1]; v[2] -= other.v[2]; return *this; } accu& operator= (const Image::iterator& background) { double r = 0, g = 0, b = 0; background.getRGB(r, g, b); v[0] = (vtype)(r * 0xffff); v[1] = (vtype)(g * 0xffff); v[2] = (vtype)(b * 0xffff); return *this; } void getRGB (vtype& r, vtype& g, vtype& b) { r = v[0]; g = v[1]; b = v[2]; } void getL (vtype& l) { l = (11 * v[0] + 16 * v[1] + 5 * v[2]) / 32; } void setRGB (vtype r, vtype g, vtype b) { v[0] = r; v[1] = g; v[2] = b; } }; rgb16_iterator (Image& _image) : ptr_begin((uint16_t*)_image.getRawData()), image (_image), stride(_image.stride()) { ptr = ptr_begin; } rgb16_iterator& at (int x, int y) { ptr = ptr_begin + y * stride / 2 + x * 3; return *this; } rgb16_iterator& operator++ () { ptr += 3; return *this; } rgb16_iterator& operator-- () { ptr -= 3; return *this; } accu operator* () { accu a; a.v[0] = ptr[0]; a.v[1] = ptr[1]; a.v[2] = ptr[2]; return a; } rgb16_iterator& set (const accu& a) { ptr[0] = a.v[0]; ptr[1] = a.v[1]; ptr[2] = a.v[2]; return *this; } }; class gray_iterator { public: uint8_t* ptr; uint8_t* ptr_begin; const Image& image; const int stride; class accu { public: typedef int32_t vtype; static const int samples = 1; vtype v[samples]; accu () { v[0] = 0; } static accu one () { accu a; a.v[0] = 0xff; return a; } accu& abs() { v[0] = std::abs(v[0]); return *this; } void saturate () { v[0] = std::min (std::max (v[0], (vtype)0), (vtype)0xff); } accu& operator*= (vtype f) { v[0] *= f; return *this; } accu operator* (vtype f) const { accu a = *this; return a *= f; } accu& operator+= (vtype f) { v[0] += f; return *this; } accu operator+ (vtype f) const { accu a = *this; return a += f; } accu& operator/= (vtype f) { v[0] /= f; return *this; } accu operator/ (vtype f) const { accu a = *this; a /= f; return a; } accu& operator+= (const accu& other) { v[0] += other.v[0]; return *this; } accu operator+ (const accu& other) const { accu a = *this; a += other; return a; } accu& operator-= (const accu& other) { v[0] -= other.v[0]; return *this; } accu& operator= (const Image::iterator& background) { v[0] = background.getL(); return *this; } void getRGB (vtype& r, vtype& g, vtype& b) { r = g = b = v[0]; } void getL (vtype& l) { l = v[0]; } void setRGB (vtype r, vtype g, vtype b) { v[0] = (11 * r + 16 * g + 5 * b) / 32; } }; gray_iterator (Image& _image) : ptr_begin(_image.getRawData()), image (_image), stride(_image.stride()) { ptr = ptr_begin; } gray_iterator& at (int x, int y) { ptr = ptr_begin + y * stride + x; return *this; } gray_iterator& operator++ () { ptr += 1; return *this; } gray_iterator& operator-- () { ptr -= 1; return *this; } accu operator* () { accu a; a.v[0] = ptr[0]; return a; } gray_iterator& set (const accu& a) { ptr[0] = a.v[0]; return *this; } }; class gray16_iterator { public: uint16_t* ptr; uint16_t* ptr_begin; const Image& image; const int stride; class accu { public: typedef int64_t vtype; static const int samples = 1; vtype v[samples]; accu () { v[0] = 0; } static accu one () { accu a; a.v[0] = 0xffff; return a; } accu& abs() { v[0] = std::abs(v[0]); return *this; } void saturate () { v[0] = std::min (std::max (v[0], (vtype)0), (vtype)0xffff); } accu& operator*= (vtype f) { v[0] *= f; return *this; } accu operator* (vtype f) const { accu a = *this; return a *= f; } accu& operator+= (vtype f) { v[0] += f; return *this; } accu operator+ (vtype f) const { accu a = *this; return a += f; } accu& operator/= (vtype f) { v[0] /= f; return *this; } accu operator/ (vtype f) const { accu a = *this; a /= f; return a; } accu& operator+= (const accu& other) { v[0] += other.v[0]; return *this; } accu operator+ (const accu& other) const { accu a = *this; a += other; return a; } accu& operator-= (const accu& other) { v[0] -= other.v[0]; return *this; } accu& operator= (const Image::iterator& background) { v[0] = background.getL(); return *this; } void getRGB (vtype& r, vtype& g, vtype& b) { r = g = b = v[0]; } void getL (vtype& l) { l = v[0]; } void setRGB (vtype r, vtype g, vtype b) { v[0] = (11 * r + 16 * g + 5 * b) / 32; } }; gray16_iterator (Image& _image) : ptr_begin((uint16_t*)_image.getRawData()), image (_image), stride(_image.stride()) { ptr = ptr_begin; } gray16_iterator& at (int x, int y) { ptr = ptr_begin + y * stride/2 + x; return *this; } gray16_iterator& operator++ () { ptr += 1; return *this; } gray16_iterator& operator-- () { ptr -= 1; return *this; } accu operator* () { accu a; a.v[0] = ptr[0]; return a; } gray16_iterator& set (const accu& a) { ptr[0] = a.v[0]; return *this; } }; template <unsigned int bitdepth> class bit_iterator { public: uint8_t* ptr; uint8_t* ptr_begin; int _x; const Image& image; const int width, stride; int bitpos; const int mask; typedef gray_iterator::accu accu; // reuse bit_iterator (Image& _image) : ptr_begin(_image.getRawData()), _x(0), image (_image), width(_image.width()), stride(_image.stride()), bitpos(7), mask ((1 << bitdepth) - 1) { ptr = ptr_begin; } bit_iterator& at (int x, int y) { _x = x; ptr = ptr_begin + y * stride + x / (8 / bitdepth); bitpos = 7 - (x % (8 / bitdepth)) * bitdepth; return *this; } bit_iterator& operator++ () { ++_x; bitpos -= bitdepth; if (bitpos < 0 || _x == width) { if (_x == width) _x = 0; ++ptr; bitpos = 7; } return *this; } // untested, TODO: test !!! bit_iterator& operator-- () { --_x; bitpos += bitdepth; if (bitpos < 0 || _x < 0) { if (_x < 0) _x = width; --ptr; bitpos = 7; } return *this; } accu operator* () { accu a; a.v[0] = ((*ptr >> (bitpos - (bitdepth - 1))) & mask) * 0xff / mask; return a; } bit_iterator& set (const accu& a) { *ptr &= ~(mask << (bitpos - (bitdepth - 1))); *ptr |= (a.v[0] >> (8 - bitdepth)) << (bitpos - (bitdepth - 1)); return *this; } }; template <template <typename T> class ALGO, class T1> void codegen (T1& a1) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; a (a1); } else { ALGO <rgb16_iterator> a; a (a1); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; a (a1); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; a(a1); } else if (a1.bps == 8) { ALGO <gray_iterator> a; a(a1); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; a (a1); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; a (a1); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; a (a1); } } template <template <typename T> class ALGO, class T1, class T2> void codegen (T1& a1, T2& a2) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; a (a1, a2); } else { ALGO <rgb16_iterator> a; a (a1, a2); } } else if (a1.bps == 16) { ALGO <gray16_iterator> a; a(a1, a2); } else if (a1.bps == 8) { ALGO <gray_iterator> a; a(a1, a2); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; a (a1, a2); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; a (a1, a2); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; a (a1, a2); } } template <template <typename T> class ALGO, class T1, class T2, class T3> void codegen (T1& a1, T2& a2, T3& a3) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; a (a1, a2, a3); } else { ALGO <rgb16_iterator> a; a (a1, a2, a3); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; a (a1, a2, a3); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; a(a1, a2, a3); } else if (a1.bps == 8) { ALGO <gray_iterator> a; a(a1, a2, a3); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; a (a1, a2, a3); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; a (a1, a2, a3); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; a (a1, a2, a3); } } template <template <typename T> class ALGO, class T1, class T2, class T3, class T4> void codegen (T1& a1, T2& a2, T3& a3, T4& a4) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; a (a1, a2, a3, a4); } else { ALGO <rgb16_iterator> a; a (a1, a2, a3, a4); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; a (a1, a2, a3, a4); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; a(a1, a2, a3, a4); } else if (a1.bps == 8) { ALGO <gray_iterator> a; a(a1, a2, a3, a4); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; a (a1, a2, a3, a4); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; a (a1, a2, a3, a4); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; a (a1, a2, a3, a4); } } template <template <typename T> class ALGO, class T1, class T2, class T3, class T4, class T5> void codegen (T1& a1, T2& a2, T3& a3, T4& a4, T5& a5) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; a (a1, a2, a3, a4, a5); } else { ALGO <rgb16_iterator> a; a (a1, a2, a3, a4, a5); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; a (a1, a2, a3, a4, a5); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; a(a1, a2, a3, a4, a5); } else if (a1.bps == 8) { ALGO <gray_iterator> a; a(a1, a2, a3, a4, a5); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; a (a1, a2, a3, a4, a5); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; a (a1, a2, a3, a4, a5); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; a (a1, a2, a3, a4, a5); } } template <template <typename T> class ALGO, class T1, class T2, class T3, class T4, class T5, class T6> void codegen (T1& a1, T2& a2, T3& a3, T4& a4, T5& a5, T6& a6) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; a (a1, a2, a3, a4, a5, a6); } else { ALGO <rgb16_iterator> a; a (a1, a2, a3, a5, a5, a6); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; a (a1, a2, a3, a5, a5, a6); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; a(a1, a2, a3, a4, a5, a6); } else if (a1.bps == 8) { ALGO <gray_iterator> a; a(a1, a2, a3, a4, a5, a6); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; a (a1, a2, a3, a4, a5, a6); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; a (a1, a2, a3, a4, a5, a6); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; a (a1, a2, a3, a4, a5, a6); } } template <template <typename T> class ALGO, class T1, class T2, class T3, class T4, class T5, class T6, class T7> void codegen (T1& a1, T2& a2, T3& a3, T4& a4, T5& a5, T6& a6, T7& a7) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; a (a1, a2, a3, a4, a5, a6, a7); } else { ALGO <rgb16_iterator> a; a (a1, a2, a3, a4, a5, a6, a7); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; a (a1, a2, a3, a5, a5, a6, a7); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; a (a1, a2, a3, a4, a5, a6, a7); } else if (a1.bps == 8) { ALGO <gray_iterator> a; a (a1, a2, a3, a4, a5, a6, a7); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; a (a1, a2, a3, a4, a5, a6, a7); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; a (a1, a2, a3, a4, a5, a6, a7); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; a (a1, a2, a3, a4, a5, a6, a7); } } template <template <typename T> class ALGO, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8> void codegen (T1& a1, T2& a2, T3& a3, T4& a4, T5& a5, T6& a6, T7& a7, T8& a8) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; a (a1, a2, a3, a4, a5, a6, a7, a8); } else { ALGO <rgb16_iterator> a; a (a1, a2, a3, a4, a5, a6, a7, a8); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; a (a1, a2, a3, a5, a5, a6, a7, a8); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; a (a1, a2, a3, a4, a5, a6, a7, a8); } else if (a1.bps == 8) { ALGO <gray_iterator> a; a (a1, a2, a3, a4, a5, a6, a7, a8); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; a (a1, a2, a3, a4, a5, a6, a7, a8); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; a (a1, a2, a3, a4, a5, a6, a7, a8); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; a (a1, a2, a3, a4, a5, a6, a7, a8); } } template <template <typename T> class ALGO, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8, class T9, class T10> void codegen (T1& a1, T2& a2, T3& a3, T4& a4, T5& a5, T6& a6, T7& a7, T8& a8, T9& a9, T10& a10) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; a (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } else { ALGO <rgb16_iterator> a; a (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; a (a1, a2, a3, a5, a5, a6, a7, a8, a9, a10); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; a (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } else if (a1.bps == 8) { ALGO <gray_iterator> a; a (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; a (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; a (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; a (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); } } // with return template <class T0, template <typename T> class ALGO, class T1> T0 codegen_return (T1& a1) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; return a (a1); } else { ALGO <rgb16_iterator> a; return a (a1); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; return a (a1); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; return a (a1); } else if (a1.bps == 8) { ALGO <gray_iterator> a; return a (a1); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; return a (a1); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; return a (a1); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; return a (a1); } // warn unhandled T0 t; return t; } template <class T0, template <typename T> class ALGO, class T1, class T2> T0 codegen_return (T1& a1, T2& a2) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; return a (a1, a2); } else { ALGO <rgb16_iterator> a; return a (a1, a2); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; return a (a1, a2); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; return a (a1, a2); } else if (a1.bps == 8) { ALGO <gray_iterator> a; return a (a1, a2); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; return a (a1, a2); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; return a (a1, a2); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; return a (a1, a2); } // warn unhandled T0 t; return t; } template <class T0, template <typename T> class ALGO, class T1, class T2, class T3> T0 codegen_return (T1& a1, T2& a2, T3& a3) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; return a (a1, a2, a3); } else { ALGO <rgb16_iterator> a; return a (a1, a2, a3); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; return a (a1, a2, a3); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; return a (a1, a2, a3); } else if (a1.bps == 8) { ALGO <gray_iterator> a; return a (a1, a2, a3); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; return a (a1, a2, a3); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; return a (a1, a2, a3); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; return a (a1, a2, a3); } // warn unhandled T0 t; return t; } template <class T0, template <typename T> class ALGO, class T1, class T2, class T3, class T4, class T5, class T6, class T7> T0 codegen_return (T1& a1, T2& a2, T3& a3, T4& a4, T5& a5, T6& a6, T7& a7) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; return a (a1, a2, a3, a4, a5, a6, a7); } else { ALGO <rgb16_iterator> a; return a (a1, a2, a3, a4, a5, a6, a7); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; return a (a1, a2, a3, a5, a5, a6, a7); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; return a (a1, a2, a3, a4, a5, a6, a7); } else if (a1.bps == 8) { ALGO <gray_iterator> a; return a (a1, a2, a3, a4, a5, a6, a7); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; return a (a1, a2, a3, a4, a5, a6, a7); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; return a (a1, a2, a3, a4, a5, a6, a7); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; return a (a1, a2, a3, a4, a5, a6, a7); } // warn unhandled T0 t; return t; } template <class T0, template <typename T> class ALGO, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8> T0 codegen_return (T1& a1, T2& a2, T3& a3, T4& a4, T5& a5, T6& a6, T7& a7, T8& a8) { if (a1.spp == 3) { if (a1.bps == 8) { ALGO <rgb_iterator> a; return a (a1, a2, a3, a4, a5, a6, a7, a8); } else { ALGO <rgb16_iterator> a; return a (a1, a2, a3, a4, a5, a6, a7, a8); } } else if (a1.spp == 4 && a1.bps == 8) { ALGO <rgba_iterator> a; return a (a1, a2, a3, a5, a5, a6, a7, a8); } else if (a1.bps == 16) { ALGO <gray16_iterator> a; return a (a1, a2, a3, a4, a5, a6, a7, a8); } else if (a1.bps == 8) { ALGO <gray_iterator> a; return a (a1, a2, a3, a4, a5, a6, a7, a8); } else if (a1.bps == 4) { ALGO <bit_iterator<4> > a; return a (a1, a2, a3, a4, a5, a6, a7, a8); } else if (a1.bps == 2) { ALGO <bit_iterator<2> > a; return a (a1, a2, a3, a4, a5, a6, a7, a8); } else if (a1.bps == 1) { ALGO <bit_iterator<1> > a; return a (a1, a2, a3, a4, a5, a6, a7, a8); } // warn unhandled T0 t; return t; } #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/Image.hh����������������������������������������������������������������������0000644�0000764�0000764�00000016211�12453514335�014500� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * The Plain Old Data encapsulation of pixel, raster data. * Copyright (C) 2005 - 2015 René Rebe * * 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. */ /* Only minimal abstraction is done here, to allow all sorts of * hand optimized low-level operations. * * While historically we only supported packed, byte-aligned scanlines, * since 2015 we also support abritrary strides. However, most algorithms * resizing the data usually compact the image to byte-aligned scanlines. * * On load a codec might be attached. The codec might be querried * to decode the image data later on (decode on access) to allow * avoiding image decoding if the data is never accessed at all. * * Equivalently writing can be optimized by keeping the codec * around and saving the original data without recompression * (JPEG). * * Some methods in the codec allow working on the compressed data such * as orthogonal rotation, down-scaling, and cropping (e.g. of JPEG * DCT coefficients - like jpegtran, epeg). * * Call sequence on Read/Wrie: * to immediatly attach the data * Image::New(w,h) * Image::getRawData() // to write the data * Image::setCodec() * * or to get on-demand decoding: * set meta data (e.g. ::w, ::h, ::xdpi, ::ydpi, ...) * Image::setRawData(0) * Image::setCodec() * * Note: setCodec must be last as it marks the data as unmodifed. * * On access the data might be loaded on-demand: * Image::getRawData() * if !data then if codec then codec->decode() end end * * After modifing the POD image setRawData*() must be called to * notify about the update: * Image::setRawData*() * if !modified then codec->free() modified=true end * * Again: If you modify more than meta data you must call: * Image::setRawData() * even with the current data pointer remains equal to ensure * proper invalidation of the cached compressed codec data! * * Call sequence of the Codec's::encode*() if data is just rewritten: * if image->isModified() then * encode_new_data() * else * just copy existing compressed data (e.g. DCT) * end * * The operator= create a complete clone of the image, the image * buffers are not shared (anymore, formerly ownership was passed and * we had a seperate Clone() method). The attached codec is not * copied. */ #ifndef IMAGE_HH #define IMAGE_HH #include <inttypes.h> #include <string> #include <math.h> // for floor #include <iostream> // just forward class ImageCodec; /// temp. state to migrate away from public member's #define DEPRECATED #ifndef DEPRECATED #ifdef __GNUC__ #define DEPRECATED __attribute__ ((deprecated)) #endif #endif #define WARN_UNHANDLED std::cerr << "unhandled spp/bps in " << __FILE__ << ":" << __LINE__ << std::endl class Image { protected: bool modified, meta_modified; int xres, yres; std::string decoderID; ImageCodec* codec; uint8_t* data; public: uint8_t* getRawData () const; uint8_t* getRawDataEnd () const; void setRawData (); // just mark modified void setRawData (uint8_t* _data); void setRawDataWithoutDelete (uint8_t* _data); void resize (int _w, int _h, unsigned stride = 0); void realloc (); void setDecoderID (const std::string& id); const std::string& getDecoderID (); ImageCodec* getCodec(); void setCodec (ImageCodec* _codec); bool isModified () { return modified; } bool isMetaModified () { return meta_modified; } typedef enum { GRAY1 = 1, GRAY2, GRAY4, GRAY8, // GRAY8A, GRAY16, // GRAY16A, RGB8, RGB8A, RGB16, // RGB16A, CMYK8, // CMYK16, YUV8, // YUVK8 - really appears in the wild? JPEG appears to support this (Y/Cb/Cr/K) } type_t; typedef union { uint8_t gray; uint16_t gray16; struct { uint8_t r; uint8_t g; uint8_t b; } rgb; struct { uint8_t r; uint8_t g; uint8_t b; uint8_t a; } rgba; struct { uint16_t r; uint16_t g; uint16_t b; } rgb16; struct { uint8_t c; uint8_t m; uint8_t y; uint8_t k; } cmyk; struct { uint8_t y; uint8_t u; uint8_t v; } yuv; } value_t; typedef union { int32_t gray; struct { int32_t r; int32_t g; int32_t b; } rgb; struct { int32_t r; int32_t g; int32_t b; int32_t a; } rgba; struct { int32_t c; int32_t m; int32_t y; int32_t k; } cmyk; struct { int32_t y; int32_t u; int32_t v; } yuv; } ivalue_t; int width () const { return w; } int height () const { return h; } unsigned stride () const { return rowstride ? rowstride : (w * spp * bps + 7) / 8; } int bitsPerSample () const { return bps; } int bitsPerPixel () const { return bps * spp; } int samplesPerPixel () const { return spp; } int resolutionX () const { return xres; } int resolutionY () const { return yres; } void setWidth (int _w) { w = _w; } void setHeight (int _h) { h = _h; } void setBitsPerSample (int _bps) { bps = _bps; } void setSamplesPerPixel (int _spp) { spp = _spp; } void setResolution (int _xres, int _yres) { if (xres != _xres || yres != _yres) meta_modified = true; xres = _xres; yres = _yres; } void setResolutionX (int _xres) { setResolution(_xres, yres); } void setResolutionY (int _yres) { setResolution(xres, _yres); } int w DEPRECATED, h DEPRECATED; // TODO: unsigned? unsigned short bps DEPRECATED, spp DEPRECATED; unsigned rowstride DEPRECATED; public: Image (); Image (Image& other); ~Image (); Image& operator= (const Image& other); void copyTransferOwnership (Image& other); type_t Type () const { switch (spp*bps) { case 1: return GRAY1; case 2: return GRAY2; case 4: return GRAY4; case 8: return GRAY8; case 16: return GRAY16; case 24: return RGB8; case 32: return RGB8A; case 48: return RGB16; default: WARN_UNHANDLED; return (Image::type_t)0; } } #define CONST const #include "ImageIterator.hh" #include "ImageIterator.hh" const_iterator begin () const { return const_iterator (this, false); } const_iterator end () const { return const_iterator (this, true); } iterator begin () { return iterator (this, false); } iterator end () { return iterator (this, true); } void copyMeta (const Image& other); protected: }; typedef struct { uint8_t r, g, b; } rgb; typedef struct { uint8_t r, g, b, a;} rgba; typedef struct { uint16_t r, g, b; } rgb16; #undef WARN_UNHANDLED #undef DEPRECATED #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/optimize2bw.hh����������������������������������������������������������������0000644�0000764�0000764�00000002356�11436731020�015726� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2005 - 2009 René Rebe * (C) 2005 - 2007 Archivista GmbH, CH-8042 Zuerich * * 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. */ #ifndef OPTIMIZE2BW_HH #define OPTIMIZE2BW_HH #include "Image.hh" // Optimizes the image for b/w images. // It does not do the thresholding, the result is still 8 bit per pixel // so the caller can scale on the shaded data. // Threshold is not used, it just is a hint whether to use the more complex // color code-path. void optimize2bw (Image& image, int low = 0, int high = 0, int threshold = 0, int sloppy_threshold = 0, int radius = 3, double standard_deviation = 2.1); #endif // OPTIMIZE2BW_HH ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/scale.hh����������������������������������������������������������������������0000644�0000764�0000764�00000002475�12402076246�014552� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2014 René Rebe, ExactCODE GmbH Germany. * (C) 2006, 2007 Archivista GmbH, CH-8042 Zuerich * * 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. */ #ifndef SCALE_HH #define SCALE_HH // pick the best void scale (Image& image, double xscale, double yscale); // explicit versions void nearest_scale (Image& image, double xscale, double yscale); void box_scale (Image& image, double xscale, double yscale); void bilinear_scale (Image& image, double xscale, double yscale, bool fixed = false); void bicubic_scale (Image& image, double xscale, double yscale); void ddt_scale (Image& image, double xscale, double yscale, bool extended = true); void thumbnail_scale (Image& image, double xscale, double yscale); #endif ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/ContourMatching.hh������������������������������������������������������������0000644�0000764�0000764�00000004147�10632025775�016571� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "ContourUtility.hh" class LogoRepresentation { public: LogoRepresentation(Contours* logo_contours, unsigned int max_feature_no, unsigned int max_avg_tolerance, unsigned int reduction_shift, double maximum_angle, double angle_step); ~LogoRepresentation(); double Score(Contours* image); // updated after call to score std::pair<int, int> logo_translation; double rot_angle; std::vector< std::pair <Contours::Contour*, Contours::Contour*> > mapping; // logo contour, image contour // calculates the (unrotatated) logo translation after -rot_angle image rotation around (rx,ry) const std::pair<int, int>& CalculateInverseTranslation(int rx, int ry); std::pair<int, int> inverse_translation; protected: friend class MatchSorter; double N_M_Match(unsigned int set, unsigned int& pivot); double PrecisionScore(); void RotatedCentroidPosition(double& rx, double& ry); bool OptimizeAngle(double& score, double delta); bool OptimizeHTranslation(double& score, int delta); bool OptimizeVTranslation(double& score, int delta); bool Optimize(double& score); Contours* source; unsigned int tolerance; unsigned int shift; double rot_max; double rot_step; double centerx; double centery; unsigned int logo_set_count; unsigned int total_contour_length; class Match; struct LogoContourData { Contours::Contour* contour; double rx; double ry; std::vector <Match*> matches; unsigned int n_to_n_match_index; }; struct ImageContourData { Contours::Contour* contour; double rx; double ry; }; class Match { public: unsigned int length; double score; double transx; double transy; Contours::Contour* cimg; Match(const ImageContourData& image, const LogoContourData& logo, int tolerance, int shift, unsigned int original_logo_length, Contours::Contour* icimg); double TransScore(double tx, double ty); }; std::vector < std::vector <LogoContourData> > logo_sets; std::vector < unsigned int > logo_set_map; std::vector < ImageContourData > image_set; }; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/Matrix.hh���������������������������������������������������������������������0000644�0000764�0000764�00000003011�12452474057�014721� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Convolution Matrix. * Copyright (C) 2006 - 2015 René Rebe * Copyright (C) 2006 Archivista * * 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. * */ #ifndef MATRIX_HH #define MATRIX_HH #include "Image.hh" // any matrix and devisior // on my AMD Turion speed is: double > int > float // and in 32bit mode: double > float > int ? typedef double matrix_type; void convolution_matrix (Image& image, const matrix_type* matrix, int xw, int yw, matrix_type divisor); // convolution matrix code if matrix[i][j] is decomposable to h_matrix[i]*v_matrix[j] // the original image is multiplied with src_add and added to the result. void decomposable_convolution_matrix (Image& image, const matrix_type* h_matrix, const matrix_type* v_matrix, int xw, int yw, matrix_type src_add); // h_matrix contains entrys m[0]...m[xw]. It is assumed, that m[-i]=m[i]. Same for v_matrix. void decomposable_sym_convolution_matrix (Image& image, const matrix_type* h_matrix, const matrix_type* v_matrix, int xw, int yw, matrix_type src_add); #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/Contours.cc�������������������������������������������������������������������0000644�0000764�0000764�00000016211�11160526665�015263� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 Valentin Ziegler, ExactCODE GmbH Germany. * 2008 - 2009 Rene Rebe, ExactCODE GmbH Germany. * * 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 "Contours.hh" /* list of pixel traversals (clockwise order): 0: on left side upwards 1: on pixel top to the right 2: on right side downwards 3: on pixel bottom to the left */ // bitmask for pixel traversal - first bit is there to indicate foreground pixel const unsigned int pixelborder[4]={2,4,8,16}; struct StartCheck { int dx; int dy; }; const StartCheck startchecks[4]={ {-1,0}, {0,-1}, {1,0}, {0,1} }; struct Transition { int dx; int dy; unsigned int border; }; const Transition transitions[4][3]={ { {-1, -1, 3}, { 0, -1, 0}, {0, 0, 1} }, { { 1, -1, 0}, { 1, 0, 1}, {0, 0, 2} }, { { 1, 1, 1}, { 0, 1, 2}, {0, 0, 3} }, { {-1, 1, 2}, {-1, 0, 3}, {0, 0, 0} } }; inline bool Step(Contours::VisitMap& map, int& x, int& y, int& border) { for (unsigned int i=0; i<3; i++) { const Transition& t=transitions[border][i]; const int xx=x+t.dx; const int yy=y+t.dy; // do we have a foreground pixel ? if (xx >= 0 && xx < (signed int)map.w && yy >= 0 && yy < (signed int)map.h && map(xx,yy) > 0) { if ((map(xx,yy) & pixelborder[t.border]) == 0) { // go there x=xx; y=yy; border=t.border; map(x,y) |= pixelborder[border]; return true; } else // already been there before return false; } } // note: this code line is never reached, because last transition is always {0,0,b} return false; } inline bool Start(Contours::VisitMap& map, int x, int y, int border) { if ((map(x,y) & pixelborder[border]) == 0 ) { const StartCheck& c=startchecks[border]; const int xx=x+c.dx; const int yy=y+c.dy; // do we have a background pixel ? if (xx < 0 || xx >= (signed int)map.w || yy < 0 || yy >= (signed int)map.h || ((map(xx,yy) & 1) == 0)) { map(x,y)|=pixelborder[border]; return true; } } return false; } Contours::Contours(const FGMatrix& image) { VisitMap map(image.w, image.h); for (unsigned int x=0; x<map.w; x++) for (unsigned int y=0; y<map.h; y++) map(x,y)=(image(x,y)) ? 1 : 0; for (unsigned int x=0; x<map.w; x++) for (unsigned int y=0; y<map.h; y++) if (map(x,y) > 0) for (unsigned int border=0; border < 4; border++) if (Start(map,x,y,border)) { int xx=x; int yy=y; int bborder=border; Contour* current=new Contour(); contours.push_back(current); do { current->push_back(std::pair<unsigned int, unsigned int>(xx, yy)); } while (Step(map, xx, yy, bborder)); } } Contours::~Contours() { for (unsigned int i=0; i<contours.size(); i++) delete contours[i]; } MidContours::MidContours(const FGMatrix& image) { Contour* current = new Contour(); contours.push_back (current); // thru the whole "image" in x-direction for (unsigned int y = 0; y < image.h; y++) for (unsigned int x = 0; x < image.w; x++) { // something? if (image(x,y)) { // search end of region of scanline const unsigned int x1 = x++; while (x < image.w && image(x,y)) x++; // region [x1,x], midpoint mx: const unsigned int mx = (x1 + x) / 2; current->push_back(std::pair<unsigned int, unsigned int>(mx, y)); } } // thru the whole "image" in x-direction for (unsigned int x = 0; x < image.w; x++) for (unsigned int y = 0; y < image.h; y++) { // something? if (image(x,y)) { // search end of region of scanline const unsigned int y1 = y++; while (y < image.h && image(x,y)) y++; // region [y1,y], midpoint mx: const unsigned int my = (y1 + y) / 2; current->push_back(std::pair<unsigned int, unsigned int>(x, my)); } } // TODO: filter duplicates and/or clean spots without neighbour // TODO: sub-pixel accuracy would help } InnerContours::InnerContours(const FGMatrix& image) { VisitMap map(image.w, image.h); for (unsigned int x=0; x<map.w; x++) for (unsigned int y=0; y<map.h; y++) map(x,y) = 0; // distance to border for (unsigned int x=0; x<map.w; x++) for (unsigned int y=0; y<map.h; y++) if (image(x,y)) { int accu = 1; for (int r = 1; ; ++r) { int add = RecursiveDist(image, x, y, LEFT, r) + RecursiveDist(image, x, y, RIGHT, r) + RecursiveDist(image, x, y, UP, r) + RecursiveDist(image, x, y, DOWN, r); accu += add; if (add < 4) break; } map(x,y) = accu; } // only use local maxima VisitMap newmap(image.w, image.h); for (unsigned int x = 0; x < map.w; x++) for (unsigned int y = 0; y < map.h; y++) { newmap(x,y) = 0; int d = map(x,y); if (d == 0) continue; if (x > 0 && d < map(x-1, y)) continue; if (y > 0 && d < map(x, y-1)) continue; if (x+1 < map.w && d < map(x+1, y)) continue; if (y+1 < map.h && d < map(x, y+1)) continue; newmap(x,y) = 1; } for (unsigned int x = 0; x < map.w; x++) for (unsigned int y = 0; y < map.h; y++) { if (newmap (x,y)) { Contour* current = new Contour(); contours.push_back(current); RecursiveTrace (newmap, current, x, y); } } } bool InnerContours::RecursiveTrace(VisitMap& newmap, Contour* current, unsigned int x, unsigned int y) { if (newmap(x,y)) { newmap(x,y) = 0; current->push_back(std::pair<unsigned int, unsigned int>(x, y)); int x1 = x > 0 ? x-1 : 0, y1 = y > 0 ? y-1 : 0, x2 = x+1 < newmap.w ? x+1 : x, y2 = y+1 < newmap.h ? y+1 : y; if (RecursiveTrace (newmap, current, x, y2)) return true; if (RecursiveTrace (newmap, current, x1, y2)) return true; if (RecursiveTrace (newmap, current, x2, y2)) return true; if (RecursiveTrace (newmap, current, x2, y)) return true; if (RecursiveTrace (newmap, current, x2, y1)) return true; if (RecursiveTrace (newmap, current, x, y1)) return true; if (RecursiveTrace (newmap, current, x1, y1)) return true; if (RecursiveTrace (newmap, current, x1, y)) return true; return true; } return false; } unsigned int InnerContours::RecursiveDist(const FGMatrix& image, int x, int y, dir d, unsigned int r) { switch (d) { case LEFT: x -= r; if (x < 0) return 0; break; case UP: y -= r; if (y < 0) return 0; break; case RIGHT: x += r; if (x >= (int)image.w) return 0; break; case DOWN: y += r; if (y >= (int)image.h) return 0; break; } return image(x,y) ? 1 : 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/ImageIterator.hh��������������������������������������������������������������0000644�0000764�0000764�00000050400�11001707007�016174� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifdef CONST #define iterator const_iterator #else #define CONST #endif class iterator { public: CONST Image* image; type_t type; /* TODO: should be unsigned */ int stride, width, _x; ivalue_t value; value_t* ptr; signed int bitpos; // for 1bps sub-position // for seperate use, e.g. to accumulate iterator () {}; iterator (CONST Image* _image, bool end) : image (_image), type (_image->Type()), stride (_image->stride()), width (image->w) { if (!end) { ptr = (value_t*) image->getRawData(); _x = 0; bitpos = 7; } else { ptr = (value_t*) image->getRawDataEnd(); _x = width; // TODO: bitpos= ... } } value_t* end_ptr() const { return (value_t*) image->getRawDataEnd(); } inline void clear () { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray = 0; break; case RGB8A: value.rgba.a=0; case RGB8: case RGB16: value.rgb.r = value.rgb.g = value.rgb.b = 0; break; case CMYK8: value.cmyk.c = value.cmyk.m = value.cmyk.y = value.cmyk.k = 0; break; case YUV8: value.yuv.y = value.yuv.u = value.yuv.v = 0; break; default: WARN_UNHANDLED; } } inline iterator at (int x, int y) { iterator tmp = *this; switch (type) { case GRAY1: tmp.ptr = (value_t*) (image->data + stride * y + x / 8); tmp.bitpos = 7 - x % 8; tmp._x = x; break; case GRAY2: tmp.ptr = (value_t*) (image->data + stride * y + x / 4); tmp.bitpos = 7 - (x % 4) * 2; tmp._x = x; break; case GRAY4: tmp.ptr = (value_t*) (image->data + stride * y + x / 2); tmp.bitpos = 7 - (x % 2) * 4; tmp._x = x; break; case GRAY8: tmp.ptr = (value_t*) (image->data + stride * y + x); break; case GRAY16: tmp.ptr = (value_t*) (image->data + stride * y + x * 2); break; case RGB8: case YUV8: tmp.ptr = (value_t*) (image->data + stride * y + x * 3); break; case RGB8A: tmp.ptr = (value_t*) (image->data + stride * y + x * 4); break; case RGB16: tmp.ptr = (value_t*) (image->data + stride * y + x * 6); break; case CMYK8: tmp.ptr = (value_t*) (image->data + stride * y + x * 4); break; default: WARN_UNHANDLED; } return tmp; } inline iterator& operator* () { switch (type) { case GRAY1: value.gray = (ptr->gray >> (bitpos-0) & 0x01) * 255; break; case GRAY2: value.gray = (ptr->gray >> (bitpos-1) & 0x03) * 255/3; break; case GRAY4: value.gray = (ptr->gray >> (bitpos-3) & 0x0f) * 255/15; break; case GRAY8: value.gray = ptr->gray; break; case GRAY16: value.gray = ptr->gray16; break; case RGB8: value.rgb.r = ptr->rgb.r; value.rgb.g = ptr->rgb.g; value.rgb.b = ptr->rgb.b; break; case RGB8A: value.rgba.r = ptr->rgba.r; value.rgba.g = ptr->rgba.g; value.rgba.b = ptr->rgba.b; value.rgba.a = ptr->rgba.a; break; case RGB16: value.rgb.r = ptr->rgb16.r; value.rgb.g = ptr->rgb16.g; value.rgb.b = ptr->rgb16.b; break; case CMYK8: value.cmyk.c = ptr->cmyk.c; value.cmyk.m = ptr->cmyk.m; value.cmyk.y = ptr->cmyk.y; value.cmyk.k = ptr->cmyk.k; break; case YUV8: value.yuv.y = ptr->yuv.y; value.yuv.u = ptr->yuv.u; value.yuv.v = ptr->yuv.v; break; default: WARN_UNHANDLED; } return *this; } inline iterator& operator+= (const iterator& other) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray += other.value.gray; break; case RGB8: case RGB16: value.rgb.r += other.value.rgb.r; value.rgb.g += other.value.rgb.g; value.rgb.b += other.value.rgb.b; break; case RGB8A: value.rgba.r += other.value.rgba.r; value.rgba.g += other.value.rgba.g; value.rgba.b += other.value.rgba.b; value.rgba.a += other.value.rgba.a; break; case CMYK8: value.cmyk.c += other.value.cmyk.c; value.cmyk.m += other.value.cmyk.m; value.cmyk.y += other.value.cmyk.y; value.cmyk.k += other.value.cmyk.k; break; case YUV8: value.yuv.y += other.value.yuv.y; value.yuv.u += other.value.yuv.u; value.yuv.v += other.value.yuv.v; break; default: WARN_UNHANDLED; } return *this; } inline iterator operator+ (const iterator& other) const { iterator tmp = *this; return tmp += other; } inline iterator operator+ (int v) const { iterator tmp = *this; switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: tmp.value.gray += v; break; case RGB8: case RGB16: tmp.value.rgb.r += v; tmp.value.rgb.g += v; tmp.value.rgb.b += v; break; case RGB8A: tmp.value.rgba.r += v; tmp.value.rgba.g += v; tmp.value.rgba.b += v; tmp.value.rgba.a += v; break; case CMYK8: tmp.value.cmyk.c += v; tmp.value.cmyk.m += v; tmp.value.cmyk.y += v; tmp.value.cmyk.k += v; break; case YUV8: tmp.value.yuv.y += v; tmp.value.yuv.u += v; tmp.value.yuv.v += v; break; default: WARN_UNHANDLED; } return tmp; } inline iterator& operator-= (const iterator& other) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray -= other.value.gray; break; case RGB8: case RGB16: value.rgb.r -= other.value.rgb.r; value.rgb.g -= other.value.rgb.g; value.rgb.b -= other.value.rgb.b; break; case RGB8A: value.rgba.r -= other.value.rgba.r; value.rgba.g -= other.value.rgba.g; value.rgba.b -= other.value.rgba.b; value.rgba.a -= other.value.rgba.a; break; case CMYK8: value.cmyk.c -= other.value.cmyk.c; value.cmyk.m -= other.value.cmyk.m; value.cmyk.y -= other.value.cmyk.y; value.cmyk.k -= other.value.cmyk.k; break; case YUV8: value.yuv.y -= other.value.yuv.y; value.yuv.u -= other.value.yuv.u; value.yuv.v -= other.value.yuv.v; break; default: WARN_UNHANDLED; } return *this; } inline iterator& operator- (const iterator& other) const { iterator tmp = *this; return tmp -= other; } inline iterator& operator*= (const int v) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray *= v; break; case RGB8: case RGB16: value.rgb.r *= v; value.rgb.g *= v; value.rgb.b *= v; break; case RGB8A: value.rgba.r *= v; value.rgba.g *= v; value.rgba.b *= v; value.rgba.a *= v; break; case CMYK8: value.cmyk.c *= v; value.cmyk.m *= v; value.cmyk.y *= v; value.cmyk.k *= v; break; case YUV8: value.yuv.y *= v; value.yuv.u *= v; value.yuv.v *= v; break; default: WARN_UNHANDLED; } return *this; } inline iterator operator* (const int v) const { iterator tmp = *this; return tmp *= v; } inline iterator& operator/= (const int v) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray /= v; break; case RGB8: case RGB16: value.rgb.r /= v; value.rgb.g /= v; value.rgb.b /= v; break; case RGB8A: value.rgba.r /= v; value.rgba.g /= v; value.rgba.b /= v; value.rgba.a /= v; break; case CMYK8: value.cmyk.c /= v; value.cmyk.m /= v; value.cmyk.y /= v; value.cmyk.k /= v; break; case YUV8: value.yuv.y /= v; value.yuv.u /= v; value.yuv.v /= v; break; default: WARN_UNHANDLED; } return *this; } inline iterator& operator/ (const int v) const { iterator tmp = *this; return tmp /= v; } inline iterator& limit () { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: if (value.gray > 0xff) value.gray = 0xff; break; case RGB8: if (value.rgb.r > 0xff) value.rgb.r = 0xff; if (value.rgb.g > 0xff) value.rgb.g = 0xff; if (value.rgb.b > 0xff) value.rgb.b = 0xff; break; case RGB8A: if (value.rgba.r > 0xff) value.rgba.r = 0xff; if (value.rgba.g > 0xff) value.rgb.g = 0xff; if (value.rgba.b > 0xff) value.rgba.b = 0xff; if (value.rgba.a > 0xff) value.rgba.a = 0xff; break; case RGB16: if (value.rgb.r > 0xffff) value.rgb.r = 0xffff; if (value.rgb.g > 0xffff) value.rgb.g = 0xffff; if (value.rgb.b > 0xffff) value.rgb.b = 0xffff; break; default: WARN_UNHANDLED; } return *this; } //prefix inline iterator& operator++ () { switch (type) { case GRAY1: --bitpos; ++_x; if (bitpos < 0 || _x == width) { bitpos = 7; if (_x == width) _x = 0; ptr = (value_t*) ((uint8_t*) ptr + 1); } break; case GRAY2: bitpos -= 2; ++_x; if (bitpos < 0 || _x == width) { bitpos = 7; if (_x == width) _x = 0; ptr = (value_t*) ((uint8_t*) ptr + 1); } break; case GRAY4: bitpos -= 4; ++_x; if (bitpos < 0 || _x == width) { bitpos = 7; if (_x == width) _x = 0; ptr = (value_t*) ((uint8_t*) ptr + 1); } break; case GRAY8: ptr = (value_t*) ((uint8_t*) ptr + 1); break; case GRAY16: ptr = (value_t*) ((uint8_t*) ptr + 2); break; case RGB8: case YUV8: ptr = (value_t*) ((uint8_t*) ptr + 3); break; case RGB8A: ptr = (value_t*) ((uint8_t*) ptr + 4); break; case RGB16: ptr = (value_t*) ((uint8_t*) ptr + 6); break; case CMYK8: ptr = (value_t*) ((uint8_t*) ptr + 4); break; default: WARN_UNHANDLED; } return *this; } inline iterator& down() { switch (type) { case GRAY1: if ( (uint8_t*) ptr + stride >= (uint8_t*) end_ptr() ) { ptr = (value_t*) ((uint8_t*) image->data + (stride - ((uint8_t*) end_ptr() - (uint8_t*) ptr))); --bitpos; ++_x; if (bitpos < 0) { bitpos = 7; ptr = (value_t*) ((uint8_t*) ptr + 1); } else if (_x == width) { ptr = end_ptr(); } } else { ptr = (value_t*) ((uint8_t*) ptr + stride); } break; case GRAY2: if ( (uint8_t*) ptr + stride >= (uint8_t*) end_ptr() ) { ptr = (value_t*) ((uint8_t*) image->data + (stride - ((uint8_t*) end_ptr() - (uint8_t*) ptr))); bitpos -= 2; ++_x; if (bitpos < 0) { bitpos = 7; ptr = (value_t*) ((uint8_t*) ptr + 1); } else if (_x == width) { ptr = end_ptr(); } } else { ptr = (value_t*) ((uint8_t*) ptr + stride); } break; case GRAY4: if ( (uint8_t*) ptr + stride >= (uint8_t*) end_ptr() ) { ptr = (value_t*) ((uint8_t*) image->data + (stride - ((uint8_t*) end_ptr() - (uint8_t*) ptr))); bitpos -= 4; ++_x; if (bitpos < 0) { bitpos = 7; ptr = (value_t*) ((uint8_t*) ptr + 1); } else if (_x == width) { ptr = end_ptr(); } } else { ptr = (value_t*) ((uint8_t*) ptr + stride); } break; case GRAY8: if ( (uint8_t*) ptr + stride >= (uint8_t*) end_ptr() ) { if ( (uint8_t*) ptr + 1 >= (uint8_t*) end_ptr() ) ptr = end_ptr(); else ptr = (value_t*) ( (uint8_t*) image->data + (stride - ((uint8_t*) end_ptr() - (uint8_t*) ptr)) + 1); } else { ptr = (value_t*) ((uint8_t*) ptr + stride); } break; case GRAY16: if ( (uint8_t*) ptr + stride >= (uint8_t*) end_ptr() ) { if ( (uint8_t*) ptr + 2 >= (uint8_t*) end_ptr() ) ptr = end_ptr(); else ptr = (value_t*) ( (uint8_t*) image->data + (stride - ((uint8_t*) end_ptr() - (uint8_t*) ptr)) + 2); } else { ptr = (value_t*) ((uint8_t*) ptr + stride); } break; case RGB8: case YUV8: if ( (uint8_t*) ptr + stride >= (uint8_t*) end_ptr() ) { if ( (uint8_t*) ptr + 3 >= (uint8_t*) end_ptr() ) ptr = end_ptr(); else ptr = (value_t*) ( (uint8_t*) image->data + (stride - ((uint8_t*) end_ptr() - (uint8_t*) ptr)) + 3); } else { ptr = (value_t*) ((uint8_t*) ptr + stride); } break; case RGB8A: if ( (uint8_t*) ptr + stride >= (uint8_t*) end_ptr() ) { if ( (uint8_t*) ptr + 4 >= (uint8_t*) end_ptr() ) ptr = end_ptr(); else ptr = (value_t*) ( (uint8_t*) image->data + (stride - ((uint8_t*) end_ptr() - (uint8_t*) ptr)) + 4); } else { ptr = (value_t*) ((uint8_t*) ptr + stride); } break; case RGB16: if ( (uint8_t*) ptr + stride >= (uint8_t*) end_ptr() ) { if ( (uint8_t*) ptr + 6 >= (uint8_t*) end_ptr() ) ptr = end_ptr(); else ptr = (value_t*) ( (uint8_t*) image->data + (stride - ((uint8_t*) end_ptr() - (uint8_t*) ptr)) + 6); } else { ptr = (value_t*) ((uint8_t*) ptr + stride); } break; case CMYK8: if ( (uint8_t*) ptr + stride >= (uint8_t*) end_ptr() ) { if ( (uint8_t*) ptr + 4 >= (uint8_t*) end_ptr() ) ptr = end_ptr(); else ptr = (value_t*) ( (uint8_t*) image->data + (stride - ((uint8_t*) end_ptr() - (uint8_t*) ptr)) + 4); } else { ptr = (value_t*) ((uint8_t*) ptr + stride); } break; default: WARN_UNHANDLED; } return *this; } inline iterator& operator-- () { switch (type) { case GRAY1: ++bitpos; --_x; if (bitpos > 7) { bitpos = 0; ptr = (value_t*) ((uint8_t*) ptr - 1); } break; case GRAY2: bitpos += 2; --_x; if (bitpos > 7) { bitpos = 1; ptr = (value_t*) ((uint8_t*) ptr - 1); } break; case GRAY4: bitpos += 4; --_x; if (bitpos > 7) { bitpos = 3; ptr = (value_t*) ((uint8_t*) ptr - 1); } break; case GRAY8: ptr = (value_t*) ((uint8_t*) ptr - 1); break; case GRAY16: ptr = (value_t*) ((uint8_t*) ptr - 2); break; case RGB8: case YUV8: ptr = (value_t*) ((uint8_t*) ptr - 3); break; case RGB8A: ptr = (value_t*) ((uint8_t*) ptr - 4); break; case RGB16: ptr = (value_t*) ((uint8_t*) ptr - 6); break; case CMYK8: ptr = (value_t*) ((uint8_t*) ptr - 4); break; default: WARN_UNHANDLED; } return *this; } // return Luminance inline uint16_t getL () const { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: return value.gray; case RGB8A: // Todo: check that return (uint16_t) (.21267 * value.rgba.r + .71516 * value.rgba.g + .07217 * value.rgba.b); case RGB8: case RGB16: return (uint16_t) (.21267 * value.rgb.r + .71516 * value.rgb.g + .07217 * value.rgb.b); case CMYK8: return value.cmyk.k; // TODO case YUV8: return value.yuv.y; default: WARN_UNHANDLED; return 0; } } // return RGB inline void getRGB(uint16_t* r, uint16_t* g, uint16_t* b) const { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: *r = *g = *b = value.gray; break; case RGB8: case RGB16: *r = value.rgb.r; *g = value.rgb.g; *b = value.rgb.b; break; case RGB8A: *r = value.rgba.r; *g = value.rgba.g; *b = value.rgba.b; break; default: WARN_UNHANDLED; } } // return RGB inline void getRGB(double& r, double& g, double& b) const { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: r = g = b = (double)value.gray / 0xff; break; case GRAY16: r = g = b = (double)value.gray / 0xffff; break; case RGB8: r = (double)value.rgb.r / 0xff; g = (double)value.rgb.g / 0xff; b = (double)value.rgb.b / 0xff; break; case RGB8A: r = (double)value.rgba.r / 0xff; g = (double)value.rgba.g / 0xff; b = (double)value.rgba.b / 0xff; break; case RGB16: r = (double)value.rgb.r / 0xffff; g = (double)value.rgb.g / 0xffff; b = (double)value.rgb.b / 0xffff; break; default: WARN_UNHANDLED; } } // return RGBA inline void getRGBA(uint16_t* r, uint16_t* g, uint16_t* b, uint16_t* a) const { getRGB(r,g,b); switch (type) { case GRAY16: case RGB16: *a=0xffff; break; case RGB8A: *a=value.rgba.a; break; default: *a=0xff; } } // return RGB inline void getRGBA(double& r, double& g, double& b, double& a) const { getRGB(r,g,b); a=(type==RGB8A)? ((double)value.rgba.a / 0xff): 1.0; } inline void setL (uint16_t L) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray = L; break; case RGB8: case RGB16: value.rgb.r = value.rgb.g = value.rgb.b = L; break; case RGB8A: // Todo: check that value.rgba.r = value.rgba.g = value.rgba.b = L; break; case CMYK8: // TODO: value.cmyk.c = value.cmyk.m = value.cmyk.y = 0; value.cmyk.k = L; break; case YUV8: value.yuv.u = value.yuv.v = 0; value.yuv.y = L; break; } } // set RGB inline void setRGB(uint16_t r, uint16_t g, uint16_t b) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray = (int) (.21267 * r + .71516 * g + .07217 * b); break; case RGB8: case RGB16: value.rgb.r = r; value.rgb.g = g; value.rgb.b = b; break; case RGB8A: // Todo: check that value.rgba.r = r; value.rgba.g = g; value.rgba.b = b; break; default: WARN_UNHANDLED; } } // set RGB inline void setRGB(double r, double g, double b) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: value.gray = (int) ((.21267 * r + .71516 * g + .07217 * b) * 0xff); break; case GRAY16: value.gray = (int) ((.21267 * r + .71516 * g + .07217 * b) * 0xffff); break; case RGB8: value.rgb.r = (int) (r * 0xff); value.rgb.g = (int) (g * 0xff); value.rgb.b = (int) (b * 0xff); break; case RGB8A: // Todo: check that value.rgba.r = (int) (r * 0xff); value.rgba.g = (int) (g * 0xff); value.rgba.b = (int) (b * 0xff); break; case RGB16: value.rgb.r = (int) (r * 0xffff); value.rgb.g = (int) (g * 0xffff); value.rgb.b = (int) (b * 0xffff); break; default: WARN_UNHANDLED; } } // set RGBA inline void setRGBA(uint16_t r, uint16_t g, uint16_t b, uint16_t a) { setRGB(r,g,b); if (type==RGB8A) value.rgba.a=a; } // set RGBA inline void setRGBA(double r, double g, double b, double a) { setRGB(r,g,b); if (type==RGB8A) value.rgba.a=(int) (a * 0xff); } inline void set (const iterator& other) { switch (type) { case GRAY1: ptr->gray = (ptr->gray & (~(1<<bitpos))) | (other.value.gray >> 7) << bitpos; break; case GRAY2: ptr->gray = (ptr->gray & (~(3<<(bitpos-1)))) | (other.value.gray >> 6) << (bitpos-1); break; case GRAY4: ptr->gray = (ptr->gray & (~(15<<(bitpos-3)))) | (other.value.gray >> 4) << (bitpos-3); break; case GRAY8: ptr->gray = other.value.gray; break; case GRAY16: ptr->gray16 = other.value.gray; break; case RGB8: ptr->rgb.r = other.value.rgb.r; ptr->rgb.g = other.value.rgb.g; ptr->rgb.b = other.value.rgb.b; break; case RGB8A: ptr->rgba.r = other.value.rgba.r; ptr->rgba.g = other.value.rgba.g; ptr->rgba.b = other.value.rgba.b; ptr->rgba.a = other.value.rgba.a; break; case RGB16: ptr->rgb16.r = other.value.rgb.r; ptr->rgb16.g = other.value.rgb.g; ptr->rgb16.b = other.value.rgb.b; break; case CMYK8: ptr->cmyk.c = other.value.cmyk.c; ptr->cmyk.m = other.value.cmyk.m; ptr->cmyk.y = other.value.cmyk.y; ptr->cmyk.k = other.value.cmyk.k; break; case YUV8: ptr->yuv.y = other.value.yuv.y; ptr->yuv.u = other.value.yuv.u; ptr->yuv.v = other.value.yuv.v; break; default: WARN_UNHANDLED; } } bool operator != (const iterator& other) const { switch (type) { case GRAY1: case GRAY2: case GRAY4: return ptr != other.ptr && _x != other._x; default: return ptr != other.ptr; } } #ifndef iterator operator const_iterator () { const_iterator it (image, false); it._x = _x; it.bitpos = bitpos; it.ptr = ptr; return it; } #endif }; #undef iterator #undef CONST ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/empty-page.hh�����������������������������������������������������������������0000644�0000764�0000764�00000002447�12156356612�015536� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2005 - 2013 René Rebe * (C) 2005 - 2007 Archivista GmbH, CH-8042 Zuerich * * 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. */ // quickly counts pixels, returns whether set pixels are below // threshold and optionally can return the set pixels of all pixels // if the image is not 1 bit per pixel it will be optimized to b/w // (if you want more control over that call it yourself before) // the margin are the border pixels skipped, it must be a multiple // of 8 for speed reasons and will be rounded down to the next // multiple of 8 if necessary. #include "Image.hh" bool detect_empty_page (Image& image, double percent = 0.05, int marginH = 8, int marginV = 16, int* set_pixels = 0); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/low-level.hh������������������������������������������������������������������0000644�0000764�0000764�00000001465�11343176350�015367� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Misc. low-level helpers, usually to aid debugging. * Copyright (C) 2007 - 2010 Ren\xc3\xa9 Rebe, ExactCOD GmbH Germany * * 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 "Image.hh" void deinterlace (Image& image); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/ContourUtility.cc�������������������������������������������������������������0000644�0000764�0000764�00000022157�10767440606�016474� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "ContourUtility.hh" #include <cmath> #include <cstdlib> //#include <iostream> #include <assert.h> #include <stdio.h> void CenterAndReduce(const Contours::Contour& source, Contours::Contour& dest, unsigned int shift, // integer coordinate bit reduction double& drx, // returned centroid double& dry // returned centroid ) { unsigned int rx=0; unsigned int ry=0; unsigned int lastx=(unsigned int)-1; unsigned int lasty=(unsigned int)-1; for (unsigned int i=0; i<source.size(); i++) { unsigned int x=(int)source[i].first >> shift; unsigned int y=(int)source[i].second >> shift; if (x != lastx || y != lasty) { dest.push_back(std::pair<unsigned int, unsigned int>(x, y)); lastx=x; lasty=y; rx+=x; ry+=y; } } drx=((double) rx / (double) dest.size()); dry=((double) ry / (double) dest.size()); } void RotCenterAndReduce(const Contours::Contour& source, Contours::Contour& dest, double phi, // clockwise rotation in radians unsigned int add, // added to all coordinates to avoid negative values, // should be to set to image.w+image.h unsigned int shift, // integer coordinate bit reduction double& drx, // returned centroid double& dry // returned centroid ) { Contours::Contour tmp; double c=cos(phi); double s=sin(phi); int lastx=0; int lasty=0; for (unsigned int i=0; i<source.size(); i++) { double dx=(double)source[i].first; double dy=(double)source[i].second; double nx=c*dx - s*dy; double ny=s*dx + c*dy; int x=(int)nx + (int)add; int y=(int)ny + (int)add; // in case of gab, place an intermediate contour pixel if (i > 0 && (abs(x-lastx) > 1 || abs(y-lasty) > 1)) { tmp.push_back(std::pair<unsigned int, unsigned int>((x+lastx)/2, (y+lasty)/2)); } tmp.push_back(std::pair<unsigned int, unsigned int>(x,y)); lastx=x; lasty=y; } CenterAndReduce(tmp, dest, shift, drx, dry); } double L1Dist(const Contours::Contour& a, const Contours::Contour& b, double drax, // a centroid double dray, // a centroid double drbx, // b centroid double drby, // b centroid unsigned int shift, // reduction bits (in case a and b are reduced) or 0 double& transx, // returned translation for a double& transy // returned translation for a ) { double factor=(double)(1 << shift); transx= (drbx-drax)*factor; transy= (drby-dray)*factor; int dx= (int)(drbx-drax); int dy= (int)(drby-dray); double sum=.0; int best=1000000; int opt=0; int delta=0; int lastpos=0; //bool forward=true; for (unsigned int i=0; i<a.size(); i++) { if (i>0) { delta=abs((int)a[i].first-(int)a[i-1].first)+abs((int)a[i].second-(int)a[i-1].second); opt=best-delta; best+=delta; } int pos=lastpos; for (unsigned int j=0; j<b.size(); j++) { int current=abs(dx+(int)a[i].first-(int)b[pos].first)+abs(dy+(int)a[i].second-(int)b[pos].second); /* sanity check if (current < 0) { std::cout << "? " << current << "\t" << abs(dx+(int)a[i].first-(int)b[pos].first) << "\t" << abs(dy+(int)a[i].second-(int)b[pos].second) << std::endl; std::cout << dx << "\t" << (int)a[i].first << "\t" << (int)b[pos].first << std::endl; std::cout << dy << "\t" << (int)a[i].second << "\t" << (int)b[pos].second << std::endl; } */ if (current < best) { best=current; //forward=(pos>lastpos); lastpos=pos; if (best == opt) j=b.size(); } else if (current > best) { int skip=((current - best) - 1) / 2; j+=skip; pos+=skip; //(forward) ? skip : -skip; } //if (forward) { pos++; if (pos >= (int)b.size()) pos-=b.size(); //} else { // pos--; //if (pos < 0) // pos+=b.size(); //} } sum += best; } return sum*factor; } // not very efficient, yet effective static void PutPixel(Image& img, int x, int y, uint16_t R, uint16_t G, uint16_t B) { Image::iterator p=img.begin(); p=p.at(x,y); p.setRGB(R, G, B); p.set(p); } void DrawContour(Image& img, const Contours::Contour& c, unsigned int r, unsigned int g, unsigned int b) { for (unsigned int i=0; i<c.size(); i++) { PutPixel(img, c[i].first, c[i].second, r, g, b); } } void DrawTContour(Image& img, const Contours::Contour& c, unsigned int tx, unsigned int ty, unsigned int r, unsigned int g, unsigned int b) { for (unsigned int i=0; i<c.size(); i++) { int x=c[i].first+tx; int y=c[i].second+ty; if (x >= 0 && x <= img.w && y >= 0 && y <= img.h) PutPixel(img, x, y, r, g, b); } } /* void DrawContour(Image& img, const Contours::Contour& c, unsigned int r, unsigned int g, unsigned int b) { int xsum=0; int ysum=0; for (unsigned int i=0; i<c.size(); i++) { PutPixel(img, c[i].first, c[i].second, r, g, b); xsum+=c[i].first; ysum+=c[i].second; } xsum /= c.size(); ysum /= c.size(); for (int dx=-10; dx<=10; dx++) { int x=xsum+dx; int y=ysum; if (x >= 0 && x <= img.w && y >= 0 && y <= img.h) PutPixel(img, x,y, r, g, b); } for (int dy=-10; dy<=10; dy++) { int x=xsum; int y=ysum+dy; if (x >= 0 && x <= img.w && y >= 0 && y <= img.h) PutPixel(img,x,y, r, g, b); } Contours::Contour trash; double tx=0; double ty=0; CenterAndReduce(c,trash,3,tx,ty); xsum=(tx*8.0); ysum=(ty*8.0); for (int dx=-4; dx<=4; dx++) { int x=xsum+dx; int y=ysum; if (x >= 0 && x <= img.w && y >= 0 && y <= img.h) PutPixel(img, x,y, r, g, b); } for (int dy=-4; dy<=4; dy++) { int x=xsum; int y=ysum+dy; if (x >= 0 && x <= img.w && y >= 0 && y <= img.h) PutPixel(img,x,y, r, g, b); } } void DrawTContour(Image& img, const Contours::Contour& c, unsigned int tx, unsigned int ty, unsigned int r, unsigned int g, unsigned int b) { int xsum=0; int ysum=0; for (unsigned int i=0; i<c.size(); i++) { int x=c[i].first+tx; int y=c[i].second+ty; xsum+=x; ysum+=y; if (x >= 0 && x <= img.w && y >= 0 && y <= img.h) PutPixel(img, x, y, r, g, b); } xsum /= c.size(); ysum /= c.size(); for (int dx=-10; dx<=10; dx++) { int x=xsum+dx; int y=ysum; if (x >= 0 && x <= img.w && y >= 0 && y <= img.h) PutPixel(img, x,y, r, g, b); } for (int dy=-10; dy<=10; dy++) { int x=xsum; int y=ysum+dy; if (x >= 0 && x <= img.w && y >= 0 && y <= img.h) PutPixel(img,x,y, r, g, b); } Contours::Contour trash; double ddx=0; double ddy=0; CenterAndReduce(c,trash,3,ddx,ddy); xsum=tx+(ddx*8.0); ysum=ty+(ddy*8.0); for (int dx=-4; dx<=4; dx++) { int x=xsum+dx; int y=ysum; if (x >= 0 && x <= img.w && y >= 0 && y <= img.h) PutPixel(img, x,y, r, g, b); } for (int dy=-4; dy<=4; dy++) { int x=xsum; int y=ysum+dy; if (x >= 0 && x <= img.w && y >= 0 && y <= img.h) PutPixel(img,x,y, r, g, b); } } */ bool WriteContour(FILE* f, const Contours::Contour& source) { if (source.size() == 0) { if (fprintf(f, "! 0 0 0\n") < 0) return false; } else { unsigned int l=source.size(); int lastx=source[0].first; int lasty=source[0].second; if (fprintf(f, "! %d %d %d\n", lastx, lasty, l) < 0) return false; int code=0; for (unsigned int i=1; i<l; i++) { int currentx=source[i].first; int currenty=source[i].second; int caddx=1+currentx-lastx; int caddy=1+currenty-lasty; assert(caddx >=0 && caddx < 3); assert(caddy >=0 && caddy < 3); int cadd=caddx+(3*caddy); lastx=currentx; lasty=currenty; if (i % 2 == 1) code=cadd; else { code+=3*3*cadd; if (fputc('"'+(char) code, f) == EOF) return false; } } if (l % 2 == 0) { if (fputc('"'+(char) code, f)==EOF) return false; } if (fputc('\n', f) == EOF) return false; } return true; } bool ReadContour(FILE* f, Contours::Contour& dest) { int l; int x; int y; if (fscanf(f, "! %d %d %d\n", &x, &y, &l) != 3) return false; dest.resize(l); if (l == 0) return true; dest[0].first=x; dest[0].second=y; int c=0; for (unsigned int i=1; i<(unsigned int) l ; i++) { if (i % 2 == 1) { c=fgetc(f); if (c == EOF) return false; c-='"'; } else { c /= 3*3; } int dx=(c % 3) - 1; int dy=((c / 3) % 3) -1; x+=dx; y+=dy; dest[i].first=x; dest[i].second=y; } fgetc(f); // read linebreak; return true; } bool WriteContourArray(FILE* f, const std::vector <Contours::Contour*>& contours) { unsigned int n=contours.size(); if (fprintf(f, "CONTOURS v1 %d\n", n)<0) return false; for (unsigned int i=0; i<n; i++) if (!WriteContour(f,*(contours[i]))) return false; return true; } bool ReadContourArray(FILE* f, std::vector <Contours::Contour*>& contours) { unsigned int n=0; if (fscanf(f, "CONTOURS v1 %d\n", &n) != 1) { return false; } contours.resize(n); for (unsigned int i=0; i<n; i++) { contours[i]=new Contours::Contour; if (!ReadContour(f, *(contours[i]))) { for (unsigned int j=0; j<=i; j++) delete contours[j]; contours.clear(); return false; } } return true; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/segmentation.hh���������������������������������������������������������������0000644�0000764�0000764�00000003203�10651701126�016142� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Image Segmentation * Copyright (C) 2007 Valentin Ziegler and René Rebe * * 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. * */ #include <vector> #include "FG-Matrix.hh" class Segment { public: unsigned int x; unsigned int y; unsigned int w; unsigned int h; Segment* parent; std::vector <Segment*> children; Segment(unsigned int ix, unsigned int iy, unsigned int iw, unsigned int ih, Segment* iparent=0); ~Segment(); bool Subdivide(const FGMatrix& img, double tolerance, unsigned int min_length, bool horizontal); // Draws a (red) frame around the segment void Draw(Image& output, uint16_t r = 255, uint16_t g = 0, uint16_t b = 0); private: void InsertChild(unsigned int start, unsigned int end, bool horizontal); // count foreground pixels in horizontal/vertical lines unsigned int* Count(const FGMatrix& img, bool horizontal); }; // returns a segmentation of foreground matrix <img>. // <tolerance> is the maximum fraction of foreground pixels allowed in a separator line // <min_w> and <min_h> denote the minimum separator width and height Segment* segment_image(const FGMatrix& img, double tolerance, unsigned int min_w, unsigned int min_h); ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/Makefile����������������������������������������������������������������������0000644�0000764�0000764�00000000605�11274342466�014601� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include build/top.make BINARY = lib BINARY_EXT = $(X_LIBEXT) DEPS = # as fallback use the built-in Agg, we depend on it, ... CPPFLAGS += $(LIBAGGINCS) LDFLAGS += $(LIBAGGLIBS) ifeq "$(WITHFREETYPE)" "1" LDFLAGS += -laggfontfreetype endif ifeq "$(WITHFREETYPE)" "1" CPPFLAGS += $(FREETYPEINCS) LDFLAGS += $(FREETYPELIBS) endif CPPFLAGS += -I lib -I utility include build/bottom.make ���������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/rotate.hh���������������������������������������������������������������������0000644�0000764�0000764�00000002430�11770544063�014754� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2012 René Rebe, ExactCODE GmbH Germany. * (C) 2006, 2007 Archivista GmbH, CH-8042 Zuerich * * 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 "Image.hh" void flipX (Image& image); void flipY (Image& image); void rotate (Image& image, double angle, const Image::iterator& background); void exif_rotate(Image& image, unsigned exif_orientation); Image* copy_crop_rotate (Image& image, int x_start, int y_start, unsigned int w, unsigned int h, double angle, const Image::iterator& background); Image* copy_crop_rotate_nn (Image& image, int x_start, int y_start, unsigned int w, unsigned int h, double angle, const Image::iterator& background); ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/agg.hh������������������������������������������������������������������������0000644�0000764�0000764�00000031307�12357744041�014221� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Agg to ExactImage bridge. * Copyright (C) 2007 - 2014 René Rebe, ExactCODE GmbH, Germany * * 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 <agg_pixfmt_rgb.h> #include <agg_rendering_buffer.h> #include <agg_renderer_primitives.h> #include <agg_renderer_scanline.h> #include <agg_renderer_outline_aa.h> #include <agg_scanline_p.h> #include <agg_rasterizer_outline.h> #include <agg_rasterizer_outline_aa.h> #include <agg_rasterizer_scanline_aa.h> #include <agg_renderer_outline_aa.h> #include "Image.hh" using agg::cover_type; using agg::rect_i; /* ExactImage to Agg::renderer_* bridge. René Rebe. */ class renderer_exact_image { public: typedef agg::pixfmt_rgb24 pixfmt_type; typedef pixfmt_type::color_type color_type; typedef color_type::calc_type calc_type; typedef pixfmt_type::row_data row_data; class blender_exact_image { public: typedef color_type::value_type value_type; typedef color_type::calc_type calc_type; enum base_scale_e { base_shift = color_type::base_shift, base_mask = color_type::base_mask }; static inline void blend_pix(Image::iterator& it, unsigned cr, unsigned cg, unsigned cb, unsigned alpha, unsigned cover=0) { uint16_t r = 0, g = 0, b = 0, a = 0; *it; it.getRGBA (&r, &g, &b, &a); r = (value_type)(((cr - r) * alpha + (r << base_shift)) >> base_shift); g = (value_type)(((cg - g) * alpha + (g << base_shift)) >> base_shift); b = (value_type)(((cb - b) * alpha + (b << base_shift)) >> base_shift); a = (value_type)((alpha + a) - ((alpha * a + base_mask) >> base_shift)); it.setRGBA (r, g, b, a); it.set (it); //p[Order::A] = (value_type)((alpha + a) - ((alpha * a + base_mask) >> base_shift)); } }; typedef blender_exact_image blender_type; //-------------------------------------------------------------------- renderer_exact_image() : m_img (0), m_clip_box(1, 1, 0, 0) {} explicit renderer_exact_image(Image& img) : m_img (&img), m_clip_box (0, 0, m_img->w - 1, m_img->h - 1) {} void attach (Image& img) { m_img = &img; m_clip_box = rect_i (0, 0, m_img->w - 1, m_img->h - 1); } //-------------------------------------------------------------------- // const pixfmt_type& ren() const; // pixfmt_type& ren(); //-------------------------------------------------------------------- unsigned width() const { return m_img->w; } unsigned height() const { return m_img->h; } //-------------------------------------------------------------------- bool clip_box(int x1, int y1, int x2, int y2); //-------------------------------------------------------------------- void reset_clipping(bool visibility); //-------------------------------------------------------------------- void clip_box_naked(int x1, int y1, int x2, int y2); //-------------------------------------------------------------------- bool inbox(int x, int y) const; //-------------------------------------------------------------------- const rect_i& clip_box() const { return m_clip_box; } int xmin() const { return m_clip_box.x1; } int ymin() const { return m_clip_box.y1; } int xmax() const { return m_clip_box.x2; } int ymax() const { return m_clip_box.y2; } //-------------------------------------------------------------------- const rect_i& bounding_clip_box(); int bounding_xmin(); int bounding_ymin(); int bounding_xmax(); int bounding_ymax(); //-------------------------------------------------------------------- void clear(const color_type& c) { for (Image::iterator it = m_img->begin(), it_end = m_img->end(); it != it_end; ++it) { it.setRGB ((uint16_t)c.r, (uint16_t)c.g, (uint16_t)c.b); it.set(it); } } //-------------------------------------------------------------------- void copy_pixel(int x, int y, const color_type& c); //-------------------------------------------------------------------- void blend_pixel(int x, int y, const color_type& c, cover_type cover) { // used in solid, primitive lines Image::iterator it = m_img->begin(); it = it.at (x, y); blender_type::blend_pix(it, c.r, c.g, c.b, c.a, cover); } //-------------------------------------------------------------------- color_type pixel(int x, int y) const; //-------------------------------------------------------------------- void copy_hline(int x1, int y, int x2, const color_type& c); //-------------------------------------------------------------------- void copy_vline(int x, int y1, int y2, const color_type& c); //-------------------------------------------------------------------- void blend_hline(int x1, int y, int x2, const color_type& c, cover_type cover) { if(x1 > x2) { int t = x2; x2 = x1; x1 = t; } if(y > ymax()) return; if(y < ymin()) return; if(x1 > xmax()) return; if(x2 < xmin()) return; if(x1 < xmin()) x1 = xmin(); if(x2 > xmax()) x2 = xmax(); // m_ren->blend_hline(x1, y, x2 - x1 + 1, c, cover); int len = x2 - x1 + 1; if (c.a) { typedef color_type::calc_type calc_type; Image::iterator it = m_img->begin(); it = it.at (x1, y); calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; if(alpha == color_type::base_mask) { // ((value_type*)&v)[order_type::A] = c.a; it.setRGBA ((uint16_t)c.r, (uint16_t)c.g, (uint16_t)c.b, (uint16_t)c.a); do { it.set(it); ++it; // Note: assumes to keep the RGB value! } while(--len); } else { if(cover == 255) { do { blender_type::blend_pix(it, c.r, c.g, c.b, alpha); ++it; } while(--len); } else { do { blender_type::blend_pix(it, c.r, c.g, c.b, alpha, cover); ++it; } while(--len); } } } } //-------------------------------------------------------------------- void blend_vline(int x, int y1, int y2, const color_type& c, cover_type cover); //-------------------------------------------------------------------- void copy_bar(int x1, int y1, int x2, int y2, const color_type& c); //-------------------------------------------------------------------- void blend_bar(int x1, int y1, int x2, int y2, const color_type& c, cover_type cover); //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, int len, const color_type& c, const cover_type* covers) { if(y > ymax()) return; if(y < ymin()) return; if(x < xmin()) { len -= xmin() - x; if(len <= 0) return; covers += xmin() - x; x = xmin(); } if(x + len > xmax()) { len = xmax() - x + 1; if(len <= 0) return; } // m_ren->blend_solid_hspan(x, y, len, c, covers); if (c.a) { typedef color_type::calc_type calc_type; Image::iterator it = m_img->begin(); it = it.at (x, y); do { calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; if(alpha == color_type::base_mask) { it.setRGBA ((uint16_t)c.r, (uint16_t)c.g, (uint16_t)c.b, color_type::base_mask); it.set(it); } else { blender_type::blend_pix(it, c.r, c.g, c.b, alpha, *covers); } ++it; ++covers; } while(--len); } } //-------------------------------------------------------------------- void blend_solid_vspan(int x, int y, int len, const color_type& c, const cover_type* covers) { if(x > xmax()) return; if(x < xmin()) return; if(y < ymin()) { len -= ymin() - y; if(len <= 0) return; covers += ymin() - y; y = ymin(); } if(y + len > ymax()) { len = ymax() - y + 1; if(len <= 0) return; } // m_ren->blend_solid_vspan(x, y, len, c, covers); if (c.a) { typedef color_type::calc_type calc_type; Image::iterator it = m_img->begin(); do { it = it.at (x, y); calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; if(alpha == color_type::base_mask) { it.setRGBA ((uint16_t)c.r, (uint16_t)c.g, (uint16_t)c.b, color_type::base_mask); it.set(it); } else { blender_type::blend_pix(it, c.r, c.g, c.b, alpha, *covers); } ++y; ++covers; } while(--len); } } //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, int len, const color_type* colors); //-------------------------------------------------------------------- void copy_color_vspan(int x, int y, int len, const color_type* colors); //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, int len, const color_type* colors, const cover_type* covers, cover_type cover = agg::cover_full) { Image::iterator it = m_img->begin(); it = it.at (x, y); if (covers) { do { copy_or_blend_pix(it, *colors++, *covers++); ++it; } while(--len); } else { if (cover == 255) { do { copy_or_blend_pix(it, *colors++, 255); ++it; } while(--len); } else { do { copy_or_blend_pix(it, *colors++, cover); ++it; } while(--len); } } } //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, int len, const color_type* colors, const cover_type* covers, cover_type cover = agg::cover_full); //-------------------------------------------------------------------- rect_i clip_rect_area(rect_i& dst, rect_i& src, int wsrc, int hsrc) const; //-------------------------------------------------------------------- template<class RenBuf> void copy_from(const RenBuf& src, const rect_i* rect_src_ptr = 0, int dx = 0, int dy = 0); //-------------------------------------------------------------------- template<class SrcPixelFormatRenderer> void blend_from(const SrcPixelFormatRenderer& src, const rect_i* rect_src_ptr = 0, int dx = 0, int dy = 0, cover_type cover = agg::cover_full); //-------------------------------------------------------------------- template<class SrcPixelFormatRenderer> void blend_from_color(const SrcPixelFormatRenderer& src, const color_type& color, const rect_i* rect_src_ptr = 0, int dx = 0, int dy = 0, cover_type cover = agg::cover_full); //-------------------------------------------------------------------- template<class SrcPixelFormatRenderer> void blend_from_lut(const SrcPixelFormatRenderer& src, const color_type* color_lut, const rect_i* rect_src_ptr = 0, int dx = 0, int dy = 0, cover_type cover = agg::cover_full); private: inline void copy_or_blend_pix(Image::iterator& it, const color_type& c, unsigned cover) { if (c.a) { calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; if(alpha == color_type::base_mask) { it.setRGBA ((uint16_t)c.r, (uint16_t)c.g, (uint16_t)c.b, color_type::base_mask); it.set(it); } else { //m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); } } } Image* m_img; rect_i m_clip_box; }; typedef agg::pixfmt_rgb24 pixfmt; typedef renderer_exact_image renderer_base; /* render vector data */ typedef agg::renderer_primitives<renderer_base> renderer_prim; typedef agg::renderer_outline_aa<renderer_base> renderer_oaa; typedef agg::renderer_scanline_bin_solid<renderer_base> renderer_bin; typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_aa; /* raster into final buffer */ typedef agg::scanline_p8 scanline; typedef agg::rasterizer_outline<renderer_prim> rasterizer_outline; typedef agg::rasterizer_outline_aa<renderer_oaa> rasterizer_oaa; typedef agg::rasterizer_scanline_aa<> rasterizer_scanline; //typedef agg::pattern_filter_bilinear_rgba8 pattern_filter; //typedef agg::line_image_pattern_pow2<pattern_filter> image_pattern; //typedef agg::renderer_outline_image<renderer_base, image_pattern> renderer_img; //typedef agg::rasterizer_outline_aa<renderer_img> rasterizer_oimg; �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/Image.cc����������������������������������������������������������������������0000644�0000764�0000764�00000010111�12452531373�014457� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * The Plain Old Data encapsulation of pixel, raster data. * Copyright (C) 2005 - 2015 René Rebe * * 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 <string.h> // memcpy #include <iostream> #define DEPRECATED #include "Image.hh" #include "Codecs.hh" Image::Image () : modified(false), meta_modified(false), xres(0), yres(0), codec(0), data(0), w(0), h(0), bps(0), spp(0), rowstride(0) { } Image::Image (Image& other) : modified(false), meta_modified(false), xres(0), yres(0), codec(0), data(0), w(0), h(0), bps(0), spp(0), rowstride(0) { operator= (other); } Image::~Image () { // release attached codec if (codec) delete (codec); codec = 0; // release POD if (data) free (data); data = 0; } void Image::copyMeta (const Image& other) { w = other.w; h = other.h; bps = other.bps; spp = other.spp; rowstride = other.rowstride; xres = other.xres; yres = other.yres; } Image& Image::operator= (const Image& other) { uint8_t* d = other.getRawData(); copyMeta (other); resize (w, h, rowstride); // allocate if (d && data) { memcpy (data, d, stride() * h); } setRawData(); return *this; } void Image::copyTransferOwnership (Image& other) { copyMeta (other); uint8_t* d = other.getRawData(); other.setRawDataWithoutDelete (0); setRawData (d); } uint8_t* Image::getRawData () const { // ask codec about it if (!data && codec) { Image* image = const_cast<Image*>(this); codec->decodeNow (image); if (data) // if data was added image->modified = false; } return data; } uint8_t* Image::getRawDataEnd () const { // we call getRawData as it might have to query the codec to actually load it return getRawData() + h * stride(); } void Image::setRawData () { if (!modified) { // DEBUG // std::cerr << "Image modified" << std::endl; modified = true; } } void Image::setRawData (uint8_t* _data) { if (_data != data && data) { free (data); data = 0; } // reuse: setRawDataWithoutDelete (_data); } void Image::setRawDataWithoutDelete (uint8_t* _data) { data = _data; // reuse setRawData (); } void Image::resize (int _w, int _h, unsigned _stride) { std::swap(w, _w); std::swap(h, _h); std::swap(rowstride, _stride); uint8_t* ptr = (uint8_t*)::realloc(data, stride() * h); if (ptr) { setRawDataWithoutDelete(ptr); } else { // if non-zero size if (w * h != 0) { // restore w = _w; h = _h; rowstride = _stride; throw std::bad_alloc(); } } } void Image::realloc () { if (!data) return; // not yet loaded, delayed, no-op #if !defined(__APPLE__) resize(w, h); // realloc, supposed to shrink #else // the OS allocator may not shrink the buffer, though that may be important for the application, ... uint8_t* newdata = (uint8_t*)malloc(stride() * h); if (newdata) { memcpy(newdata, data, stride() * h); setRawData(newdata); } else { resize(w, h); // at least try realloc, ... } #endif } void Image::setDecoderID (const std::string& id) { decoderID = id; } const std::string& Image::getDecoderID () { return decoderID; } ImageCodec* Image::getCodec() { return codec; } void Image::setCodec (ImageCodec* _codec) { // do not reset, nor free when the same codec is re-sety if (codec == _codec) return; // release attached codec if (codec) { delete (codec); } codec = _codec; // at the moment the codec is attached the data recent, 0 on detach if (codec) { modified = meta_modified = false; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/Contours.hh�������������������������������������������������������������������0000644�0000764�0000764�00000003445�11162425462�015275� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 Valentin Ziegler, ExactCODE GmbH Germany. * 2008 - 2009 Rene Rebe, ExactCODE GmbH Germany. * * 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. */ #ifndef CONTOURS_HH #define CONTOURS_HH #include "FG-Matrix.hh" #include <vector> // "outline" contours class Contours { public: typedef std::vector < std::pair<unsigned int, unsigned int> > Contour; typedef DataMatrix<int> VisitMap; typedef std::vector<Contour*>::iterator iterator; Contours(const FGMatrix& image); Contours() {} // empty constructor for generic usage void clear (); void scan (const FGMatrix& image); ~Contours(); std::vector <Contour*> contours; }; // "midpoint of scanlines" inner storke /tracer/" class MidContours : public Contours { public: MidContours(const FGMatrix& image); }; // "local maxima of neighbor distance to border" class InnerContours : public Contours { typedef enum {LEFT, RIGHT, UP, DOWN} dir; unsigned int RecursiveDist(const FGMatrix& image, int x, int y, dir d, unsigned int r); bool RecursiveTrace(VisitMap& newmap, Contour* current, unsigned int x, unsigned int y); public: InnerContours(const FGMatrix& image); }; #endif // CONTOURS_HH ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/optimize2bw.cc����������������������������������������������������������������0000644�0000764�0000764�00000012634�12453267433�015730� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2005 - 2013 René Rebe, ExactCODE GmbH * (C) 2005 - 2007 Archivista GmbH, CH-8042 Zuerich * * 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. */ /* Short Description: * Any color-space to b/w (1-bit) optimization. Applications involving * huge amount of document archiving often prefer storing the data * as (compressed) b/w data even in the age of TB storage as higher * (color) image often explores the data volume exponentially. * * For this case this algorithm automatically determines a threshold * and performs some optimizations in order to loose as few details * as possible (e.g. retrieve hand notes, stamps, etc. but leave * the background color, coffee sparkels, dust and folding lines * out. * * While the first version only performed a unsharp mask and auto- * thresholding, the latest version does perform a segmentation-pass, * to optimize the performance (by leaving out empty areas) and * to keep dithering of image areas. */ #include <cstdlib> #include <cmath> #include <iostream> #include <iomanip> #ifdef _MSC_VER #include <vector> #endif #include "Image.hh" #include "Colorspace.hh" #include "Matrix.hh" #include "optimize2bw.hh" //#include "Timer.cc" void optimize2bw (Image& image, int low, int high, int threshold, int sloppy_threshold, int radius, double standard_deviation) { // do nothing if already at s/w, ... if (image.spp == 1 && image.bps == 1) return; /* Convert to RGB to gray. If the threshold is to be determined automatically, use color info. */ const bool debug = false; // color normalize on background color // search for background color { std::vector<std::vector<unsigned int> > hist = histogram(image); colorspace_by_name (image, "rgb8"); int lowest = 255, highest = 0, bg_r = 0, bg_g = 0, bg_b = 0; for (int i = 0; i <= 255; i++) { int r, g, b; r = g = b = hist[0][i]; if (hist.size() > 1) { g = hist[1][i]; b = hist[2][i]; } if (debug) std::cout << i << ": "<< r << " " << g << " " << b << std::endl; const int magic = 2; // magic denoise constant if (r >= magic || g >= magic || b >= magic) { if (i < lowest) lowest = i; if (i > highest) highest = i; } if (hist[0][i] > hist[0][bg_r]) bg_r = i; if (hist.size() > 1) { if (hist[1][i] > hist[1][bg_r]) bg_g = i; if (hist[2][i] > hist[2][bg_r]) bg_b = i; } else { bg_g = bg_b = i; } } highest = (int) (.21267 * bg_r + .71516 * bg_g + .07217 * bg_b); if (false) std::cerr << "lowest: " << lowest << ", highest: " << highest << ", back rgb: " << bg_r << " " << bg_g << " " << bg_b << std::endl; const int min_delta = 128; lowest = std::max (std::min (lowest, highest - min_delta), 0); highest = std::min (std::max (highest, lowest + min_delta), 255); if (low) lowest = low; if (high) highest = high; if (false) std::cerr << "after limit and overwrite, lowest: " << lowest << ", highest: " << highest << std::endl; signed int a = (255 * 256) / (highest - lowest); signed int b = (-a * lowest); if (false) std::cerr << "a: " << (float) a / 256 << " b: " << (float) b / 256 << std::endl; uint8_t* it = image.getRawData(); uint8_t* end = image.getRawDataEnd(); uint8_t* it2 = it; while (it != end) { int _r = *it++; int _g = *it++; int _b = *it++; _r = (_r * a + b) / 256; _g = (_g * a + b) / 256; _b = (_b * a + b) / 256; // clip _r = std::max (std::min (_r, 255), 0); _g = std::max (std::min (_g, 255), 0); _b = std::max (std::min (_b, 255), 0); // on-the-fly convert to gray with associated weighting *it2++ = (_r*28 + _g*59 + _b*11) / 100; } image.spp = 1; // converted data RGB8->GRAY8 image.setRawData(); } // Convolution Matrix (unsharp mask a-like) if (radius > 0) { // compute kernel (convolution matrix to move over the iamge) // Utility::AutoTimer<Utility::Timer> timer ("convolution"); matrix_type divisor = 0; float sd = standard_deviation; #ifdef _MSC_VER std::vector<matrix_type> matrix(radius+1); std::vector<matrix_type> matrix_2(radius+1); #else matrix_type matrix[radius+1]; matrix_type matrix_2[radius+1]; #endif for (int d = 0; d <= radius; ++d) { matrix_type v = (matrix_type) (exp (-((float)d*d) / (2. * sd * sd)) ); matrix[d] = v; divisor+=v; if (d>0) divisor+=v; } // normalize (will not work with integer matrix type !) divisor=1.0/divisor; for (int i=0; i<=radius; i++) { matrix[i]*=divisor; matrix_2[i]=-matrix[i]; } decomposable_sym_convolution_matrix (image, &matrix[0], &matrix_2[0], radius, radius, 2.0); } } ����������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/FG-Matrix.hh������������������������������������������������������������������0000644�0000764�0000764�00000002066�11014767041�015213� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Valentin Ziegler, ExactCODE GmbH Germany. * * 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. */ #ifndef FG_MATRIX_HH__ #define FG_MATRIX_HH__ #include "Image.hh" #include "DataMatrix.hh" class FGMatrix : public DataMatrix<bool> { public: FGMatrix(Image& image, unsigned int fg_threshold); FGMatrix(const FGMatrix& source); FGMatrix(const FGMatrix& source, unsigned int x, unsigned int y, unsigned int w, unsigned int h); ~FGMatrix(); }; #endif ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/hocr.hh�����������������������������������������������������������������������0000644�0000764�0000764�00000001646�11140010460�014375� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * The ExactImage library's hOCR to PDF parser * Copyright (C) 2008-2009 René Rebe, ExactCODE GmbH Germany * Copyright (C) 2008 Archivista * * 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. */ bool hocr2pdf(std::istream& hocrStream, PDFCodec* pdfContext, unsigned int res, bool sloppy = false, std::ostream* txtStream = 0); ������������������������������������������������������������������������������������������exact-image-0.9.1/lib/ContourUtility.hh�������������������������������������������������������������0000644�0000764�0000764�00000003536�10636510473�016501� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include "Contours.hh" void CenterAndReduce(const Contours::Contour& source, Contours::Contour& dest, unsigned int shift, // integer coordinate bit reduction double& drx, // returned centroid double& dry // returned centroid ); void RotCenterAndReduce(const Contours::Contour& source, Contours::Contour& dest, double phi, // clockwise rotation in radians unsigned int add, // added to all coordinates to avoid negative values, // should be at least image diagonal length unsigned int shift, // integer coordinate bit reduction double& drx, // returned centroid double& dry // returned centroid ); // realy fast summation of minimum L1-distance double L1Dist(const Contours::Contour& a, const Contours::Contour& b, double drxa, // a centroid double drxb, // a centroid double drya, // b centroid double dryb, // b centroid unsigned int shift, // reduction bits (in case a and b are reduced) or 0 double& transx, // returned translation for a double& transy // returned translation for a ); // plot contour in specified color // c coordinates must not be outside image range void DrawContour(Image& img, const Contours::Contour& c, unsigned int r, unsigned int g, unsigned int b); // plot translated contour // c coordinates may lie outside image void DrawTContour(Image& img, const Contours::Contour& c, unsigned int tx, unsigned int ty, unsigned int r, unsigned int g, unsigned int b); // functions to cache preprocessed contours on disk bool WriteContour(FILE* f, const Contours::Contour& source); bool ReadContour(FILE* f, Contours::Contour& dest); bool WriteContourArray(FILE* f, const std::vector <Contours::Contour*>& contours); bool ReadContourArray(FILE* f, std::vector <Contours::Contour*>& contours); ������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/crop.hh�����������������������������������������������������������������������0000644�0000764�0000764�00000001465�12341613504�014420� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Canvas cropping. * Copyright (C) 2006 - 2011 René Rebe, ExactCODE * * 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. */ void crop (Image& image, int x, int y, unsigned int w, unsigned int h); void fastAutoCrop (Image& image); �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/canvas.hh���������������������������������������������������������������������0000644�0000764�0000764�00000001404�11556323200�014717� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2009-2011 René Rebe, ExactCODE GmbH Germany. * * 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 "Image.hh" void append (Image& image, Image& other); ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/hocr.cc�����������������������������������������������������������������������0000644�0000764�0000764�00000027740�11140354543�014403� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * The ExactImage library's hOCR to PDF parser * Copyright (C) 2008-2009 René Rebe, ExactCODE GmbH Germany * Copyright (C) 2008 Archivista * * 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 <string.h> #include <iostream> #include <fstream> #include <iomanip> #include <cmath> #include <cctype> #include <vector> #include "ArgumentList.hh" #include "config.h" #include "Codecs.hh" #include "pdf.hh" #include "hocr.hh" using namespace Utility; static int res = 300; static bool sloppy = false; static PDFCodec* pdfContext = 0; static std::ostream* txtStream = 0; static std::string txtString; std::string lowercaseStr(const std::string& _s) { std::string s(_s); std::transform(s.begin(), s.end(), s.begin(), tolower); return s; } // custom copy to trip newlines, likewise bool isMyBlank(char c) { switch (c) { case ' ': case '\t': case '\r': case '\n': return true; break; default: return false; } } std::string peelWhitespaceStr(const std::string& _s) { std::string s(_s); // trailing whitespace for (int i = s.size() - 1; i >= 0 && isMyBlank(s[i]); --i) s.erase(i, 1); // leading whitespace while (!s.empty() && isMyBlank(s[0])) s.erase(0, 1); return s; } // lower-case, and strip leading/trailing white-space std::string sanitizeStr(const std::string& _s) { return peelWhitespaceStr(lowercaseStr(_s)); } // HTML decode std::string htmlDecode(const std::string& _s) { std::string s(_s); std::string::size_type i; while ((i = s.find("&")) != std::string::npos) s.replace(i, 5, "&"); while ((i = s.find("<")) != std::string::npos) s.replace(i, 4, "<"); while ((i = s.find(">")) != std::string::npos) s.replace(i, 4, ">"); while ((i = s.find(""")) != std::string::npos) s.replace(i, 6, "\""); // TODO: '&8212;' and more - when implemented, best locked on // each '&' and matched to the next ';' return s; } // state per char: bbox, bold, italic, boldItalic // state per line: bbox, align: left, right justified struct BBox { BBox() : x1(0), y1(0), x2(0), y2(0) {} bool operator== (const BBox& other) { return x1 == other.x1 && y1 == other.y1 && x2 == other.x2 && y2 == other.y2; } double x1, y1, x2, y2; } lastBBox; std::ostream& operator<< (std::ostream& s, const BBox& b) { s << b.x1 << ", " << b.y1 << ", " << b.x2 << ", " << b.y2; return s; } enum Style { None = 0, Bold = 1, Italic = 2, BoldItalic = (Bold | Italic) } lastStyle; std::ostream& operator<< (std::ostream& s, const Style& st) { switch (st) { case Bold: s << "Bold"; break; case Italic: s << "Italic"; break; case BoldItalic: s << "BoldItalic"; break; default: s << "None"; break; } return s; } // TODO: implement parsing, if of any guidance for the PDF enum Align { Left = 0, Right = 1, Justify = 2, } lastAlign; struct Span { BBox bbox; Style style; std::string text; }; struct Textline { std::vector<Span> spans; typedef std::vector<Span>::iterator span_iterator; void draw() { double y1 = 0, y2 = 0, yavg = 0; int n = 0; for (span_iterator it = spans.begin(); it != spans.end(); ++it, ++n) { if (it == spans.begin()) { y1 = it->bbox.y1; yavg = y2 = it->bbox.y2; } else { if (it->bbox.y1 < y1) y1 = it->bbox.y1; if (it->bbox.y2 > y2) y2 = it->bbox.y2; yavg += it->bbox.y2; } } if (n > 0) yavg /= n; int height = (int)round(std::abs(y2 - y1) * 72. / res); if (height < 8) // TODO: allow configuration? height = 8; //std::cerr << "drawing with height: " << height << std::endl; // remove trailing whitespace for (span_iterator it = spans.end(); it != spans.begin(); --it) { span_iterator it2 = it; --it2; for (int i = it2->text.size() - 1; i >= 0; --i) { if (isMyBlank(it2->text[i])) it2->text.erase(i); else goto whitespace_cleaned; } } whitespace_cleaned: for (span_iterator it = spans.begin(); it != spans.end(); ++it, ++n) { // escape decoding, TODO: maybe change our SAX parser to emmit a single // text element, and thus decode it earlier std::string text = htmlDecode(it->text); BBox bbox = it->bbox; // one might imprecicely place text sloppily in favour of "sometimes" // improved cut'n paste-able text in not so advanced PDF Viewers if (sloppy) { span_iterator it2 = it; for (++it2; it2 != spans.end(); ++it2) { if (it->style != it2->style) break; std::string nextText = htmlDecode(it2->text); // TODO: in theory expand bbox, if later needed text += nextText; // stop on whitespaces to sync on gaps in justified text if (nextText != peelWhitespaceStr(nextText)) { ++it2; // we consumed the glyph, so proceeed break; } } it = --it2; } const char* font = "Helvetica"; switch (it->style) { case Bold: font = "Helvetica-Bold"; break; case Italic: font = "Helvetica-Oblique"; break; case BoldItalic: font = "Helvetica-BoldOblique"; break; default: ; // already initialized } //std::cerr << "(" << text << ") "; pdfContext->textTo(72. * bbox.x1 / res, 72. * yavg / res); pdfContext->showText(font, text, height); if (txtStream) txtString += text; } if (txtStream) txtString += "\n"; //std::cerr << std::endl; } void flush() { if (!spans.empty()) draw(); spans.clear(); } void push_back(Span s) { //std::cerr << "push_back (" << s.text << ") " << s.style << std::endl; // do not insert newline garbage (empty string after white- // space peeling) at the beginning of a line if (spans.empty()) { s.text = peelWhitespaceStr(s.text); if (s.text.empty()) return; } // if the direction wrapps, assume new line if (!spans.empty() && s.bbox.x1 < spans.back().bbox.x1) flush(); // unify inserted spans with same properties, for now to // not draw them at the same position, but one text operator if (!spans.empty() && (spans.back().bbox == s.bbox) && (spans.back().style == s.style)) spans.back().text += s.text; else spans.push_back(s); } } textline; BBox parseBBox(std::string s) { BBox b; // self initialized to zero const char* tS = "title=\""; std::string::size_type i = s.find(tS); if (i == std::string::npos) return b; std::string::size_type i2 = s.find("\"", i + strlen(tS)); if (i2 == std::string::npos) return b; std::stringstream stream(s.substr(i + strlen(tS), i2 - i - strlen(tS))); std::string dummy; stream >> dummy >> b.x1 >> b.y1 >> b.x2 >> b.y2; return b; } void elementStart(const std::string& _name, const std::string& _attr = "") { std::string name(sanitizeStr(_name)), attr(sanitizeStr(_attr)); //std::cerr << "elementStart: '" << name << "', attr: '" << attr << "'" << std::endl; BBox b = parseBBox(attr); if (b.x2 > 0 && b.y2 > 0) lastBBox = b; if (name == "b" || name == "strong") lastStyle = Style(lastStyle | Bold); else if (name == "i" || name == "em") lastStyle = Style(lastStyle | Italic); } void elementText(const std::string& text) { //std::cerr << "elementText: \"" << text << "\"" << std::endl; Span s; s.bbox = lastBBox; s.style = lastStyle; s.text += text; textline.push_back(s); } void elementEnd(const std::string& _name) { std::string name (sanitizeStr(_name)); //std::cerr << "elementEnd: " << name << std::endl; if (name == "b" || name == "strong") lastStyle = Style(lastStyle & ~Bold); else if (name == "i" || name == "em") lastStyle = Style(lastStyle & ~Italic); // explicitly flush line of text on manual preak or end of paragraph else if (name == "br" || name == "p") textline.flush(); } // returns the string before the first whitespace std::string tagName(std::string t) { std::string::size_type i = t.find(' '); if (i != std::string::npos) t.erase(i); return t; } bool hocr2pdf(std::istream& hocrStream, PDFCodec* pdfContext, unsigned int res, bool sloppy, std::ostream* txtStream) { // TODO: soft hyphens // TODO: better text placement, using one TJ with spacings // TODO: more image compressions, jbig2, Fax // TODO: do not use global vars, use a state container ::pdfContext = pdfContext; ::res = res; ::sloppy = sloppy; ::txtStream = txtStream; pdfContext->beginText(); // minimal, cuneiform HTML ouptut parser char c; std::vector<std::string> openTags; std::string* curTag = 0; std::string closingTag; while (hocrStream.get(c), hocrStream.good()) { // consume tag element text if (curTag && c != '>') { *curTag += c; continue; } switch (c) { case '<': if (hocrStream.peek() != '/') { openTags.push_back(""); curTag = &openTags.back(); } else { closingTag.clear(); curTag = &closingTag; } break; case '>': if (curTag != &closingTag) { bool closed = false; if (!curTag->empty() && curTag->at(curTag->size() - 1) == '/') { curTag->erase(curTag->size() - 1); closed = true; } // HTML asymetric tags, TODO: more of those (and !DOCTYPE)? // TODO: maybe specially treat meta & co? { std::string lowTag = lowercaseStr(tagName(*curTag)); if (lowTag == "br" || lowTag == "img" || lowTag == "meta") closed = true; } //std::cout << "tag start: " << openTags.back() // << (closed ? " immediately closed" : "") << std::endl; { std::string element = tagName(*curTag); std::string attr = *curTag; attr.erase(0, element.size()); elementStart(element, attr); } if (closed) { elementEnd(*curTag); openTags.pop_back(); } } else { // garuanteed to begin with a /, remove it curTag->erase(0, 1); // get just the tag name from the stack std::string lastOpenTag = (openTags.empty() ? "" : openTags.back()); lastOpenTag = tagName(lastOpenTag); if (lastOpenTag != *curTag) { std::cout << "Warning: tag mismatch: '" << *curTag << "' can not close last open: '" << lastOpenTag << "'" << std::endl; } else openTags.pop_back(); elementEnd(*curTag); } curTag = 0; break; default: elementText(std::string(1, c)); break; } } while (!openTags.empty()) { std::string tag = tagName(openTags.back()); openTags.pop_back(); // skip special tags such as !DOCTYPE if (tag.empty() || tag[0] != '!') std::cerr << "Warning: unclosed tag: '" << tag << "'" << std::endl; } textline.flush(); pdfContext->endText(); if (txtStream) { // for now hypenation compensator, later to be inserted to the // generic code-flow to detect and write out soft-hypens on-the-go // regex: ([a-z])-\n([a-z]) -> \1\2 // + insert \n at next space of next line for (std::string::iterator it = txtString.begin(); it != txtString.end();) { if ((*it == '\n') && // lock on newlines (it != txtString.begin() && it[-1] == '-') && // hyphen in front (it != txtString.end() - 1 && islower(it[+1])) // and the next is lower case ) { it = txtString.erase(it -1, it + 1); // erase "\n-" // so, newline removed, insert a break at the next word, same line for (; it != txtString.end() && *it != '\n'; ++it) { if (*it == ' ') { *it = '\n'; ++it; break; } } } else ++it; } *txtStream << txtString; } return true; // or error } ��������������������������������exact-image-0.9.1/lib/empty-page.cc�����������������������������������������������������������������0000644�0000764�0000764�00000005333�12205140177�015511� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2005 - 2013 René Rebe * (C) 2005 - 2007 Archivista GmbH, CH-8042 Zuerich * * 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 <iostream> #include "Image.hh" #include "Colorspace.hh" #include "Matrix.hh" #include "empty-page.hh" #include "optimize2bw.hh" /* TODO: for more accurance one could introduce a hot-spot area that has a higher weight than the other (outer) region to more reliably detect crossed but otherwise empty pages */ bool detect_empty_page (Image& im, double percent, int marginH, int marginV, int* set_pixels) { // sanitize margins if (marginH % 8 != 0) marginH -= marginH % 8; // TODO: optimize not to copy the pixel data on colorspace conversion Image image; image = im; // already in sub-byte domain? just count the black pixels if (image.spp == 1 && (image.bps > 1 && image.bps < 8)) { colorspace_by_name (image, "gray1"); } // if not 1-bit, yet: convert it down ... else if (image.spp != 1 || image.bps != 1) { // don't care about cmyk vs. rgb, just get gray8 pixels, quickly colorspace_by_name (image, "gray8"); // force quick pass, no color use, 1px radius optimize2bw (image, 0, 0, 128, 0, 1); // convert to 1-bit (threshold) - optimize2bw does not perform that step ... colorspace_gray8_to_gray1 (image); } // count bits and decide based on that // create a fast bit count lookup table int bits_set[256] = { 0 }; for (int i = 0; i < 256; i++) { int bits = 0; for (int j = i; j != 0; j >>= 1) { bits += (j & 0x01); } bits_set[i] = bits; } int stride = (image.w * image.bps * image.spp + 7) / 8; // count pixels by table lookup int pixels = 0; uint8_t* data = image.getRawData(); for (int row = marginV; row < image.h - marginV; ++row) { for (int x = marginH/8; x < stride - marginH/8; ++x) { int b = bits_set [ data[stride*row + x] ]; // it is a bits_set table - and we want the zeros ... pixels += 8-b; } } float image_percent = (float)pixels/(image.w*image.h) * 100; if (set_pixels) *set_pixels = pixels; return image_percent < percent; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/rotate.cc���������������������������������������������������������������������0000644�0000764�0000764�00000027612�12467377771�014771� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2015 René Rebe, ExactCODE GmbH Germany. * (C) 2006, 2007 Archivista GmbH, CH-8042 Zuerich * * 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 <math.h> #include <iostream> #include <iomanip> #include "Image.hh" #include "ImageIterator2.hh" #include "Codecs.hh" #include "rotate.hh" void flipX (Image& image) { // thru the codec? if (!image.isModified() && image.getCodec()) if (image.getCodec()->flipX(image)) return; const unsigned stride = image.stride(); uint8_t* data = image.getRawData(); switch (image.spp * image.bps) { case 1: case 2: case 4: { // create a reversed bit table for fast lookup uint8_t reversed_bits[256]; const int bps = image.bps; const int mask = (1 << bps) - 1; for (int i = 0; i < 256; ++i) { uint8_t rev = 0, v = i; for (int j = 0; j < 8/bps; ++j) { rev = (rev << bps) | (v & mask); v >>= bps; } reversed_bits[i] = rev; } for (int y = 0; y < image.h; ++y) { uint8_t* row = &data [y*stride]; for (int x = 0; x < stride/2; ++x) { uint8_t v = row [x]; row[x] = reversed_bits [row[stride - 1 - x]]; row[stride - 1 - x] = reversed_bits[v]; } // TODO: this still needs to be fixed for stride < 1 byte! if (stride & 1) // uneven? center-byte: row[stride/2] = reversed_bits[row[stride/2]]; } } break; case 8: case 16: case 24: case 32: case 48: { const unsigned int bytes = image.spp * image.bps / 8; for (int y = 0; y < image.h; ++y) { uint8_t* ptr1 = &data[y * stride]; uint8_t* ptr2 = ptr1 + stride - bytes; for (; ptr1 < ptr2; ptr2 -= 2 * bytes) { for (unsigned b = 0; b < bytes; b++) { uint8_t v = *ptr1; *ptr1++ = *ptr2; *ptr2++ = v; } } } } break; default: std::cerr << "flipX: unsupported depth." << std::endl; return; } image.setRawData(); } void flipY (Image& image) { // thru the codec? if (!image.isModified() && image.getCodec()) if (image.getCodec()->flipY(image)) return; const unsigned int bytes = image.stride(); uint8_t* data = image.getRawData(); for (int y = 0; y < image.h / 2; ++y) { int y2 = image.h - y - 1; uint8_t* row1 = &data[y * bytes]; uint8_t* row2 = &data[y2 * bytes]; for (unsigned x = 0; x < bytes; ++x) { uint8_t v = *row1; *row1++ = *row2; *row2++ = v; } } image.setRawData(); } void rot90 (Image& image, int angle) { bool cw = false; // clock-wise if (angle == 90) cw = true; // else 270 or -90 or whatever and thus counter cw int rot_stride = (image.h * image.spp * image.bps + 7) / 8; uint8_t* data = image.getRawData(); uint8_t* rot_data = (uint8_t*) malloc(rot_stride * image.w); switch (image.spp * image.bps) { case 1: case 2: case 4: { const int bps = image.bps; const int spb = 8 / bps; // Samples Per Byte const uint8_t mask = 0xF00 >> bps; // std::cerr << "mask: " << (int)mask << std::endl; for (int y = 0; y < image.h; ++y) { uint8_t* new_row; if (cw) new_row = &rot_data [ (image.h - 1 - y) / spb ]; else new_row = &rot_data [ (image.w - 1) * rot_stride + y / spb ]; for (int x = 0; x < image.w;) { // spread the bits thru the various row slots uint8_t bits = *data++; int i = 0; for (; i < spb && x < image.w; ++i) { if (cw) { *new_row = *new_row >> bps | (bits & mask); new_row += rot_stride; } else { *new_row = *new_row << bps | (bits & mask) >> (8-bps); new_row -= rot_stride; } bits <<= bps; ++x; } // finally shift the last line if necessary // TODO: recheck this residual bit for correctness if (i < spb) { if (cw) { new_row -= rot_stride; *new_row = *new_row >> (8 - (bps*i)); } else { new_row += rot_stride; *new_row = *new_row << (8 - (bps*i)); } bits <<= 1; ++x; } } } } break; case 8: case 16: case 24: case 32: case 48: { const int bps = (image.bps + 7) / 8 * image.spp; // bytes... for (int y = 0; y < image.h; ++y) { uint8_t* new_row = cw ? &rot_data[(image.h - 1 - y) * bps] : &rot_data[(image.w - 1) * rot_stride + (y * bps)]; for (int x = 0; x < image.w; ++x) { for (int i = 0; i < bps; ++i) *new_row++ = *data++; new_row += cw ? rot_stride - bps : -rot_stride - bps; } } } break; default: std::cerr << "rot90: unsupported depth. spp: " << image.spp << ", bpp:" << image.bps << std::endl; free (rot_data); return; } // we are done, tweak the w/h int x = image.w; image.w = image.h; image.h = x; // resolution, likewise image.setResolution(image.resolutionY(), image.resolutionX()); // set the new data image.setRawData (rot_data); } template <typename T> struct rotate_template { void operator() (Image& image, double angle, const Image::iterator& background) { angle = angle / 180 * M_PI; const int xcent = image.w / 2; const int ycent = image.h / 2; Image orig_image; orig_image.copyTransferOwnership(image); image.resize (image.w, image.h); const float cached_sin = sin (angle); const float cached_cos = cos (angle); #pragma omp parallel for schedule (dynamic, 16) for (int y = 0; y < image.h; ++y) { T it (image); it.at(0, y); for (int x = 0; x < image.w; ++x) { float ox = (x - xcent) * cached_cos + (y - ycent) * cached_sin; float oy = - (x - xcent) * cached_sin + (y - ycent) * cached_cos; ox += xcent; oy += ycent; typename T::accu a; if (ox >= 0 && oy >= 0 && ox < image.w && oy < image.h) { int oxx = (int)floor(ox); int oyy = (int)floor(oy); int oxx2 = std::min (oxx + 1, image.w - 1); int oyy2 = std::min (oyy + 1, image.h - 1); int xdist = (int) ((ox - oxx) * 256); int ydist = (int) ((oy - oyy) * 256); T orig_it (orig_image); a = (*orig_it.at(oxx, oyy)) * ((256 - xdist) * (256 - ydist)); a += (*orig_it.at(oxx2, oyy)) * (xdist * (256 - ydist)); a += (*orig_it.at(oxx, oyy2)) * ((256 - xdist) * ydist); a += (*orig_it.at(oxx2, oyy2)) * (xdist * ydist); a /= (256 * 256); } else a = (background); it.set (a); ++it; } } image.setRawData (); } }; void rotate (Image& image, double angle, const Image::iterator& background) { angle = fmod (angle, 360); if (angle < 0) angle += 360; if (angle == 0.0) return; // thru the codec? if (!image.isModified() && image.getCodec()) if (image.getCodec()->rotate(image, angle)) return; if (angle == 180.0) { flipX (image); flipY (image); return; } if (angle == 90.0) { rot90 (image, 90); return; } if (angle == 270.0) { rot90 (image, 270); return; } codegen<rotate_template> (image, angle, background); } void exif_rotate(Image& image, unsigned exif_orientation) { Image::iterator bgrd(image.begin()); // not used //std::cerr << exif_orientation << std::endl; switch (exif_orientation) { case 0: // undefined, but handled as NOP case 1: // top, left side break; case 2: // top, rigth side flipX(image); break; case 3: // bottom, rigth side rotate(image, 180, bgrd); break; case 4: // bottom, left side flipY(image); break; case 5: // left side, top rotate(image, -90, bgrd); break; // tested case 6: // right side, top rotate(image, 90, bgrd); break; // tested case 7: // right side, bottom rotate(image, 90, bgrd); flipX(image); break; case 8: // left side, bottom rotate(image, -90, bgrd); break; // tested default: std::cerr << "unknown exif orientation: " << exif_orientation << std::endl; } } template <typename T> struct copy_crop_rotate_template { Image* operator() (Image& image, int x_start, int y_start, unsigned int w, unsigned int h, double angle, const Image::iterator& background) { angle = fmod (angle, 360); if (angle < 0) angle += 360; // trivial code just for testing, to be optimized angle = angle / 180 * M_PI; Image* new_image = new Image; new_image->copyMeta (image); new_image->resize (w, h); const float cached_sin = sin (angle); const float cached_cos = cos (angle); #pragma omp parallel for schedule (dynamic, 16) for (unsigned int y = 0; y < h; ++y) { T it (*new_image); T src (image); it.at(0, y); for (unsigned int x = 0; x < w; ++x) { const float ox = ( (float)x * cached_cos + (float)y * cached_sin) + x_start; const float oy = (-(float)x * cached_sin + (float)y * cached_cos) + y_start; typename T::accu a1; if (ox >= 0 && oy >= 0 && ox < image.w && oy < image.h) { const int sx = (int)floor(ox); const int sy = (int)floor(oy); const int sxx = std::min (sx+1, image.w-1); const int syy = std::min (sy+1, image.h-1); const int xdist = (int) ((ox - sx) * 256); const int ydist = (int) ((oy - sy) * 256); a1 = (*src.at (sx, sy )) * ((256-xdist)); a1 += (*src.at (sxx, sy )) * (xdist ); a1 /= 256; typename T::accu a2; a2 = (*src.at (sx, syy)) * ((256-xdist)); a2 += (*src.at (sxx, syy)) * (xdist ); a2 /= 256; a1 = a1 * (256-ydist) + a2 * ydist; a1 /= 256; } else a1 = (background); it.set(a1); ++it; } } return new_image; } }; Image* copy_crop_rotate (Image& image, int x_start, int y_start, unsigned int w, unsigned int h, double angle, const Image::iterator& background) { return codegen_return<Image*, copy_crop_rotate_template> (image, x_start, y_start, w, h, angle, background); } template <typename T> struct copy_crop_rotate_nn_template { Image* operator() (Image& image, int x_start, int y_start, unsigned int w, unsigned int h, double angle, const Image::iterator& background) { angle = fmod (angle, 360); if (angle < 0) angle += 360; // trivial code just for testing, to be optimized angle = angle / 180 * M_PI; Image* new_image = new Image; new_image->copyMeta (image); new_image->resize (w, h); const float cached_sin = sin (angle); const float cached_cos = cos (angle); #pragma omp parallel for schedule (dynamic, 16) for (unsigned int y = 0; y < h; ++y) { T it (*new_image); it.at(0, y); for (unsigned int x = 0; x < w; ++x) { const int ox = ( (float)x * cached_cos + (float)y * cached_sin) + x_start; const int oy = (-(float)x * cached_sin + (float)y * cached_cos) + y_start; T orig_it (image); typename T::accu a; if (ox >= 0 && oy >= 0 && ox < image.w && oy < image.h) { a = *orig_it.at(ox, oy); } else a = (background); it.set (a); ++it; } } return new_image; } }; Image* copy_crop_rotate_nn (Image& image, int x_start, int y_start, unsigned int w, unsigned int h, double angle, const Image::iterator& background) { return codegen_return<Image*, copy_crop_rotate_nn_template> (image, x_start, y_start, w, h, angle, background); } ����������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/GaussianBlur.hh���������������������������������������������������������������0000644�0000764�0000764�00000001444�10741671331�016055� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Gaussian Blur. * Copyright (C) 2008, Valentin Ziegler * * 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. * */ #ifndef GAUSSIAN_BLUR_HH #define GAUSSIAN_BLUR_HH #include "Image.hh" // when radius <= 0, then an optimal radius for sd is used void GaussianBlur(Image& image, double standard_deviation, int radius=0); #endif ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/Image2.hh���������������������������������������������������������������������0000644�0000764�0000764�00000030135�10550234425�014556� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#ifndef IMAGE2_HH #define IMAGE2_HH #include <inttypes.h> // the more optimizing next-gen Image::iterator DRAFT #include "Image.hh" // the Plain Old Data image /* Colorspace: GRAY, GRAYA, RGB, RGBA, CMYK, YUV, YUVA Bit depth: INT1 INT2 INT4 INT8 INT16 INT32 FLOAT32 FLOAT64 */ /* Operations: begin end ++ -- at += -= /= */ typedef enum { GRAY, GRAYA, RGB, RGBA, CMYK, YUV, } type_t; template<class T, class bps> class iterator2 { public: Image* image; int stride, width, _x; ivalue_t value; value_t* ptr; signed int bitpos; // for 1bps sub-position // for seperate use, e.g. to accumulate iterator2 () {}; iterator2 (Image* _image, bool end) : image (_image), type (_image->Type()), stride (_image->Stride()), width (image->w) { if (!end) { ptr = (value_t*) image->data; _x = 0; bitpos = 7; } else { ptr = (value_t*) (image->data + stride * image->h); _x = width; // TODO: bitpos= ... } } inline void clear () { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray = 0; break; case RGB8: case RGB16: value.rgb.r = value.rgb.g = value.rgb.b = 0; break; case CMYK8: value.cmyk.c = value.cmyk.m = value.cmyk.y = value.cmyk.k = 0; break; case YUV8: value.yuv.y = value.yuv.u = value.yuv.v = 0; break; } } inline iterator2 at (int x, int y) { iterator2 tmp = *this; switch (type) { case GRAY1: tmp.ptr = (value_t*) (image->data + stride * y + x / 8); tmp.bitpos = 7 - x % 8; break; case GRAY2: tmp.ptr = (value_t*) (image->data + stride * y + x / 4); tmp.bitpos = 7 - (x % 4) * 2; break; case GRAY4: tmp.ptr = (value_t*) (image->data + stride * y + x / 2); tmp.bitpos = 7 - (x % 2) * 4; break; case GRAY8: tmp.ptr = (value_t*) (image->data + stride * y + x); break; case GRAY16: tmp.ptr = (value_t*) (image->data + stride * y + x * 2); break; case RGB8: case YUV8: tmp.ptr = (value_t*) (image->data + stride * y + x * 3); break; case RGB16: tmp.ptr = (value_t*) (image->data + stride * y + x * 6); break; case CMYK8: tmp.ptr = (value_t*) (image->data + stride * y + x * 4); break; } return tmp; } inline iterator2& operator* () { switch (type) { case GRAY1: value.gray = (ptr->gray >> (bitpos-0) & 0x01) * 255; break; case GRAY2: value.gray = (ptr->gray >> (bitpos-1) & 0x03) * 255/3; break; case GRAY4: value.gray = (ptr->gray >> (bitpos-3) & 0x0f) * 255/15; break; case GRAY8: value.gray = ptr->gray; break; case GRAY16: value.gray = ptr->gray16; break; case RGB8: value.rgb.r = ptr->rgb.r; value.rgb.g = ptr->rgb.g; value.rgb.b = ptr->rgb.b; break; case RGB16: value.rgb.r = ptr->rgb16.r; value.rgb.g = ptr->rgb16.g; value.rgb.b = ptr->rgb16.b; break; case CMYK8: value.cmyk.c = ptr->cmyk.c; value.cmyk.m = ptr->cmyk.m; value.cmyk.y = ptr->cmyk.y; value.cmyk.k = ptr->cmyk.k; break; case YUV8: value.yuv.y = ptr->yuv.y; value.yuv.u = ptr->yuv.u; value.yuv.v = ptr->yuv.v; break; } return *this; } inline iterator2& operator+= (const iterator2& other) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray += other.value.gray; break; case RGB8: case RGB16: value.rgb.r += other.value.rgb.r; value.rgb.g += other.value.rgb.g; value.rgb.b += other.value.rgb.b; break; case CMYK8: value.cmyk.c += other.value.cmyk.c; value.cmyk.m += other.value.cmyk.m; value.cmyk.y += other.value.cmyk.y; value.cmyk.k += other.value.cmyk.k; break; case YUV8: value.yuv.y += other.value.yuv.y; value.yuv.u += other.value.yuv.u; value.yuv.v += other.value.yuv.v; break; } return *this; } inline iterator2 operator+ (const iterator2& other) const { iterator2 tmp = *this; return tmp += other; } inline iterator2 operator+ (int v) const { iterator2 tmp = *this; switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: tmp.value.gray += v; break; case RGB8: case RGB16: tmp.value.rgb.r += v; tmp.value.rgb.g += v; tmp.value.rgb.b += v; break; case CMYK8: tmp.value.cmyk.c += v; tmp.value.cmyk.m += v; tmp.value.cmyk.y += v; tmp.value.cmyk.k += v; break; case YUV8: tmp.value.yuv.y += v; tmp.value.yuv.u += v; tmp.value.yuv.v += v; break; } return tmp; } inline iterator2& operator-= (const iterator2& other) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray -= other.value.gray; break; case RGB8: case RGB16: value.rgb.r -= other.value.rgb.r; value.rgb.g -= other.value.rgb.g; value.rgb.b -= other.value.rgb.b; break; case CMYK8: value.cmyk.c -= other.value.cmyk.c; value.cmyk.m -= other.value.cmyk.m; value.cmyk.y -= other.value.cmyk.y; value.cmyk.k -= other.value.cmyk.k; break; case YUV8: value.yuv.y -= other.value.yuv.y; value.yuv.u -= other.value.yuv.u; value.yuv.v -= other.value.yuv.v; break; } return *this; } inline iterator2& operator- (const iterator2& other) const { iterator2 tmp = *this; return tmp -= other; } inline iterator2& operator*= (const int v) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray *= v; break; case RGB8: case RGB16: value.rgb.r *= v; value.rgb.g *= v; value.rgb.b *= v; break; case CMYK8: value.cmyk.c *= v; value.cmyk.m *= v; value.cmyk.y *= v; value.cmyk.k *= v; break; case YUV8: value.yuv.y *= v; value.yuv.u *= v; value.yuv.v *= v; break; } return *this; } inline iterator2 operator* (const int v) const { iterator2 tmp = *this; return tmp *= v; } inline iterator2& operator/= (const int v) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray /= v; break; case RGB8: case RGB16: value.rgb.r /= v; value.rgb.g /= v; value.rgb.b /= v; break; case CMYK8: value.cmyk.c /= v; value.cmyk.m /= v; value.cmyk.y /= v; value.cmyk.k /= v; break; case YUV8: value.yuv.y /= v; value.yuv.u /= v; value.yuv.v /= v; break; } return *this; } inline iterator2& operator/ (const int v) const { iterator2 tmp = *this; return tmp /= v; } inline iterator2& limit () { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: if (value.gray > 0xff) value.gray = 0xff; break; case RGB8: if (value.rgb.r > 0xff) value.rgb.r = 0xff; if (value.rgb.g > 0xff) value.rgb.g = 0xff; if (value.rgb.b > 0xff) value.rgb.b = 0xff; break; case RGB16: if (value.rgb.r > 0xffff) value.rgb.r = 0xffff; if (value.rgb.g > 0xffff) value.rgb.g = 0xffff; if (value.rgb.b > 0xffff) value.rgb.b = 0xffff; break; } return *this; } //prefix inline iterator2& operator++ () { switch (type) { case GRAY1: --bitpos; ++_x; if (bitpos < 0 || _x == width) { bitpos = 7; if (_x == width) _x = 0; ptr = (value_t*) ((uint8_t*) ptr + 1); } break; case GRAY2: bitpos -= 2; ++_x; if (bitpos < 0 || _x == width) { bitpos = 7; if (_x == width) _x = 0; ptr = (value_t*) ((uint8_t*) ptr + 1); } break; case GRAY4: bitpos -= 4; ++_x; if (bitpos < 0 || _x == width) { bitpos = 7; if (_x == width) _x = 0; ptr = (value_t*) ((uint8_t*) ptr + 1); } break; case GRAY8: ptr = (value_t*) ((uint8_t*) ptr + 1); break; case GRAY16: ptr = (value_t*) ((uint8_t*) ptr + 2); break; case RGB8: case YUV8: ptr = (value_t*) ((uint8_t*) ptr + 3); break; case RGB16: ptr = (value_t*) ((uint8_t*) ptr + 6); break; case CMYK8: ptr = (value_t*) ((uint8_t*) ptr + 4); break; } return *this; } inline iterator2& operator-- () { switch (type) { case GRAY1: ++bitpos; --_x; if (bitpos > 7) { bitpos = 0; ptr = (value_t*) ((uint8_t*) ptr - 1); } break; case GRAY2: bitpos += 2; --_x; if (bitpos > 7) { bitpos = 1; ptr = (value_t*) ((uint8_t*) ptr - 1); } break; case GRAY4: bitpos += 4; --_x; if (bitpos > 7) { bitpos = 3; ptr = (value_t*) ((uint8_t*) ptr - 1); } break; case GRAY8: ptr = (value_t*) ((uint8_t*) ptr - 1); break; case GRAY16: ptr = (value_t*) ((uint8_t*) ptr - 2); break; case RGB8: case YUV8: ptr = (value_t*) ((uint8_t*) ptr - 3); break; case RGB16: ptr = (value_t*) ((uint8_t*) ptr - 6); break; case CMYK8: ptr = (value_t*) ((uint8_t*) ptr - 4); break; } return *this; } // return Luminance inline uint16_t getL () { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: return value.gray; break; case RGB8: case RGB16: return (uint16_t) (.21267 * value.rgb.r + .71516 * value.rgb.g + .07217 * value.rgb.b); break; case CMYK8: return value.cmyk.k; // TODO break; case YUV8: return value.yuv.y; break; } } // return Luminance inline void getRGB(uint16_t* r, uint16_t* g, uint16_t* b) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: *r = *g = *b = value.gray; return; break; case RGB8: case RGB16: *r = value.rgb.r; *g = value.rgb.g; *b = value.rgb.b; return; break; case CMYK8: // TODO break; case YUV8: // TODO break; } } // set Luminance inline void setL (uint16_t L) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray = L; break; case RGB8: case RGB16: value.rgb.r = value.rgb.g = value.rgb.b = L; break; case CMYK8: // TODO: value.cmyk.c = value.cmyk.m = value.cmyk.y = 0; value.cmyk.k = L; break; case YUV8: value.yuv.u = value.yuv.v = 0; value.yuv.y = L; break; } } // set RGB inline void setRGB(uint16_t r, uint16_t g, uint16_t b) { switch (type) { case GRAY1: case GRAY2: case GRAY4: case GRAY8: case GRAY16: value.gray = (int) (.21267 * r + .71516 * g + .07217 * b); return; break; case RGB8: case RGB16: value.rgb.r = r; value.rgb.g = g; value.rgb.b = b; return; break; case CMYK8: // TODO break; case YUV8: // TODO break; } } inline void set (const iterator2& other) { switch (type) { case GRAY1: ptr->gray |= (other.value.gray >> 7) << bitpos; break; case GRAY2: ptr->gray |= (other.value.gray >> 6) << (bitpos-1); break; case GRAY4: ptr->gray |= (other.value.gray >> 4) << (bitpos-3); break; case GRAY8: ptr->gray = other.value.gray; break; case GRAY16: ptr->gray16 = other.value.gray; break; case RGB8: ptr->rgb.r = other.value.rgb.r; ptr->rgb.g = other.value.rgb.g; ptr->rgb.b = other.value.rgb.b; break; case RGB16: ptr->rgb16.r = other.value.rgb.r; ptr->rgb16.g = other.value.rgb.g; ptr->rgb16.b = other.value.rgb.b; break; case CMYK8: ptr->cmyk.c = other.value.cmyk.c; ptr->cmyk.m = other.value.cmyk.m; ptr->cmyk.y = other.value.cmyk.y; ptr->cmyk.k = other.value.cmyk.k; break; case YUV8: ptr->yuv.y = other.value.yuv.y; ptr->yuv.u = other.value.yuv.u; ptr->yuv.v = other.value.yuv.v; break; } } bool operator != (const iterator2& other) { switch (type) { case GRAY1: case GRAY2: case GRAY4: return ptr != other.ptr && _x != other._x; case GRAY8: case GRAY16: case RGB8: case RGB16: case CMYK8: case YUV8: return ptr != other.ptr; } } }; #endif �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/utils.hh����������������������������������������������������������������������0000644�0000764�0000764�00000000470�10373352262�014614� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� inline void ycbcr_to_rgb( int ycbcr[3], int* const ret ) { int dummy[3] = { (int)((1/1.772) * (ycbcr[0] + 1.402 * ycbcr[2])), (int)((1/1.772) * (ycbcr[0] - 0.34413 * ycbcr[1] - 0.71414 * ycbcr[2])), (int)((1/1.772) * (ycbcr[0] + 1.772 * ycbcr[1])) }; for( int k = 0; k < 3; ++k ) ret[k] = dummy[k]; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/agg.cc������������������������������������������������������������������������0000644�0000764�0000764�00000001462�11352362142�014176� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Agg to ExactImage bridge. * Copyright (C) 2007 - 2010 René Rebe, ExactCODE GmbH, Germany * * 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 "agg.hh" #include "Image.hh" // the big methods later go here, ... ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/Colorspace.cc�����������������������������������������������������������������0000644�0000764�0000764�00000067455�12464375565�015572� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Colorspace conversions. * Copyright (C) 2006 - 2015 René Rebe, ExactCOD GmbH Germany * Copyright (C) 2007 Susanne Klaus, ExactCODE * * 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 <iostream> #include <map> #include <vector> #include "Image.hh" #include "ImageIterator2.hh" #include "Codecs.hh" #include "Colorspace.hh" #include "Endianess.hh" template <typename T> struct histogram_template { std::vector<std::vector<unsigned int> > operator() (Image& image, int bins = 256) { std::vector<std::vector<unsigned int> > hist; hist.resize(image.spp); typename T::accu a; for (int i = 0; i < image.spp; ++i) hist[i].resize(bins, 0); typename T::accu one = T::accu::one(); T it (image); for (int y = 0; y < image.h; ++y) { for (int x = 0; x < image.w; ++x, ++it) { a = *it; for (int i = 0; i < image.spp; ++i) { typename T::accu::vtype v = a.v[i]; int j = (int)(v * (bins-1) / one.v[i]); if (j < 0) j = 0; else if (j >= bins) j = bins - 1; hist[i][j]++; } } } return hist; } }; std::vector<std::vector<unsigned int> > histogram(Image& image, int bins) { return codegen_return<std::vector<std::vector<unsigned int> >, histogram_template> (image, bins); } template <typename T> struct normalize_template { void operator() (Image& image, uint8_t l, uint8_t h) { typename T::accu a; typename T::accu::vtype black(0), white(0); // darkest 1%, lightest .5% const int white_point = image.w * image.h / 100; const int black_point = white_point / 2; { // TODO: fall back to map for HDR types typedef std::vector<typename T::accu::vtype> histogram_type; typename T::accu::vtype hsize; T::accu::one().getL(hsize); histogram_type histogram(hsize + 1); T it (image); typename T::accu::vtype l; for (int y = 0; y < image.h; ++y) { for (int x = 0; x < image.w; ++x) { a = *it; a.getL(l); // TODO: create discrete interval for floats etc. histogram[l]++; ++it; } } // find suitable black and white points int count = 0, ii = 0; for (typename histogram_type::iterator i = histogram.begin(); i != histogram.end(); ++i, ++ii) { count += *i; if (count >= black_point) { black = ii; break; } } count = 0; ii = 255; for (typename histogram_type::reverse_iterator i = histogram.rbegin(); i != histogram.rend(); ++i, --ii) { count += *i; if (count >= white_point) { white = ii; break; } } } // TODO: scale to type range if (l) black = l; if (h) white = h; typename T::accu::vtype fa, fb = -black; T::accu::one().getL(fa); fa *= 256; // shift for interger multiplication fa /= (white - black); T it (image); for (int y = 0; y < image.h; ++y) { for (int x = 0; x < image.w; ++x) { a = *it; a += fb; a *= fa; a /= 256; a.saturate(); it.set (a); ++it; } } image.setRawData(); } }; void normalize (Image& image, uint8_t l, uint8_t h) { codegen<normalize_template> (image, l, h); } void colorspace_rgba8_to_rgb8 (Image& image) { unsigned ostride = image.stride(); image.spp = 3; image.rowstride = 0; for (int y = 0; y < image.h; ++y) { uint8_t* output = image.getRawData() + y * image.stride(); uint8_t* it = image.getRawData() + y * ostride; for (int x = 0; x < image.w; ++x) { *output++ = *it++; *output++ = *it++; *output++ = *it++; it++; // skip over a } } image.resize(image.w, image.h); // realloc } void colorspace_argb8_to_rgb8 (Image& image) { uint8_t* data = image.getRawData(); unsigned ostride = image.stride(); image.spp = 3; image.rowstride = 0; for (int y = 0; y < image.h; ++y) { uint8_t* output = data + y * image.stride(); uint8_t* it = data + y * ostride; for (int x = 0; x < image.w; ++x) { it++; // skip over a *output++ = *it++; *output++ = *it++; *output++ = *it++; } } image.resize(image.w, image.h); // realloc } void colorspace_cmyk_to_rgb8 (Image& image) { uint8_t* data = image.getRawData(); unsigned ostride = image.stride(); image.spp = 3; image.rowstride = 0; for (int y = 0; y < image.h; ++y) { uint8_t* output = data + y * image.stride(); uint8_t* it = data + y * ostride; for (int x = 0; x < image.w; ++x, it += 4, output += 3) { uint8_t c = it[0], m = it[1], y = it[2], k = it[3]; output[0] = 0xff - std::min(c+k, 0xff); // ((0xff-c)*(0xff-k)) >> 8; output[1] = 0xff - std::min(m+k, 0xff); // ((0xff-m)*(0xff-k)) >> 8; output[2] = 0xff - std::min(y+k, 0xff); // ((0xff-y)*(0xff-k)) >> 8; } } image.resize(image.w, image.h); // realloc } void colorspace_rgb8_to_gray8 (Image& image, const int bytes, const int wR, const int wG, const int wB) { unsigned ostride = image.stride(); image.spp = 1; image.rowstride = 0; const int sum = wR + wG + wB; for (int y = 0; y < image.h; ++y) { uint8_t* output = image.getRawData() + y * image.stride(); uint8_t* it = image.getRawData() + y * ostride; for (int x = 0; x < image.w; ++x, it += bytes) { // R G B order and associated weighting int c = (int)it[0] * wR; c += (int)it[1] * wG; c += (int)it[2] * wB; *output++ = (uint8_t)(c / sum); } } image.resize(image.w, image.h); // realloc } void colorspace_rgb16_to_gray16 (Image& image) { unsigned ostride = image.stride(); image.spp = 1; image.rowstride = 0; for (int y = 0; y < image.h; ++y) { uint16_t* output = (uint16_t*)(image.getRawData() + y * image.stride()); uint16_t* it = (uint16_t*)image.getRawData() + y * ostride; for (int x = 0; x < image.w; ++x) { // R G B order and associated weighting int c = (int)*it++ * 28; c += (int)*it++ * 59; c += (int)*it++ * 11; *output++ = (uint16_t)(c / 100); } } image.resize(image.w, image.h, image.stride()); // realloc } void colorspace_rgb8_to_rgb8a (Image& image, uint8_t alpha) { image.setRawDataWithoutDelete ((uint8_t*)realloc(image.getRawData(), image.w * 4 * image.h)); image.setSamplesPerPixel(4); // reverse copy with alpha fill inside the buffer uint8_t* it_src = image.getRawData() + image.w * 3 * image.h - 1; for (uint8_t* it_dst = image.getRawDataEnd() - 1; it_dst > image.getRawData();) { *it_dst-- = alpha; *it_dst-- = *it_src--; *it_dst-- = *it_src--; *it_dst-- = *it_src--; } } void colorspace_gray8_threshold (Image& image, uint8_t threshold) { for (int y = 0; y < image.h; ++y) { uint8_t* it = image.getRawData() + y * image.stride(); for (int x = 0; x < image.w; ++x) *it = *it > threshold ? 0xFF : 0x00; } image.setRawData(); } void colorspace_gray8_denoise_neighbours (Image &image, bool gross) { if (image.bps != 8 || image.spp != 1) return; unsigned stride = image.stride(); uint8_t* data = image.getRawData(); uint8_t* ndata = (uint8_t*)malloc(stride * image.h); struct compare_and_set { const Image& image; const int stride; compare_and_set (const Image& _image) : image(_image), stride (image.stride()) { } // without the inner(area) compiler guidance the conditionals are // not optimized away well enough void operator() (const int x, const int y, uint8_t* it, uint8_t* it2, const bool inner, const bool gross = false) { int n = 0, sum = 0; // + if (inner || x > 0) sum += it[-1], ++n; if (inner || y > 0) sum += it[-stride], ++n; if (inner || x < image.w-1) sum += it[1], ++n; if (inner || y < image.h-1) sum += it[stride], ++n; // x if (gross) { if (inner || y > 0) { if (inner || x > 0) sum += it[-stride - 1], ++n; if (inner || x < image.w-1) sum += it[-stride + 1], ++n; } if (inner || y < image.h-1) { if (inner || x > 0) sum += it[stride - 1], ++n; if (inner || x < image.w-1) sum += it[stride + 1], ++n; } } // if all direct neighbours are black or white, fill it if (gross) { if (sum <= 1 * 0xff) *it2 = 0; else if (sum >= (n - 1) * 0xff) *it2 = 0xff; else *it2 = *it; } else { if (sum == 0) *it2 = 0; else if (sum == n * 0xff) *it2 = 0xff; else *it2 = *it; } } } compare_and_set (image); for (int y = 0; y < image.h; ++y) { uint8_t* it = data + y * stride; uint8_t* it2 = ndata + y * stride; // optimize conditionals away for the inner area if (y > 0 && y < image.h-1) { compare_and_set (0, y, it++, it2++, false, gross); for (int x = 1; x < image.w-1; ++x) compare_and_set (x, y, it++, it2++, true, gross); compare_and_set (image.w-1, y, it++, it2++, false, gross); } else // quite some out of bounds conditions to check for (int x = 0; x < image.w; ++x) compare_and_set (x, y, it++, it2++, false, gross); } image.setRawData(ndata); } void colorspace_gray8_to_gray1 (Image& image, uint8_t threshold) { unsigned ostride = image.stride(); image.bps = 1; image.rowstride = 0; for (int row = 0; row < image.h; row++) { uint8_t *output = image.getRawData() + row * image.stride(); uint8_t *input = image.getRawData() + row * ostride; uint8_t z = 0; int x = 0; for (; x < image.w; ++x) { z <<= 1; if (*input++ > threshold) z |= 0x01; if (x % 8 == 7) { *output++ = z; z = 0; } } int remainder = 8 - x % 8; if (remainder != 8) { z <<= remainder; *output++ = z; } } image.resize(image.w, image.h); // realloc } void colorspace_gray8_to_gray4 (Image& image) { unsigned ostride = image.stride(); image.bps = 4; image.rowstride = 0; for (int row = 0; row < image.h; row++) { uint8_t *output = image.getRawData() + row * image.stride(); uint8_t *input = image.getRawData() + row * ostride; uint8_t z = 0; int x = 0; for (; x < image.w; x++) { z <<= 4; z |= (*input++ >> 4) & 0xF; if (x % 2 == 1) { *output++ = z; z = 0; } } int remainder = 2 - x % 2; if (remainder != 2) { z <<= 4*remainder; *output++ = z; } } image.resize(image.w, image.h); // realloc } void colorspace_gray8_to_gray2 (Image& image) { unsigned ostride = image.stride(); image.bps = 2; image.rowstride = 0; for (int row = 0; row < image.h; ++row) { uint8_t *output = image.getRawData() + row * image.stride(); uint8_t *input = image.getRawData() + row * ostride; uint8_t z = 0; int x = 0; for (; x < image.w; x++) { z <<= 2; z |= (*input++ >> 6) & 0x3; if (x % 4 == 3) { *output++ = z; z = 0; } } int remainder = 4 - x % 4; if (remainder != 4) { z <<= 2*remainder; *output++ = z; } } image.resize(image.w, image.h); // realloc } void colorspace_gray8_to_rgb8 (Image& image) { const int stride = image.stride(); const int nstride = image.w * 3; image.setRawDataWithoutDelete((uint8_t*)realloc(image.getRawData(), std::max(stride, nstride) * image.h)); uint8_t* data = image.getRawData(); uint8_t* output = data + image.h * nstride - 1; for (int y = image.h - 1; y >= 0; --y) { uint8_t* it = data + y * stride; for (int x = image.w - 1; x >= 0; --x) { *output-- = it[x]; *output-- = it[x]; *output-- = it[x]; } } image.spp = 3; image.resize(image.w, image.h); // realloc } void colorspace_grayX_to_gray8 (Image& image) { uint8_t* old_data = image.getRawData(); unsigned old_stride = image.stride(); const int bps = image.bps; image.bps = 8; image.rowstride = 0; image.setRawDataWithoutDelete ((uint8_t*)malloc(image.h * image.stride())); uint8_t* output = image.getRawData(); const int vmax = 1 << bps; #ifdef _MSC_VER std::vector<uint8_t> gray_lookup(vmax); #else uint8_t gray_lookup[vmax]; #endif for (int i = 0; i < vmax; ++i) { gray_lookup[i] = 0xff * i / (vmax - 1); //std::cerr << i << " = " << (int)gray_lookup[i] << std::endl; } const unsigned int bitshift = 8 - bps; for (int row = 0; row < image.h; ++row) { uint8_t* input = old_data + row * old_stride; uint8_t z = 0, bits = 0; for (int x = 0; x < image.w; ++x) { if (bits == 0) { z = *input++; bits = 8; } *output++ = gray_lookup[z >> bitshift]; z <<= bps; bits -= bps; } } free (old_data); } void colorspace_grayX_to_rgb8 (Image& image) { uint8_t* old_data = image.getRawData(); int old_stride = image.stride(); const int bps = image.bps; image.bps = 8; image.spp = 3; image.setRawDataWithoutDelete ((uint8_t*)malloc(image.h * image.stride())); uint8_t* output = image.getRawData(); const int vmax = 1 << bps; #ifdef _MSC_VER std::vector<uint8_t> gray_lookup(vmax); #else uint8_t gray_lookup[vmax]; #endif for (int i = 0; i < vmax; ++i) { gray_lookup[i] = 0xff * i / (vmax - 1); //std::cerr << i << " = " << (int)gray_lookup[i] << std::endl; } const unsigned int bitshift = 8 - bps; for (int row = 0; row < image.h; ++row) { uint8_t* input = old_data + row * old_stride; uint8_t z = 0; unsigned int bits = 0; for (int x = 0; x < image.w; ++x) { if (bits == 0) { z = *input++; bits = 8; } *output++ = gray_lookup[z >> bitshift]; *output++ = gray_lookup[z >> bitshift]; *output++ = gray_lookup[z >> bitshift]; z <<= bps; bits -= bps; } } free (old_data); } void colorspace_gray1_to_gray2 (Image& image) { uint8_t* old_data = image.getRawData(); int old_stride = image.stride(); image.bps = 2; image.rowstride = 0; image.setRawDataWithoutDelete ((uint8_t*)malloc(image.h * image.stride())); uint8_t* output = image.getRawData(); for (int row = 0; row < image.h; ++row) { uint8_t z = 0; uint8_t zz = 0; uint8_t* input = old_data + row * old_stride; int x; for (x = 0; x < image.w; ++x) { if (x % 8 == 0) z = *input++; zz <<= 2; if (z >> 7) zz |= 0x3; z <<= 1; if (x % 4 == 3) *output++ = zz; } int remainder = 4 - x % 4; if (remainder != 4) { zz <<= 2*remainder; *output++ = zz; } } free (old_data); } void colorspace_gray1_to_gray4 (Image& image) { uint8_t* old_data = image.getRawData(); int old_stride = image.stride(); image.bps = 4; image.setRawDataWithoutDelete ((uint8_t*)malloc(image.h * image.stride())); uint8_t* output = image.getRawData(); for (int row = 0; row < image.h; ++row) { uint8_t z = 0; uint8_t zz = 0; uint8_t* input = old_data + row * old_stride; int x; for (x = 0; x < image.w; ++x) { if (x % 8 == 0) z = *input++; zz <<= 4; if (z >> 7) zz |= 0x0F; z <<= 1; if (x % 2 == 1) *output++ = zz; } int remainder = 2 - x % 2; if (remainder != 2) { zz <<= 4*remainder; *output++ = zz; } } free (old_data); } void colorspace_16_to_8 (Image& image) { uint8_t* output = image.getRawData(); unsigned ostride = image.stride(); image.bps = 8; image.rowstride = 0; for (int y = 0; y < image.h; ++y) { uint16_t* it = (uint16_t*)(image.getRawData() + y * ostride); for (int x = 0; x < image.stride(); ++x) { *output++ = it[x] >> 8; } } image.resize(image.w, image.h); // realloc } void colorspace_8_to_16 (Image& image) { image.setRawDataWithoutDelete((uint8_t*)realloc(image.getRawData(), image.stride() * 2 * image.h)); uint8_t* data = image.getRawData(); unsigned stride = image.stride(); for (int y = image.h - 1; y >= 0; --y) { uint8_t* data8 = data + y * stride; uint16_t* data16 = (uint16_t*)(data + y * stride * 2); for (int x = image.stride() - 1; x >= 0; --x) { data16[x] = data8[x] * 0xffff / 255; } } image.rowstride *= 2; image.bps = 16; // converted 16bit data } void colorspace_de_palette (Image& image, int table_entries, uint16_t* rmap, uint16_t* gmap, uint16_t* bmap, uint16_t* amap) { // detect 1bps b/w tables if (image.bps == 1 && table_entries >= 2 && !amap) { if (rmap[0] == 0 && gmap[0] == 0 && bmap[0] == 0 && rmap[1] >= 0xff00 && gmap[1] >= 0xff00 && bmap[1] >= 0xff00) { //std::cerr << "correct b/w table." << std::endl; return; } if (rmap[1] == 0 && gmap[1] == 0 && bmap[1] == 0 && rmap[0] >= 0xff00 && gmap[0] >= 0xff00 && bmap[0] >= 0xff00) { //std::cerr << "inverted b/w table." << std::endl; for (uint8_t* it = image.getRawData(); it < image.getRawDataEnd(); ++it) *it ^= 0xff; image.setRawData (); return; } } // detect gray tables bool is_gray = false; if (table_entries > 1 && !amap) { bool is_ordered_gray = (image.bps == 8 || image.bps == 4 || image.bps == 2) && (1 << image.bps == table_entries); is_gray = true; // std::cerr << (1 << image.bps) << " vs " << table_entries << std::endl; // std::cerr << "checking for gray table" << std::endl; for (int i = 0; (is_gray || is_ordered_gray) && i < table_entries; ++i) { // std::cerr << rmap[i] << " " << gmap[i] << " " << bmap[i] << std::endl; if (rmap[i] >> 8 != gmap[i] >> 8 || rmap[i] >> 8 != bmap[i] >> 8) { is_gray = is_ordered_gray = false; } else if (is_ordered_gray) { const int ref = i * 0xff / (table_entries - 1); if (rmap[i] >> 8 != ref || gmap[i] >> 8 != ref || bmap[i] >> 8 != ref) is_ordered_gray = false; } } // std::cerr << "gray: " << is_gray << ", is ordered: " << is_ordered_gray << std::endl; if (is_ordered_gray) return; } int new_size = image.w * image.h; if (amap) new_size *= 4; // RGBA, CMYK else if (!is_gray) // RGB new_size *= 3; uint8_t* orig_data = image.getRawData(); uint8_t* new_data = (uint8_t*) malloc (new_size); uint8_t* src = orig_data; uint8_t* dst = new_data; // TODO: allow 16bit output if the palette contains that much dynamic const unsigned int bitshift = 8 - image.bps; while (dst < new_data + new_size) { uint8_t z = 0; unsigned int bits = 0; for (int x = 0; x < image.w; ++x) { if (bits == 0) { z = *src++; bits = 8; } if (is_gray) { *dst++ = rmap[z >> bitshift] >> 8; } else { *dst++ = rmap[z >> bitshift] >> 8; *dst++ = gmap[z >> bitshift] >> 8; *dst++ = bmap[z >> bitshift] >> 8; if (amap) *dst++ = amap[z >> bitshift] >> 8; } z <<= image.bps; bits -= image.bps; } } image.bps = 8; if (is_gray) image.spp = 1; else if (amap) image.spp = 4; else image.spp = 3; image.setRawData (new_data); } bool colorspace_by_name (Image& image, const std::string& target_colorspace, uint8_t threshold) { std::string space = target_colorspace; std::transform (space.begin(), space.end(), space.begin(), tolower); int spp, bps; if (space == "bw" || space == "bilevel" || space == "gray1") { spp = 1; bps = 1; } else if (space == "gray2") { spp = 1; bps = 2; } else if (space == "gray4") { spp = 1; bps = 4; } else if (space == "gray" || space == "gray8") { spp = 1; bps = 8; } else if (space == "gray16") { spp = 1; bps = 16; } else if (space == "rgb" || space == "rgb8") { spp = 3; bps = 8; } else if (space == "rgba" || space == "rgba8") { spp = 4; bps = 8; } else if (space == "rgb16") { spp = 3; bps = 16; // TODO: CYMK, YVU, RGBA, GRAYA... } else { std::cerr << "Requested colorspace conversion not yet implemented." << std::endl; return false; } return colorspace_convert(image, spp, bps, threshold); } bool colorspace_convert(Image& image, int spp, int bps, uint8_t threshold) { // thru the codec? if (!image.isModified() && image.getCodec()) if (spp == 1 && bps >= 8) if (image.getCodec()->toGray(image)) return true; // no image data, e.g. for loading raw images if (!image.getRawData()) { image.spp = spp; image.bps = bps; return true; } // up if (image.bps == 1 && bps == 2) colorspace_gray1_to_gray2 (image); else if (image.bps == 1 && bps == 4) colorspace_gray1_to_gray4 (image); else if (image.bps < 8 && bps >= 8) colorspace_grayX_to_gray8 (image); // upscale to 8 bit even for sub byte gray since we have no inter sub conv., yet if (image.bps < 8 && image.bps != bps) colorspace_grayX_to_gray8 (image); if (image.bps == 8 && image.spp == 1 && spp >= 3) colorspace_gray8_to_rgb8 (image); if (image.bps == 8 && bps == 16) colorspace_8_to_16 (image); // down if (image.bps == 16 && bps < 16) colorspace_16_to_8 (image); if (image.spp == 4 && spp < 4 && image.bps == 8) { // TODO: might be RGB16 if (spp < 3) colorspace_rgb8_to_gray8 (image, 4); else colorspace_rgba8_to_rgb8 (image); } if (image.spp == 3 && spp == 4 && image.bps == 8) { // TODO: might be RGB16 colorspace_rgb8_to_rgb8a (image); } if (image.spp == 3 && spp == 1) { if (image.bps == 8) colorspace_rgb8_to_gray8 (image); else if (image.bps == 16) colorspace_rgb16_to_gray16 (image); } if (spp == 1 && image.bps > bps) { if (image.bps == 8 && bps == 1) colorspace_gray8_to_gray1 (image, threshold); else if (image.bps == 8 && bps == 2) colorspace_gray8_to_gray2 (image); else if (image.bps == 8 && bps == 4) colorspace_gray8_to_gray4 (image); } if (image.spp != spp || image.bps != bps) { std::cerr << "Incomplete colorspace conversion. Requested: spp: " << spp << ", bps: " << bps << " - now at spp: " << image.spp << ", bps: " << image.bps << std::endl; image.spp = spp; image.bps = bps; image.resize(image.w, image.h); return false; } return true; } const char* colorspace_name (Image& image) { switch (image.spp * image.bps) { case 1: return "gray1"; case 2: return "gray2"; case 4: return "gray4"; case 8: return "gray8"; case 16: return "gray16"; case 24: return "rgb8"; case 32: return "rgba8"; case 48: return "rgb16"; default: return ""; } } // -- #include <math.h> static inline double getExponentContrast (double contrast) { return (contrast < 0.0) ? 1.0 + contrast : ( (contrast == 1.0) ? 127 : 1.0 / (1.0 - contrast) ); } static inline double getExponentGamma (double gamma) { return 1.0 / gamma; } static inline double convert (double val, double brightness, double contrast, double gamma) { /* apply brightness */ if (brightness < 0.0) val = val * (1.0 + brightness); else if (brightness > 0.0) val = val + ((1.0 - val) * brightness); /* apply contrast */ if (contrast != 0.0) { double nvalue = (val > 0.5) ? 1.0 - val : val; if (nvalue < 0.0) nvalue = 0.0; nvalue = 0.5 * pow (2.0 * nvalue, getExponentContrast (contrast)); val = (val > 0.5) ? 1.0 - nvalue : nvalue; } /* apply gamma */ if (gamma != 1.0) { val = pow (val, getExponentGamma (gamma)); } return val; } template<typename T> struct brightness_contrast_gamma_template { void operator() (Image& image, double brightness, double contrast, double gamma) { T it (image); typename T::accu a; typename T::accu::vtype _r, _g, _b; double r, g, b; for (int i = 0; i < image.h * image.w; ++i) { a = *it; a.getRGB (_r, _g, _b); r = _r, g = _g, b = _b; r /= T::accu::one().v[0]; g /= T::accu::one().v[0]; b /= T::accu::one().v[0]; r = convert (r, brightness, contrast, gamma); g = convert (g, brightness, contrast, gamma); b = convert (b, brightness, contrast, gamma); _r = (typename T::accu::vtype)(r * T::accu::one().v[0]); _g = (typename T::accu::vtype)(g * T::accu::one().v[0]); _b = (typename T::accu::vtype)(b * T::accu::one().v[0]); a.setRGB (_r, _g, _b); it.set(a); ++it; } image.setRawData(); } }; void brightness_contrast_gamma (Image& image, double brightness, double contrast, double gamma) { codegen<brightness_contrast_gamma_template> (image, brightness, contrast, gamma); } template <typename T> struct hue_saturation_lightness_template { void operator() (Image& image, double _hue, double saturation, double lightness) { T it (image); // optimized ONE2 in divisions imprecise shifts if not an FP type const typename T::accu::vtype ONE = T::accu::one().v[0], ONE2 = ONE > 1 ? ONE + 1 : ONE; // H in degree, S and L [-1, 1], latér scaled to the integer range _hue = fmod (_hue, 360); if (_hue < 0) _hue += 360; const typename T::accu::vtype hue = ONE * _hue / 360; for (int i = 0; i < image.h * image.w; ++i) { typename T::accu a = *it; typename T::accu::vtype r, g, b; a.getRGB (r, g, b); // RGB to HSV typename T::accu::vtype h, s, v; { const typename T::accu::vtype min = std::min (std::min (r, g), b); const typename T::accu::vtype max = std::max (std::max (r, g), b); const typename T::accu::vtype delta = max - min; v = max; if (delta == 0) { h = 0; s = 0; } else { s = max == 0 ? 0 : ONE - (ONE * min / max); if (max == r) // yellow - magenta h = (60*ONE/360) * (g - b) / delta + (g >= b ? 0 : ONE); else if (max == g) // cyan - yellow h = (60*ONE/360) * (b - r) / delta + 120*ONE/360; else // magenta - cyan h = (60*ONE/360) * (r - g) / delta + 240*ONE/360; } } // hue should only be positive, se we only need to check one overflow h += hue; if (h >= ONE) h -= ONE; // TODO: this might not be accurate, double check, ... s = s + s * saturation; s = std::max (std::min (s, ONE), (typename T::accu::vtype)0); v = v + v * lightness; v = std::max (std::min (v, ONE), (typename T::accu::vtype)0); // back from HSV to RGB { const int i = 6 * h / ONE2; const typename T::accu::vtype f = 6 * h % ONE2; // only compute the ones "on-demand" as needed #define p (v * (ONE - s) / ONE2) #define q (v * (ONE - f * s / ONE2) / ONE2) #define t (v * (ONE - (ONE - f) * s / ONE2) / ONE2) switch (i) { case 0: r = v; g = t; b = p; break; case 1: r = q; g = v; b = p; break; case 2: r = p; g = v; b = t; break; case 3: r = p; g = q; b = v; break; case 4: r = t; g = p; b = v; break; default: // case 5: r = v; g = p; b = q; break; } #undef p #undef q #undef t } // end a.setRGB (r, g, b); it.set(a); ++it; } image.setRawData(); } }; void hue_saturation_lightness (Image& image, double hue, double saturation, double lightness) { codegen<hue_saturation_lightness_template> (image, hue, saturation, lightness); } template <typename T> struct invert_template { void operator() (Image& image) { T it (image); for (int y = 0; y < image.h; ++y) { for (int x = 0; x < image.w; ++x) { typename T::accu a = *it; a = T::accu::one() -= a; it.set (a); ++it; } } image.setRawData(); } }; void invert (Image& image) { codegen<invert_template> (image); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/low-level.cc������������������������������������������������������������������0000644�0000764�0000764�00000002536�11343176350�015355� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Misc. low-level helpers, usually to aid debugging. * Copyright (C) 2007 - 2010 Ren\xc3\xa9 Rebe, ExactCOD GmbH Germany * * 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> // malloc #include <string.h> // memcpy #include "low-level.hh" void deinterlace (Image& image) { const int stride = image.stride(); const int height = image.height(); uint8_t* deinterlaced = (uint8_t*) malloc(image.stride() * height); for (int i = 0; i < height; ++i) { const int dst_i = i / 2 + (i % 2) * (height / 2); std::cerr << i << " - " << dst_i << std::endl; uint8_t* dst = deinterlaced + stride * dst_i; uint8_t* src = image.getRawData() + stride * i; memcpy(dst, src, stride); } image.setRawData(deinterlaced); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/vectorial.cc������������������������������������������������������������������0000644�0000764�0000764�00000027172�12400436243�015435� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Agg vector rasterization interface * Copyright (C) 2007 - 2014 Rene Rebe, ExactCODE GmbH * Copyright (C) 2007 Susanne Klaus, ExactCODE GmbH * * based on GSMP/plugins-gtk/GUI-gtk/Pixmap.cc: * Copyright (C) 2000 - 2002 René Rebe and Valentin Ziegler, GSMP * * 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 "vectorial.hh" #include "C.h" // ARRAY_SIZE #include <iostream> #include <cmath> #include "agg.hh" #include "Image.hh" #include "Encodings.hh" #include "agg_conv_dash.h" #include "agg_conv_curve.h" #include "agg_conv_contour.h" #include "agg_conv_segmentator.h" #include "agg_conv_smooth_poly1.h" #include "agg_path_storage.h" #include "agg_conv_stroke.h" #include "agg_trans_single_path.h" #include "agg_bounding_rect.h" #if WITHFREETYPE == 1 #include "agg_font_freetype.h" #endif // --- Path::Path () : line_width (1.0), dashes_start_offset (0.0), line_cap (agg::butt_cap), line_join (agg::miter_join) { } Path::~Path () { } void Path::moveTo (double x, double y) { path.move_to (x, y); } void Path::addLine (double x, double y) { path.line_rel (x, y); } void Path::addLineTo (double x, double y) { path.line_to (x, y); } void Path::addRect (double x, double y, double x2, double y2) { moveTo (x, y); addLineTo (x2, y); addLineTo (x2, y2); addLineTo (x, y2); close (); } void Path::addArcTo (double rx, double ry, double angle, double x, double y) { path.arc_to (rx, ry, angle, false /*large arc */, false /* sweep */, x, y); } void Path::addArc (double rx, double ry, double angle, double dx, double dy) { path.arc_rel (rx, ry, angle, false /*large arc */, false /* sweep */, dx, dy); } void Path::addCurveTo (double c1x, double c1y, double x, double y) { path.curve3 (c1x, c1y, x, y); } void Path::addCurveTo (double c1x, double c1y, double c2x, double c2y, double x, double y) { path.curve4 (c1x, c1y, c2x, c2y, x, y); } void Path::end () { // do not close the path, we have ::close() for that purpose path.end_poly (agg::path_flags_none); } void Path::close () { path.close_polygon (); } void Path::clear () { path.remove_all (); } void Path::setFillColor (double _r, double _g, double _b, double _a) { r = _r; g = _g; b = _b; a = _a; } void Path::setLineWidth (double width) { line_width = width; } void Path::setLineDash (double offset, const std::vector<double>& _dashes) { dashes_start_offset = offset; dashes = _dashes; } void Path::setLineDash (double offset, const double* _dashes, int n) { dashes_start_offset = offset; dashes.clear (); for (; n; n--, _dashes++) dashes.push_back (*_dashes); } void Path::setLineCap (line_cap_t cap) { line_cap = cap; } void Path::setLineJoin (line_join_t join) { line_join = join; } void Path::draw (Image& image, filling_rule_t fill) { renderer_exact_image ren_base (image); /* the rederer_bin type would "avoid" anti-aliasing */ renderer_aa ren (ren_base); ren.color (agg::rgba (r, g, b, a)); rasterizer_scanline ras; scanline sl; agg::conv_curve<agg::path_storage> smooth (path); if (fill == fill_none) { agg::line_profile_aa profile; profile.gamma (agg::gamma_power(1.2)); // optional //profile.min_width (0.75); // optional //profile.smoother_width (3.0); //optional if (dashes.empty ()) { agg::conv_stroke<agg::conv_curve<agg::path_storage> > stroke (smooth); stroke.line_cap (line_cap); stroke.line_join (line_join); stroke.width (line_width); ras.add_path (stroke); } else { typedef agg::conv_dash<agg::conv_curve<agg::path_storage> > dash_t; dash_t dash (smooth); dash.dash_start (dashes_start_offset); for (std::vector<double>::const_iterator i = dashes.begin (); i != dashes.end ();) { double a = *i++, b; if (i != dashes.end ()) b = *i++; else break; // TODO: warn or exception ? dash.add_dash (a, b); } agg::conv_stroke<dash_t> stroke (dash); stroke.line_cap (line_cap); stroke.line_join (line_join); stroke.width (line_width); ras.add_path (stroke); } } else { // just cast, we use a toll-free enum bridge ras.filling_rule ((agg::filling_rule_e)fill); ras.add_path (smooth); } agg::render_scanlines (ras, sl, ren); image.setRawData(); // invalidate cache } #if WITHFREETYPE == 1 static const bool hinting = true; static const bool kerning = true; typedef agg::font_engine_freetype_int32 font_engine_type; typedef agg::font_cache_manager<font_engine_type> font_manager_type; static agg::glyph_rendering gren = agg::glyph_ren_outline; static const char* fonts[] = { "/usr/X11/share/fonts/TTF/DejaVuSans.ttf", "/usr/X11/share/fonts/TTF/Vera.ttf", }; static bool load_font(font_engine_type& m_feng, const char* fontfile) { if (fontfile) { if (m_feng.load_font (fontfile, 0, gren)) return true; std::cerr << "failed to load ttf font: " << fontfile << std::endl; return false; } else { for (unsigned int i = 0; i < ARRAY_SIZE(fonts); ++i) { if (m_feng.load_font (fonts[i], 0, gren)) return true; std::cerr << "failed to load ttf font: " << fonts[i] << std::endl; } } return false; } bool Path::drawText (Image& image, const char* text, double height, const char* fontfile, agg::trans_affine mtx, filling_rule_t fill, double* w, double* h, double* dx, double* dy) { if (!text) return false; renderer_exact_image ren_base (image); rasterizer_scanline ras; scanline sl; renderer_aa ren_solid (ren_base); ren_solid.color (agg::rgba (r, g, b, a)); renderer_bin ren_bin (ren_base); ren_bin.color (agg::rgba (r, g, b, a)); font_engine_type m_feng; font_manager_type m_fman (m_feng); mtx *= agg::trans_affine_translation(path.last_x(), path.last_y()); // Pipeline to process the vectors glyph paths agg::conv_curve<font_manager_type::path_adaptor_type> m_curves(m_fman.path_adaptor()); agg::conv_transform<agg::conv_curve<font_manager_type::path_adaptor_type> > m_curves_mtx(m_curves, mtx); agg::conv_stroke<agg::conv_curve<font_manager_type::path_adaptor_type> > m_stroke(m_curves); m_stroke.width(line_width); agg::conv_transform<agg::conv_stroke<agg::conv_curve<font_manager_type::path_adaptor_type> > > m_stroke_mtx(m_stroke, mtx); m_feng.height (height); if (!load_font(m_feng, fontfile)) return false; m_feng.hinting (hinting); m_feng.height (height); m_feng.flip_y (true); agg::rect_d bbox(0, 0, -1, -1); std::vector<uint32_t> utf8 = DecodeUtf8(text, strlen(text)); double x = 0, y = 0; for (unsigned int i = 0, n = 0; i < utf8.size(); ++i) { switch (utf8[i]) { case '\n': n = 0; x = path.last_x(); y += height * 1.2; continue; case '\t': { const agg::glyph_cache* glyph = m_fman.glyph(' '); int skip = 8 - n % 8; x += glyph->advance_x * skip; y += glyph->advance_y * skip; n += skip; } continue; } const agg::glyph_cache* glyph = m_fman.glyph(utf8[i]); if (glyph) { if (kerning) m_fman.add_kerning(&x, &y); m_fman.init_embedded_adaptors(glyph, x, y); switch (glyph->data_type) { case agg::glyph_data_mono: if (!w && !h) agg::render_scanlines (m_fman.mono_adaptor(), m_fman.mono_scanline(), ren_bin); break; case agg::glyph_data_gray8: if (!w && !h) agg::render_scanlines (m_fman.gray8_adaptor(), m_fman.gray8_scanline(), ren_solid); break; case agg::glyph_data_outline: if (fill != fill_none) { if (w && h) { agg::rect_d r; agg::bounding_rect_single(m_curves_mtx, 0, &r.x1, &r.y1, &r.x2, &r.y2); if (!bbox.is_valid()) bbox = r; else bbox = agg::unite_rectangles(bbox, r); } else ras.add_path (m_curves_mtx); } else { if (w && h) { agg::rect_d r; agg::bounding_rect_single(m_stroke_mtx, 0, &r.x1, &r.y1, &r.x2, &r.y2); if (!bbox.is_valid()) bbox = r; else bbox = agg::unite_rectangles(bbox, r); } else ras.add_path (m_stroke_mtx); } break; default: break; } // increment pen position x += glyph->advance_x; y += glyph->advance_y; } } if (w || h) { *w = bbox.x2 - bbox.x1 + 1; *h = bbox.y2 - bbox.y1 + 1; *dx = *dy = 0; mtx.transform(dx, dy); *dx -= bbox.x1; *dy -= bbox.y1; return true; } agg::render_scanlines(ras, sl, ren_solid); image.setRawData(); // invalidate cache mtx.transform(&x, &y); path.move_to(x, y); // save last point for further drawing return true; } bool Path::drawTextOnPath (Image& image, const char* text, double height, const char* fontfile) // TODO: , filling_rule_t fill) { if (!text) return false; renderer_exact_image ren_base (image); renderer_aa ren_solid (ren_base); ren_solid.color (agg::rgba (r, g, b, a)); rasterizer_scanline ras; scanline sl; agg::conv_curve<agg::path_storage> smooth (path); agg::trans_single_path tcurve; tcurve.add_path (smooth); // tcurve.preserve_x_scale(m_preserve_x_scale.status()); font_engine_type m_feng; font_manager_type m_fman (m_feng); // Pipeline to process the vectors glyph paths agg::conv_curve<font_manager_type::path_adaptor_type> m_curves (m_fman.path_adaptor()); m_feng.height (height); if (!load_font(m_feng, fontfile)) return false; // Transform pipeline typedef agg::conv_curve<font_manager_type::path_adaptor_type> conv_font_curve_type; typedef agg::conv_segmentator<conv_font_curve_type> conv_font_segm_type; typedef agg::conv_transform<conv_font_segm_type, agg::trans_single_path> conv_font_trans_type; conv_font_curve_type fcurves (m_fman.path_adaptor()); conv_font_segm_type fsegm (fcurves); conv_font_trans_type ftrans (fsegm, tcurve); fsegm.approximation_scale (3.0); fcurves.approximation_scale (2.0); m_feng.hinting (hinting); m_feng.height (height); m_feng.flip_y (true); ras.reset (); double x = 0, y = 0; std::vector<uint32_t> utf8 = DecodeUtf8(text, strlen(text)); for (unsigned int i = 0, n = 0; i < utf8.size(); ++i) { switch (utf8[i]) { case '\n': n = 0; x = 0; y += height * 1.2; continue; case '\t': { const agg::glyph_cache* glyph = m_fman.glyph(' '); int skip = 8 - n % 8; x += glyph->advance_x * skip; y += glyph->advance_y * skip; n += skip; } continue; } const agg::glyph_cache* glyph = m_fman.glyph(utf8[i]); if (glyph) { if (kerning) m_fman.add_kerning(&x, &y); m_fman.init_embedded_adaptors(glyph, x, y); if (glyph->data_type == agg::glyph_data_outline) { ras.add_path (ftrans); } else std::cerr << "Warning: unexpected glyph type!" << std::endl; // increment pen position x += glyph->advance_x; y += glyph->advance_y; } } agg::render_scanlines(ras, sl, ren_solid); image.setRawData(); // invalidate cache path.move_to(x, y); // save last point for further drawing return true; } #endif ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/scale.cc����������������������������������������������������������������������0000644�0000764�0000764�00000037656�12453273425�014555� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2006 - 2015 René Rebe, ExactCODE GmbH Germany. * (C) 2006, 2007 Archivista GmbH, CH-8042 Zuerich * * 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 <string.h> // memset #include <cmath> #include <iostream> #include <algorithm> #include "Image.hh" #include "ImageIterator2.hh" #include "Codecs.hh" #include "Colorspace.hh" #include "scale.hh" #ifdef _MSC_VER #include <vector> #endif void scale (Image& image, double scalex, double scaley) { if (scalex == 1.0 && scaley == 1.0) return; // thru the codec? if (!image.isModified() && image.getCodec()) if (image.getCodec()->scale(image, scalex, scaley)) return; if (scalex <= 0.5) box_scale (image, scalex, scaley); else bilinear_scale (image, scalex, scaley); } template <typename T> struct nearest_scale_template { void operator() (Image& new_image, double scalex, double scaley) { Image image; image.copyTransferOwnership (new_image); new_image.resize ((int)(scalex * (double) image.w), (int)(scaley * (double) image.h)); new_image.setResolution (scalex * image.resolutionX(), scaley * image.resolutionY()); #pragma omp parallel for schedule (dynamic, 16) for (int y = 0; y < new_image.h; ++y) { T dst (new_image); dst.at(0, y); T src (image); for (int x = 0; x < new_image.w; ++x) { const int bx = (int) (((double) x) / scalex); const int by = (int) (((double) y) / scaley); typename T::accu a; a = *src.at (bx, by); dst.set (a); ++dst; } } } }; void nearest_scale (Image& image, double scalex, double scaley) { if (scalex == 1.0 && scaley == 1.0) return; codegen<nearest_scale_template> (image, scalex, scaley); } template <typename T> struct bilinear_scale_template { void operator() (Image& new_image, double scalex, double scaley, bool fixed) { if (!fixed) { scalex = (int)(scalex * new_image.w); scaley = (int)(scaley * new_image.h); } Image image; image.copyTransferOwnership (new_image); new_image.resize (scalex, scaley); new_image.setResolution (new_image.w * image.resolutionX() / image.w, new_image.h * image.resolutionY() / image.h); // cache x offsets, 2x speedup #ifndef _MSC_VER float bxmap[new_image.w]; int sxmap[new_image.w]; int sxxmap[new_image.w]; #else std::vector<float> bxmap(new_image.w); std::vector<int> sxmap(new_image.w); std::vector<int> sxxmap(new_image.w); #endif for (int x = 0; x < new_image.w; ++x) { bxmap[x] = (float)x / (new_image.w - 1) * (image.w - 1); sxmap[x] = (int)floor(bxmap[x]); sxxmap[x] = sxmap[x] == (image.w - 1) ? sxmap[x] : sxmap[x] + 1; } #pragma omp parallel for schedule (dynamic, 16) for (int y = 0; y < new_image.h; ++y) { T dst (new_image); dst.at(0, y); const float by = (float)y / (new_image.h - 1) * (image.h - 1); const int sy = (int)floor(by); const int ydist = (int) ((by - sy) * 256); const int syy = sy == (image.h - 1) ? sy : sy + 1; T src (image); for (int x = 0; x < new_image.w; ++x) { const float bx = bxmap[x]; const int sx = sxmap[x];; const int xdist = (int) ((bx - sx) * 256); const int sxx = sxxmap[x];; typename T::accu a1, a2; a1 = (*src.at (sx, sy )) * ((256-xdist)); a1 += (*src.at (sxx, sy )) * (xdist ); a1 /= 256; a2 = (*src.at (sx, syy)) * ((256-xdist)); a2 += (*src.at (sxx, syy)) * (xdist ); a2 /= 256; a1 = a1 * (256-ydist) + a2 * ydist; a1 /= 256; dst.set(a1); ++dst; } } } }; void bilinear_scale (Image& image, double scalex, double scaley, bool fixed) { if (scalex == 1.0 && scaley == 1.0) return; codegen<bilinear_scale_template> (image, scalex, scaley, fixed); } template <typename T> struct box_scale_template { void operator() (Image& new_image, double scalex, double scaley) { Image image; image.copyTransferOwnership (new_image); new_image.resize ((int)(scalex * (double) image.w), (int)(scaley * (double) image.h)); new_image.setResolution (scalex * image.resolutionX(), scaley * image.resolutionY()); T src (image); T dst (new_image); // prepare boxes #if defined(_MSC_VER) || defined(__clang__) std::vector<typename T::accu> boxes(new_image.w); #else typename T::accu boxes [new_image.w]; #endif #if defined(_MSC_VER) std::vector<int> count(new_image.w); std::vector<int> bindex(image.w); // pre-computed box-indexes #else int count [new_image.w]; int bindex [image.w]; // pre-computed box indexes #endif for (int sx = 0; sx < image.w; ++sx) bindex[sx] = std::min ((int)(scalex * sx), new_image.w - 1); int dy = 0; for (int sy = 0; dy < new_image.h && sy < image.h; ++dy) { // clear for accumulation for (int x = 0; x < new_image.w; ++x) { boxes[x] = typename T::accu(); count[x] = 0; } for (; sy < image.h && scaley * sy < dy + 1; ++sy) { // std::cout << "sy: " << sy << " from " << image.h << std::endl; for (int sx = 0; sx < image.w; ++sx) { // std::cout << "sx: " << sx << " -> " << dx << std::endl; const int dx = bindex[sx]; boxes[dx] += *src; ++src; ++count[dx]; } } // set box // std::cout << "dy: " << dy << " from " << new_image.h << std::endl; for (int dx = 0; dx < new_image.w; ++dx) { // std::cout << "setting: dx: " << dx << ", from: " << new_image.w // << ", count: " << count[dx] << std::endl; boxes[dx] /= count[dx]; dst.set (boxes[dx]); ++dst; } } } }; void box_scale (Image& image, double scalex, double scaley) { if (scalex == 1.0 && scaley == 1.0) return; codegen<box_scale_template> (image, scalex, scaley); } inline Image::iterator CubicConvolution (int distance, const Image::iterator& f0, const Image::iterator& f1, const Image::iterator& f2, const Image::iterator& f3) { Image::iterator it = f0; it = ( /*( f1 + f3 - f0 - f2 ) * distance * distance * distance + (f0*2 + f2 - f1*2 - f3 ) * distance * distance +*/ ( f2 - f1 ) * distance ) / (256) + f1; return it; } /* 0 0 0 0 0 4 0 0 0 0 -13.5 6 0 0 6.1 -2.45 */ void bicubic_scale (Image& new_image, double scalex, double scaley) { if (scalex == 1.0 && scaley == 1.0) return; Image image; image.copyTransferOwnership (new_image); new_image.resize ((int)(scalex * (double) image.w), (int)(scaley * (double) image.h)); new_image.setResolution (scalex * image.resolutionX(), scaley * image.resolutionY()); Image::iterator dst = new_image.begin(); Image::iterator src = image.begin(); Image::iterator r0 = image.begin(); Image::iterator r1 = image.begin(); Image::iterator r2 = image.begin(); Image::iterator r3 = image.begin(); for (int y = 0; y < new_image.h; ++y) { double by = .5+y / scaley; const int sy = std::min((int)by, image.h-1); const int ydist = (int) ((by - sy) * 256); const int sy0 = std::max(sy-1, 0); const int sy2 = std::min(sy+1, image.h-1); const int sy3 = std::min(sy+2, image.h-1); for (int x = 0; x < new_image.w; ++x) { const double bx = .5+x / scalex; const int sx = std::min((int)bx, image.w - 1); const int xdist = (int) ((bx - sx) * 256); const int sx0 = std::max(sx-1, 0); const int sx2 = std::min(sx+1, image.w-1); const int sx3 = std::min(sx+2, image.w-1); // xdist = ydist = 0; r0 = CubicConvolution (xdist, *src.at(sx0,sy0), *src.at(sx,sy0), *src.at(sx2,sy0), *src.at(sx3,sy0)); r1 = CubicConvolution (xdist, *src.at(sx0,sy), *src.at(sx,sy), *src.at(sx2,sy), *src.at(sx3,sy)); r2 = CubicConvolution (xdist, *src.at(sx0,sy2), *src.at(sx,sy2), *src.at(sx2,sy2), *src.at(sx3,sy2)); r3 = CubicConvolution (xdist, *src.at(sx0,sy3), *src.at(sx,sy3), *src.at(sx2,sy3), *src.at(sx3,sy3)); dst.set (CubicConvolution (ydist, r0, r1, r2, r3)); ++dst; } } } #ifndef _MSC_VER template <typename T> T interp(float x, float y, const T&a, const T& b, const T& c, const T& d) { // x, y: [0 .. 1] // we use 256-scale for fix-point int images if (x >= y) { float b1 = -(x - 1); float b2 = (x - 1) - (y - 1); float b3 = 1 - b1 - b2; return (a * (256 * b1) + d * (256 * b2) + c * (256 * b3)) / 256; } else { float b1 = -(y - 1); float b2 = -((x - 1) - (y - 1)); float b3 = 1 - b1 - b2; return (a * (256 * b1) + b * (256 * b2) + c * (256 * b3)) / 256; } } template <typename T> struct ddt_scale_template { void operator() (Image& new_image, double scalex, double scaley, bool extended) { Image image; image.copyTransferOwnership (new_image); new_image.resize((int)(scalex * (double) image.w), (int)(scaley * (double) image.h)); new_image.setResolution (scalex * image.resolutionX(), scaley * image.resolutionY()); // first scan the source image and build a direction map // TODO: we could do the check on-the-fly, ... char dir_map [image.h - 1][image.w - 1]; // A - D // | | // B - C T src_a(image), src_b(image), src_c(image), src_d(image); for (int y = 0; y < image.h-1; ++y) { src_a.at(0, y); src_b.at(0, y+1); src_c.at(1, y+1); src_d.at(1, y); for (int x = 0; x < image.w-1; ++x) { typename T::accu::vtype a, b, c, d; (*src_a).getL(a); ++src_a; (*src_b).getL(b); ++src_b; (*src_c).getL(c); ++src_c; (*src_d).getL(d); ++src_d; //std::cout << "x: " << x << ", y: " << y << std::endl; //std::cout << "a: " << a << ", b: " << b // << ", c: " << c << ", d: " << d << std::endl; if (abs(a-c) < abs(b-d)) dir_map[y][x] = '\\'; else dir_map[y][x] = '/'; } } if (extended) { char dir_map2 [image.h - 1][image.w - 1]; for (int y = 1; y < image.h-2; ++y) { for (int x = 1; x < image.w-2; ++x) { uint8_t n1 = 0, n2 = 0; for (int i = 0; i < 3; ++i) { for (int j = 0; j < 3; ++j) { n1 += dir_map[y+i][x+j] == '/'; n2 += dir_map[y+i][x+j] == '\\'; } } if (n1 >= 6) dir_map2[y][x] = '/'; else if (n2 >= 6) dir_map2[y][x] = '\\'; else dir_map2[y][x] = dir_map[y][x]; } } for (int y = 1; y < image.h-2; ++y) for (int x = 1; x < image.w-2; ++x) dir_map[y][x] = dir_map2[y][x]; } if (false) { int n = 0; for (int y = 0; y < image.h-1; ++y) { for (int x = 0; x < image.w-1; ++x) { std::cout << (dir_map[y][x] == '/' ? ' ' : '\\'); if (dir_map[y][x] == '/') ++n; } std::cout << std::endl; } std::cout << "NW-SE: " << n << std::endl; std::cout << std::endl; n = 0; for (int y = 0; y < image.h-1; ++y) { for (int x = 0; x < image.w-1; ++x) { std::cout << (dir_map[y][x] == '/' ? '/' : ' '); if (dir_map[y][x] != '/') ++n; } std::cout << std::endl; } std::cout << "NE-SW: " << n << std::endl; } T dst(new_image); T src(image); for (int y = 0; y < new_image.h; ++y) { const float by = (float)y / (new_image.h - 1) * (image.h - 1); const int sy = std::min((int)floor(by), image.h - 2); const float ydist = by - sy; for (int x = 0; x < new_image.w; ++x) { const float bx = (float)x / (new_image.w - 1) * (image.w - 1); const int sx = std::min((int)floor(bx), image.w - 2); const float xdist = bx - sx; if (false) std::cout << "x: " << x << ", y: " << y << " <- " << "bx: " << bx << ", by: " << by << ", sx: " << sx << ", sy: " << sy << " dist: " << xdist <<", " << ydist << std::endl; typename T::accu v; const typename T::accu a = *src.at(sx, sy); const typename T::accu b = *src.at(sx, sy + 1); const typename T::accu c = *src.at(sx + 1, sy + 1); const typename T::accu d = *src.at(sx + 1, sy); // which triangle does the point fall into? if (dir_map[sy][sx] == '\\') { v = interp(xdist, ydist, a, b, c, d); } else { // '/' // virtually rotate triangles by 90 v = interp(ydist, 1. - xdist, d, a, b, c); } dst.set(v); ++dst; } } // syntetic test if (false) { dst.at(0, 0); for (int y = 0; y < new_image.h; ++y) { for (int x = 0; x < new_image.w; ++x) { typename T::accu v, a, b, c, d; a.setRGB(0, 0, 0); b.setRGB(33, 33, 33); c.setRGB(255, 255, 255); d.setRGB(128, 128, 128); v = interp(float(x) / new_image.w, (float)y / new_image.h, a, b, c, d); //v = interp((float)y / new_image.h, 1. - float(x) / new_image.w, d, a, b, c); dst.set(v); ++dst; } } } } }; void ddt_scale (Image& image, double scalex, double scaley, bool extended) { if (scalex == 1.0 && scaley == 1.0) return; codegen<ddt_scale_template> (image, scalex, scaley, extended); } #endif void box_scale_grayX_to_gray8 (Image& new_image, double scalex, double scaley) { if (scalex == 1.0 && scaley == 1.0) return; Image image; image.copyTransferOwnership (new_image); new_image.bps = 8; // always output 8bit gray new_image.resize((int)(scalex * (double) image.w), (int)(scaley * (double) image.h)); new_image.setResolution (scalex * image.resolutionX(), scaley * image.resolutionY()); uint8_t* src = image.getRawData(); uint8_t* dst = new_image.getRawData(); #ifdef _MSC_VER std::vector<uint32_t> boxes(new_image.w); std::vector<uint32_t> count(new_image.w); std::vector<int> bindex(image.w); #else uint32_t boxes[new_image.w]; uint32_t count[new_image.w]; // pre-compute box indexes int bindex [image.w]; #endif for (int sx = 0; sx < image.w; ++sx) bindex[sx] = std::min ((int)(scalex * sx), new_image.w - 1); const int bps = image.bps; const int vmax = 1 << bps; #ifdef _MSC_VER std::vector<uint8_t> gray_lookup(vmax); #else uint8_t gray_lookup[vmax]; #endif for (int i = 0; i < vmax; ++i) { gray_lookup[i] = 0xff * i / (vmax - 1); //std::cerr << i << " = " << (int)gray_lookup[i] << std::endl; } const unsigned int bitshift = 8 - bps; int dy = 0; for (int sy = 0; dy < new_image.h && sy < image.h; ++dy) { // clear for accumulation memset (&boxes[0], 0, sizeof(boxes[0]) * new_image.w); memset (&count[0], 0, sizeof(count[0]) * new_image.w); for (; sy < image.h && sy * scaley < dy + 1; ++sy) { uint8_t z = 0; unsigned int bits = 0; for (int sx = 0; sx < image.w; ++sx) { if (bits == 0) { z = *src++; bits = 8; } const int dx = bindex[sx]; boxes[dx] += gray_lookup[z >> bitshift]; ++count[dx]; z <<= bps; bits -= bps; } } for (int dx = 0; dx < new_image.w; ++dx) { *dst = (boxes[dx] / count[dx]); ++dst; } } } void thumbnail_scale (Image& image, double scalex, double scaley) { // only optimize the regular thumbnail down-scaling if (scalex > 1 || scaley > 1) return scale(image, scalex, scaley); // thru the codec? if (!image.isModified() && image.getCodec()) if (image.getCodec()->scale(image, scalex, scaley)) return; // quick sub byte scaling if (image.bps <= 8 && image.spp == 1) { box_scale_grayX_to_gray8(image, scalex, scaley); } else { if (image.spp == 1 && image.bps > 8) colorspace_by_name(image, "gray"); else if (image.spp > 3 || image.bps > 8) colorspace_by_name(image, "rgb"); box_scale(image, scalex, scaley); } } ����������������������������������������������������������������������������������exact-image-0.9.1/lib/DistanceMatrix.hh�������������������������������������������������������������0000644�0000764�0000764�00000001134�10630037076�016370� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <vector> #include "FG-Matrix.hh" #include "Image.hh" class QueueElement; typedef std::vector<QueueElement> Queue; class DistanceMatrix : public DataMatrix<unsigned int> { public: static const unsigned int precission_shift=3; static const unsigned int undefined_dist=(unsigned int) -1; DistanceMatrix(Image& image, unsigned int fg_threshold); DistanceMatrix(const FGMatrix& image); DistanceMatrix(const DistanceMatrix& source, unsigned int x, unsigned int y, unsigned int w, unsigned int h); ~DistanceMatrix(); private: void Init(Queue& queue); void RunBFS(Queue& queue); }; ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/FG-Matrix.cc������������������������������������������������������������������0000644�0000764�0000764�00000002565�11014767041�015205� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Valentin Ziegler, ExactCODE GmbH Germany. * * 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 "FG-Matrix.hh" FGMatrix::FGMatrix(Image& image, unsigned int fg_threshold) : DataMatrix<bool>(image.w, image.h) { unsigned int line=0; unsigned int row=0; Image::iterator i=image.begin(); Image::iterator end=image.end(); for (; i!=end ; ++i) { data[row][line]=((*i).getL() < fg_threshold); if (++row == (unsigned int)image.w) { line++; row=0; } } } FGMatrix::FGMatrix(const FGMatrix& source) : DataMatrix<bool>(source, 0, 0, source.w, source.h) { } FGMatrix::FGMatrix(const FGMatrix& source, unsigned int x, unsigned int y, unsigned int w, unsigned int h) : DataMatrix<bool>(source, x,y,w,h) { } FGMatrix::~FGMatrix() { } �������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/DistanceMatrix.cc�������������������������������������������������������������0000644�0000764�0000764�00000005133�10762114316�016360� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <math.h> #include "DistanceMatrix.hh" class QueueElement { public: int x; int y; unsigned int xdiff; unsigned int ydiff; QueueElement(unsigned int i_x, unsigned int i_y) { x=i_x; y=i_y; xdiff=0; ydiff=0; } QueueElement(const QueueElement& e, int direction) { switch (direction) { case 0: x=e.x-1; y=e.y; xdiff=e.xdiff-1; ydiff=e.ydiff; break; case 1: x=e.x; y=e.y-1; xdiff=e.xdiff; ydiff=e.ydiff-1; break; case 2: x=e.x+1; y=e.y; xdiff=e.xdiff+1; ydiff=e.ydiff; break; default: x=e.x; y=e.y+1; xdiff=e.xdiff; ydiff=e.ydiff+1; } } unsigned int Value() const { return ((xdiff*xdiff) + (ydiff*ydiff)); } }; DistanceMatrix::DistanceMatrix(Image& image, unsigned int fg_threshold) : DataMatrix<unsigned int>(image.w, image.h) { Queue queue; Init(queue); int line=0, row=0; Image::iterator i=image.begin(); Image::iterator end=image.end(); for (; i!=end ; ++i) { if ((*i).getL() < fg_threshold) { queue.push_back(QueueElement(row, line)); data[row][line]=0; } if (++row == image.w) { line++; row=0; } } RunBFS(queue); } DistanceMatrix::DistanceMatrix(const FGMatrix& image) : DataMatrix<unsigned int>(image.w, image.h) { Queue queue; Init(queue); for (unsigned int x=0; x<w; x++) for (unsigned int y=0; y<h ; y++) if (image(x,y)) { queue.push_back(QueueElement(x, y)); data[x][y]=0; } RunBFS(queue); } void DistanceMatrix::Init(Queue& queue) { for (unsigned int x=0; x<w; x++) for (unsigned int y=0; y<h; y++) data[x][y]=undefined_dist; queue.reserve(4*w*h); } void DistanceMatrix::RunBFS(Queue& queue) { unsigned int pos=0; while (pos < queue.size()) { for (unsigned int direction=0; direction<4; direction++) { queue.push_back(QueueElement(queue[pos],direction)); QueueElement& last=queue.back(); unsigned int value=last.Value(); if (last.x < 0 || last.x >= (int)w || last.y < 0 || last.y >= (int)h || value >= data[last.x][last.y]) queue.pop_back(); else data[last.x][last.y]=value; } pos++; } for (unsigned int x=0; x<w; x++) for (unsigned int y=0; y<h; y++) data[x][y]=(unsigned int) sqrt((double) (data[x][y] << 2*precission_shift)); queue.clear(); } DistanceMatrix::DistanceMatrix(const DistanceMatrix& source, unsigned int x, unsigned int y, unsigned int w, unsigned int h) : DataMatrix<unsigned int>(source, x,y,w,h) { } DistanceMatrix::~DistanceMatrix() { } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/floyd-steinberg.cc������������������������������������������������������������0000644�0000764�0000764�00000006573�12453273744�016561� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Floyd Steinberg dithering based on web publications. * * Copyright (C) 2006 - 2015 René Rebe, ExactCOD GmbH Germany * * 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 "floyd-steinberg.h" #include "ImageIterator2.hh" #include <cmath> // floor #ifdef _MSC_VER #include <vector> #endif template <typename T> struct FloydSteinberg_template { void operator() (Image& image, int shades) { T it(image); typename T::accu a, a2; typename T::accu one = a.one(); const int height = image.h, width = image.w; int direction = 1; const float factor = (float) (shades - 1) / (float) one.v[0]; // row/error buffers #ifndef _MSC_VER float _error[width * image.spp]; float _nexterror[width * image.spp]; #else std::vector<float> _error(width * image.spp); std::vector<float> _nexterror(width * image.spp); #endif float* error = &_error[0]; float* nexterror = &_nexterror[0]; // initialize the error buffers for (int x = 0; x < width * image.spp; ++x) error[x] = nexterror[x] = 0; for (int y = 0; y < height; ++y) { int start, end; for (int x = 0; x < width * image.spp; ++x) nexterror[x] = 0; if (direction == 1) { start = 0; end = width; } else { direction = -1; start = width - 1; end = -1; } it.at(start, y); for (int x = start; x != end; x += direction) { a = *it; for (int channel = 0; channel < image.spp; ++channel) { float newval = a.v[channel] + error[x * image.spp + channel]; newval = floor (newval * factor + 0.5) / factor; if (newval > one.v[0]) newval = one.v[0]; else if (newval < 0) newval = 0; a2.v[channel] = newval + 0.5; float cerror = a.v[channel] + error[x * image.spp + channel] - a2.v[channel]; // limit color bleeding, limit to /4 of the sample range // TODO: make optional if (fabs(cerror) > one.v[0] / 4) { if (cerror < 0) cerror = -one.v[0] / 4; else cerror = one.v[0] / 4; } nexterror[x * image.spp + channel] += cerror * 5 / 16; if (x + direction >= 0 && x + direction < width) { error[(x + direction) * image.spp + channel] += cerror * 7 / 16; nexterror[(x + direction) * image.spp + channel] += cerror * 1 / 16; } if (x - direction >= 0 && x - direction < width) nexterror[(x - direction) * image.spp + channel] += cerror * 3 / 16; } it.set(a2); if (direction > 0) ++it; else --it; } // next row in the opposite direction direction *= -1; // swap error/nexterror float* tmp = error; error = nexterror; nexterror = tmp; } } }; void FloydSteinberg (Image& image, int shades) { codegen<FloydSteinberg_template> (image, shades); } �������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/Image2.cc���������������������������������������������������������������������0000644�0000764�0000764�00000000076�10550234425�014545� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#include <string> #include <iostream> //#include "Image2.hh" ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/floyd-steinberg.h�������������������������������������������������������������0000644�0000764�0000764�00000001505�12151730550�016375� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Floyd Steinberg dithering based on web publications. * * Copyright (C) 2006 - 2013 René Rebe, ExactCOD GmbH Germany * * 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 "Image.hh" void FloydSteinberg(Image& image, int shades); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/lib/GaussianBlur.cc���������������������������������������������������������������0000644�0000764�0000764�00000003064�11357614303�016043� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Gaussian Blur. * Copyright (C) 2008, Valentin Ziegler * * 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. * */ #include "Matrix.hh" #include "GaussianBlur.hh" void GaussianBlur(Image& image, double standard_deviation, int radius) { double sd = standard_deviation; if (radius <= 0) { double thresh=1.0/255.0; double divisor=0.0; radius=-1; double factor; do { radius++; factor=exp (-((float)radius*radius) / (2.*sd*sd)); divisor+=(radius==0) ? factor : 2.0*factor; } while (factor/(divisor*divisor) > thresh); } // compute kernel (convolution matrix to move over the iamge) matrix_type divisor = 0; matrix_type matrix[radius+1]; for (int d = 0; d <= radius; ++d) { matrix_type v = (matrix_type) (exp (-((float)d*d) / (2. * sd * sd)) ); matrix[d] = v; divisor+=v; if (d>0) divisor+=v; } // normalize (will not work with integer matrix type !) divisor=1.0/divisor; for (int i=0; i<=radius; i++) { matrix[i]*=divisor; } decomposable_sym_convolution_matrix (image, matrix, matrix, radius, radius, 0.0); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/bardecode/������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664271�014310� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/bardecode/Scanner.hh��������������������������������������������������������������0000644�0000764�0000764�00000010767�11055507507�016223� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Lars Kuhtz, ExactCODE GmbH Germany. * * 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. */ #ifndef _SCANNER_HH_ #define _SCANNER_HH_ #include <map> #include <vector> #include <string> #include "Tokenizer.hh" namespace BarDecode { // 16 bit should be enough we do not want to use all of these anyway. typedef uint16_t module_word_t; typedef uint32_t codes_t; // Bitset of types typedef unsigned int psize_t; // size in pixel type typedef unsigned int usize_t; // size in X unit typedef double u_t; // type for X unit enum code_t { ean8 = 1<<0, ean13 = 1<<1, upca = 1<<2, ean = ean8|ean13|upca, upce = 1<<3, code128 = 1<<4, gs1_128 = 1<<5, code39 = 1<<6, code39_mod43 = 1<<7, code39_ext = 1<<8, code25i = 1<<9, any_code = 0xfff }; enum directions_t { left_right = 1<<0, top_down = 1<<1, right_left = 1<<2, down_top = 1<<3, any_direction = 0xf }; std::ostream& operator<< (std::ostream& s, const code_t& t); struct bar_vector_t : public std::vector<token_t> { bar_vector_t(int s) : std::vector<token_t>(s), bpsize(0), wpsize(0), psize(0) {} psize_t bpsize; psize_t wpsize; psize_t psize; }; struct scanner_result_t { scanner_result_t() : valid(false), type(), code(""), x(0), y(0) {} scanner_result_t(code_t type, const std::string& code, pos_t x, pos_t y) : valid(true), type(type), code(code), x(x), y(y) {} bool valid; code_t type; std::string code; pos_t x; pos_t y; operator bool() const { return valid; } }; template<bool vertical = false> class BarcodeIterator { public: typedef BarcodeIterator self_t; typedef scanner_result_t value_type; typedef Tokenizer<vertical> tokenizer_t; typedef std::vector<token_t> token_line_t; static const psize_t min_quiet_psize = 7; BarcodeIterator(const Image* img, threshold_t threshold = 150, codes_t requested_codes = any_code, directions_t directions = any_direction, int concurrent_lines = 4, int line_skip = 8) : tokenizer(img,concurrent_lines,line_skip,threshold), requested_codes(requested_codes), directions(directions), cur_barcode(), token_line(), x(), y(), ti(), te() { if ( ! end() ) next(); } virtual ~BarcodeIterator() {} value_type operator*() const { return cur_barcode; } // Try to find next modulizer self_t& operator++() { assert(! end()); next(); return *this; } bool end() const { return tokenizer.end(); } private: long pixel_diff(token_line_t::const_iterator a, const token_line_t::const_iterator& b) { long ret = 0; while( a != b ) { ret += (a++)->second; } return ret; } bool requested(code_t code) const { return code & requested_codes; } void next(); private: tokenizer_t tokenizer; codes_t requested_codes; directions_t directions; scanner_result_t cur_barcode; token_line_t token_line; pos_t x, y; token_line_t::const_iterator ti,te; }; }; // namespace BarDecode #include "Scanner.tcc" #endif // _SCANNER_HH_ ���������exact-image-0.9.1/bardecode/code25i.hh��������������������������������������������������������������0000644�0000764�0000764�00000030737�11461351157�016062� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Lars Kuhtz, ExactCODE GmbH Germany. * Copyright (C) 2010 René Rebe, ExactCODE GmbH Germany. * * 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. */ #ifndef _CODE25I_HH_ #define _CODE25I_HH_ #include "scanner_utils.hh" namespace BarDecode { struct code25i_t { code25i_t(); static const int START_SEQUENCE = 0xA; static const int END_SEQUENCE = 0xD; static const char no_entry = 0; static const double n_lq = 15; static const double n_hq = 5.3; static const double w_lq = 5.2; static const double w_hq = 1.5; static const double tol = 0.2; static const usize_t min_quiet_usize = 5; //static const usize_t min_quiet_usize = 10; static const usize_t min_quiet_usize_right = 5; template<class TIT> scanner_result_t scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t) const; template<class TIT> scanner_result_t reverse_scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t) const; bool check_bar_vector(const bar_vector_t& b,psize_t old_psize, double bdisprop) const; bool reverse_check_bar_vector(const bar_vector_t& b,psize_t old_psize, double bdisprop) const; std::pair<module_word_t,module_word_t> reverse_get_keys(const bar_vector_t& b) const; std::pair<module_word_t,module_word_t> get_keys(const bar_vector_t& b) const; DECLARE_TABLE(table,0x19); }; inline code25i_t::code25i_t() { INIT_TABLE(table,0x18,no_entry); PUT_IN_TABLE(table,0x6,'0'); PUT_IN_TABLE(table,0x11,'1'); PUT_IN_TABLE(table,0x9,'2'); PUT_IN_TABLE(table,0x18,'3'); PUT_IN_TABLE(table,0x5,'4'); PUT_IN_TABLE(table,0x14,'5'); PUT_IN_TABLE(table,0xC,'6'); PUT_IN_TABLE(table,0x3,'7'); PUT_IN_TABLE(table,0x12,'8'); PUT_IN_TABLE(table,0xA,'9'); } inline std::pair<module_word_t,module_word_t> code25i_t::get_keys(const bar_vector_t& b) const { assert(b.size() == 10); #ifdef STRICT u_t n_l = ((double) b.psize / 18.0); // (((b.size/2) / (3*1+2*3)) * 1 u_t n_h = ((double) b.psize / 14.0); // (((b.size/2) / (3*1+2*2)) * 1 u_t w_l = ((double) b.psize / 7.0); // (((b.size/2) / (3*1+2*2)) * 2 u_t w_h = ((double) b.psize / 6.0); // (((b.size/2) / (3*1+2*3)) * 3 #else u_t bn_l = ((double) b.bpsize / n_lq); u_t bn_h = ((double) b.bpsize / n_hq); u_t bw_l = ((double) b.bpsize / w_lq); u_t bw_h = ((double) b.bpsize / w_hq); u_t wn_l = ((double) b.wpsize / n_lq); u_t wn_h = ((double) b.wpsize / n_hq); u_t ww_l = ((double) b.wpsize / w_lq); u_t ww_h = ((double) b.wpsize / w_hq); #endif module_word_t r1 = 0; module_word_t r2 = 0; for (uint i = 0; i < 10; ++i) { r1 <<= 1; if (bw_l <= b[i].second && b[i].second <= bw_h) r1 += 1; else if (! (bn_l <= b[i].second && b[i].second <= bn_h)) { return std::make_pair(0,0); } ++i; r2 <<= 1; if (ww_l <= b[i].second && b[i].second <= ww_h) r2 += 1; else if (! (wn_l <= b[i].second && b[i].second <= wn_h)) { return std::make_pair(0,0); } } return std::make_pair(r1,r2); } inline std::pair<module_word_t,module_word_t> code25i_t::reverse_get_keys(const bar_vector_t& b) const { assert(b.size() == 10); #ifdef STRICT u_t n_l = ((double) b.psize / 18.0); // (((b.size/2) / (3*1+2*3)) * 1 u_t n_h = ((double) b.psize / 14.0); // (((b.size/2) / (3*1+2*2)) * 1 u_t w_l = ((double) b.psize / 7.0); // (((b.size/2) / (3*1+2*2)) * 2 u_t w_h = ((double) b.psize / 6.0); // (((b.size/2) / (3*1+2*3)) * 3 #else u_t bn_l = ((double) b.bpsize / n_lq); u_t bn_h = ((double) b.bpsize / n_hq); u_t bw_l = ((double) b.bpsize / w_lq); u_t bw_h = ((double) b.bpsize / w_hq); u_t wn_l = ((double) b.wpsize / n_lq); u_t wn_h = ((double) b.wpsize / n_hq); u_t ww_l = ((double) b.wpsize / w_lq); u_t ww_h = ((double) b.wpsize / w_hq); #endif module_word_t r1 = 0; module_word_t r2 = 0; for (int i = 9; i >= 0; --i) { r1 <<= 1; if (bw_l <= b[i].second && b[i].second <= bw_h) r1 += 1; else if (! (bn_l <= b[i].second && b[i].second <= bn_h)) { return std::make_pair(0,0); } --i; r2 <<= 1; if (ww_l <= b[i].second && b[i].second <= ww_h) r2 += 1; else if (! (wn_l <= b[i].second && b[i].second <= wn_h)) { return std::make_pair(0,0); } } return std::make_pair(r2,r1); } inline bool code25i_t::check_bar_vector(const bar_vector_t& b,psize_t old_psize, double bdisprop) const { // check psize // check colors assert(b.size() == 10); #if 0 return (!old_psize || fabs((long)b.psize - (long)old_psize) < 0.5 * old_psize) && b[0].first && b[8].first; #else if (old_psize && ! (fabs((long) b.psize - (long) old_psize) < 0.5 * old_psize)) { return false; } else if (b.bpsize < (1-tol) * (b.psize * bdisprop * 0.5) || b.bpsize > (1+tol) * (b.psize * bdisprop * 0.5)) { return false; } else if ( ! b[0].first || b[9].first ) { return false; } else return true; #endif } inline bool code25i_t::reverse_check_bar_vector(const bar_vector_t& b,psize_t old_psize, double bdisprop) const { // check psize // check colors assert(b.size() == 10); #if 0 return (!old_psize || fabs((long)b.psize - (long)old_psize) < 0.5 * old_psize) && b[0].first && b[8].first; #else if (old_psize && ! (fabs((long) b.psize - (long) old_psize) < 0.5 * old_psize)) { return false; } else if (b.bpsize < (1-tol) * (b.psize * bdisprop * 0.5) || b.bpsize > (1+tol) * (b.psize * bdisprop * 0.5)) { return false; } else if ( b[0].first || ! b[9].first ) { return false; } else return true; #endif } template<class TIT> scanner_result_t code25i_t::scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t quiet_psize) const { using namespace scanner_utilities; // try to match start marker // do relatively cheap though rough test on the first two bars only. bar_vector_t b(4); if ( get_bars(start,end,b,2) != 2 ) return scanner_result_t(); // lax-check (assymetric: we assume that black bars might be wider) if (b[0].second < 0.7 * b[1].second || b[0].second > 3 * b[1].second) return scanner_result_t(); // check quiet_zone with respect to length of the first symbol if (quiet_psize < (double) (b[0].second + b[1].second) * 5 * 0.5) return scanner_result_t(); // 10 x quiet zone if ( add_bars(start,end,b,2) != 2 ) return scanner_result_t(); // strict-check if (b[0].second < 0.7 * b[2].second || b[0].second > 1.3 * b[2].second) return scanner_result_t(); if (b[1].second < 0.7 * b[3].second || b[1].second > 1.3 * b[3].second) return scanner_result_t(); const double wdisprop = b.wpsize / (b.psize * 0.5); const double bdisprop = b.bpsize / (b.psize * 0.5); std::string code; psize_t old_psize = 0; bool at_end = false; while (! at_end) { // get new symbols if ( get_bars(start,end,b,3) != 3) return scanner_result_t(); // check END sequence and expect quiet zone // TODO compare b[1] with value from start sequence? or better use disprop factor. if ( b[0].second < b[2].second * 3.1 * 1.3 && b[0].second > b[2].second * 2 * 0.7 && b[1].second < b.psize * 0.25 * (1+tol) * wdisprop && b[1].second > b.psize * 0.18 * (1-tol) * wdisprop) { if ((start+1)->second > b.psize * 1.3) { break; } } if ( add_bars(start,end,b,7) != 7) return scanner_result_t(); if (! check_bar_vector(b,old_psize,bdisprop) ) return scanner_result_t(); old_psize = b.psize; std::pair<module_word_t,module_word_t> keys = get_keys(b); if (! keys.first || ! keys.second ) return scanner_result_t(); const char c1 = table[keys.first]; if (c1 == no_entry) return scanner_result_t(); code.push_back(c1); const char c2 = table[keys.second]; if (c2 == no_entry) return scanner_result_t(); code.push_back(c2); } if ( code.empty() ) return scanner_result_t(); else { return scanner_result_t(code25i,code,x,y); } } template<class TIT> scanner_result_t code25i_t::reverse_scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t quiet_psize) const { using namespace scanner_utilities; // try to match end marker: 1 1 2 / 1 1 3 bar_vector_t b(3); if ( get_bars(start,end,b,2) != 2 ) return scanner_result_t(); // lax-check (assymetric) if (b[0].second < 0.7 * b[1].second || b[0].second > 3 * b[1].second) return scanner_result_t(); // check quiet_zone with respect to length of the first symbol if (quiet_psize < (double) (b[0].second + b[1].second) * 5 * 0.5) return scanner_result_t(); // 10 x quiet zone if ( add_bars(start,end,b,1) != 1 ) return scanner_result_t(); // strict-check (TODO) if ( b[0].second < 0.3 * 0.7 * b[2].second || b[0].second > 0.5 * 1.3 * b[2].second ) return scanner_result_t(); const double bdisprop = b.bpsize / (b.psize * 0.75); std::string code = ""; psize_t old_psize = 0; bool at_end = false; while (! at_end) { // get new symbols if ( get_bars(start,end,b,4) != 4) return scanner_result_t(); // check START sequence and expect quiet zone static const double ltol = 0.3; if ( b.bpsize > (1-tol) * (b.psize * bdisprop * 0.5) && b.bpsize < (1+tol) * (b.psize * bdisprop * 0.5) && (b.bpsize / (double) b[3].second) > 2 * (1-ltol) && (b.bpsize / (double) b[3].second) < 2 * (1+ltol) && (b.wpsize / (double) b[2].second) > 2 * (1-ltol) && (b.wpsize / (double) b[2].second) < 2 * (1+ltol) && (b.bpsize / (double) b[1].second) > 2 * (1-ltol) && (b.bpsize / (double) b[1].second) < 2 * (1+ltol) && (b.wpsize / (double) b[0].second) > 2 * (1-ltol) && (b.wpsize / (double) b[0].second) < 2 * (1+ltol)) { // FIXME make this in a more performant way if ((start+1)->second > b.psize * 1) { break; } } if ( add_bars(start,end,b,6) != 6 ) return scanner_result_t(); if (! reverse_check_bar_vector(b,old_psize,bdisprop) ) return scanner_result_t(); old_psize = b.psize; std::pair<module_word_t,module_word_t> keys = reverse_get_keys(b); if (! keys.first || ! keys.second ) return scanner_result_t(); const char c1 = table[keys.first]; if (c1 == no_entry) return scanner_result_t(); code.push_back(c1); const char c2 = table[keys.second]; if (c2 == no_entry) return scanner_result_t(); code.push_back(c2); } if ( code.empty() ) return scanner_result_t(); else { return scanner_result_t(code25i,std::string(code.rbegin(),code.rend()),x,y); } } }; // namespace BarDecode #endif // _CODE25I_HH_ ���������������������������������exact-image-0.9.1/bardecode/ean.hh������������������������������������������������������������������0000644�0000764�0000764�00000023075�11457530260�015367� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Lars Kuhtz, ExactCODE GmbH Germany. * Copyright (C) 2010 René Rebe, ExactCODE GmbH Germany. * * 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. */ #ifndef _EAN_HH_ #define _EAN_HH_ #include "scanner_utils.hh" namespace BarDecode { struct ean_t { enum { normal_guard = 1, center_guard = 2, special_guard = 3, add_on_guard = 4, add_on_delineator = 5 }; static const usize_t min_quiet_usize = 5; // static const usize_t min_quiet_usize = 7; ean_t(); template<class TIT> scanner_result_t scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t, directions_t dir = any_direction); DECLARE_TABLE(table,128); DECLARE_TABLE(ean13table,64); DECLARE_TABLE(auxtable,32); }; inline ean_t::ean_t() { // EAN Tables (table A,B,C are put into onei array) (5.1.1.2.1) INIT_TABLE(table,128,0); // EAN Table A (parity odd) PUT_IN_TABLE(table,0x0D,'0'); PUT_IN_TABLE(table,0x19,'1'); PUT_IN_TABLE(table,0x13,'2'); PUT_IN_TABLE(table,0x3D,'3'); PUT_IN_TABLE(table,0x23,'4'); PUT_IN_TABLE(table,0x31,'5'); PUT_IN_TABLE(table,0x2F,'6'); PUT_IN_TABLE(table,0x3B,'7'); PUT_IN_TABLE(table,0x37,'8'); PUT_IN_TABLE(table,0x0B,'9'); // EAN Table B (parity even) #define EANB(a) (0x40&(((~a)&127)<<6)) | \ (0x20&(((~a)&127)<<4)) | \ (0x10&(((~a)&127)<<2)) | \ (0x01&(((~a)&127)>>6)) | \ (0x02&(((~a)&127)>>4)) | \ (0x04&(((~a)&127)>>2)) | \ (0x08&((~a)&127)) // mirror of EANC PUT_IN_TABLE(table,EANB(0x0D),'0'); PUT_IN_TABLE(table,EANB(0x19),'1'); PUT_IN_TABLE(table,EANB(0x13),'2'); PUT_IN_TABLE(table,EANB(0x3D),'3'); PUT_IN_TABLE(table,EANB(0x23),'4'); PUT_IN_TABLE(table,EANB(0x31),'5'); PUT_IN_TABLE(table,EANB(0x2F),'6'); PUT_IN_TABLE(table,EANB(0x3B),'7'); PUT_IN_TABLE(table,EANB(0x37),'8'); PUT_IN_TABLE(table,EANB(0x0B),'9'); // EAN Table C (parity even) #define EANC(a) (~a)&127 // bit complement of A (7 bit) PUT_IN_TABLE(table,EANC(0x0D),'0'); PUT_IN_TABLE(table,EANC(0x19),'1'); PUT_IN_TABLE(table,EANC(0x13),'2'); PUT_IN_TABLE(table,EANC(0x3D),'3'); PUT_IN_TABLE(table,EANC(0x23),'4'); PUT_IN_TABLE(table,EANC(0x31),'5'); PUT_IN_TABLE(table,EANC(0x2F),'6'); PUT_IN_TABLE(table,EANC(0x3B),'7'); PUT_IN_TABLE(table,EANC(0x37),'8'); PUT_IN_TABLE(table,EANC(0x0B),'9'); // EAN Auxiliary Pattern Table (5.1.1.2.2) INIT_TABLE(auxtable,32,0); PUT_IN_TABLE(auxtable,0x05,normal_guard); // normal guard pattern, 3 modules PUT_IN_TABLE(auxtable,0x0A,center_guard); // center guard pattern, 5 modules PUT_IN_TABLE(auxtable,0x15,special_guard); // special guard pattern, 6 modules PUT_IN_TABLE(auxtable,0x0B,add_on_guard); // add-on guard pattern, 4 modules PUT_IN_TABLE(auxtable,0x01,add_on_delineator); // add-on delineator, 2 modules INIT_TABLE(ean13table,64,0); PUT_IN_TABLE(ean13table,0x3f,'0'); PUT_IN_TABLE(ean13table,0x34,'1'); PUT_IN_TABLE(ean13table,0x32,'2'); PUT_IN_TABLE(ean13table,0x31,'3'); PUT_IN_TABLE(ean13table,0x2c,'4'); PUT_IN_TABLE(ean13table,0x26,'5'); PUT_IN_TABLE(ean13table,0x23,'6'); PUT_IN_TABLE(ean13table,0x2a,'7'); PUT_IN_TABLE(ean13table,0x29,'8'); PUT_IN_TABLE(ean13table,0x25,'9'); } // scanner_result_t() indicates failure template<class TIT> scanner_result_t ean_t::scan(TIT& start, TIT end, pos_t x, pos_t y,psize_t quiet_psize, directions_t dir) { using namespace scanner_utilities; bool scan_reverted = dir & right_left; bool scan_normal = dir & left_right; // try to match start marker // try ean with 3 bars bar_vector_t b(3); if ( get_bars(start,end,b,2) != 2) return scanner_result_t(); if ( b[0].second > 2 * b[1].second || b[0].second < 0.5 * b[1].second ) return scanner_result_t(); if ( add_bars(start,end,b,1) != 1) return scanner_result_t(); // get a first guess for u u_t u = (double) b.psize / 3.0; // 3 is the number of modules of the start sequence // check if u is within max_u imposed by quiet_zone if ( u > max_u<ean_t>(quiet_psize) ) return scanner_result_t(); // expect start sequence module_word_t mw = get_module_word_adjust_u(b,u,3); char result = auxtable[mw]; std::string code = ""; if (result != normal_guard) return scanner_result_t(); // Ok, we found an ean start sequence, let's try to read the code: uint bps = 4; // (bars per symbol) a symbol has 4 bars module_word_t parities = 0; uint symbols_count = 0; result = 0; b.resize(bps); bool reverted = false; do { // get symbol if ( get_bars(start,end,b,4) != 4 ) return scanner_result_t(); // decide if to go for a symbol (7 modules) or the center_guard (4 modules) // FIXME FIXME FIXME Getting this right is crucial! Do not use a value that is to big if ( symbols_count == 6 ) break; //if ( symbols_count == 4 && fabs(((double)b.psize / 4.0) - u) <= (u * 0.25) ) break; if ( symbols_count == 4 && get_module_word(b,u,4) ) break; // lets assume 7 modules module_word_t mw = get_module_word_adjust_u(b,u,7); if ( ! mw ) return scanner_result_t(); result = table[mw]; if (! result) return scanner_result_t(); if ( symbols_count == 0 ) { if (! get_parity(mw) ) { if (! scan_reverted ) return scanner_result_t(); reverted = true; } else if ( ! scan_normal ) return scanner_result_t(); } ++symbols_count; if (! reverted) { parities <<= 1; parities |= get_parity(mw); } code += result; } while ( true ); // only way to leave is a failure return or the center_guard break above // check if we found a symbol at all if ( ! symbols_count ) return scanner_result_t(); // consume the next bar (it belongs to the center_guard, that we expect) if (add_bars(start,end,b,1) != 1) return scanner_result_t(); // expect the center guard (with 5 modules) mw = get_module_word_adjust_u(b,u,5); if ( ! mw || auxtable[mw] != center_guard) return scanner_result_t(); // TODO check for special guard (we need to implement add_bar() method // Decode the second half of the barcode // TODO if (symbols_count != 6 && symbols_count != 4) return scanner_result_t(); for (uint i = 0; i < symbols_count; ++i) { if ( get_bars(start,end,b,4) != 4 ) return scanner_result_t(); module_word_t mw = get_module_word_adjust_u(b,u,7); if ( ! mw ) return scanner_result_t(); if (reverted) { result = table[0x3f & ~mw]; } else { result = table[mw]; } if (! result) return scanner_result_t(); code += result; if (reverted) { parities >>= 1; parities |= (! get_parity(0x3f & ~mw) << 5); } } // expect normal guard if ( get_bars(start,end,b,3) != 3) return scanner_result_t(); mw = get_module_word_adjust_u(b,u,3); if ( ! mw ) return scanner_result_t(); result = auxtable[mw]; if (result == normal_guard) { // TODO check right quiet zone } else if (result == add_on_guard) { // TODO assert(false && "TODO"); } else { return scanner_result_t(); } if (reverted) { code = std::string(code.rbegin(),code.rend()); } // get type and lookup bit 0 for ean13 code_t type = ean; if (symbols_count == 6) { result = ean13table[parities]; if (! result) return scanner_result_t(); if ( result == '0' ) { type = upca; } else { code = std::string(1,result) + code; type = ean13; } } else { type = ean8; } // checksum test int check = code[code.size()-1] - 48; code.erase(code.size()-1); int sum = 0; int f = 3; for (int i = (int)code.size()-1; i >= 0; --i) { sum += (code[i]-48)*f; f = ((f==1) ? 3 : 1); } if (10-(sum % 10) != check) return scanner_result_t(); // scan modules according to code_type return scanner_result_t(type,code,x,y); } }; // namespace BarDecode #endif // _EAN_HH_ �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/bardecode/concept.txt�������������������������������������������������������������0000644�0000764�0000764�00000013024�11007034706�016463� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Lars Kuhtz, ExactCODE GmbH Germany. * * 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. */ IDEAS: * calculate threshold dynamically: try to identify edges (or different more or less constant levels) put the threshold inbetween. * Try mean of bar code region (look ahead and adjust threshold) * Try median of bar code region * Try to compensate single "flipped bits" (local noise: far to narrow for a bar and no vertical continuity (but see also vertical interpolation) * Use a different metric on interpolation that considers more the media (majority vote) or at least rules out extrem deviations * Compute angle (using first bar) and adjust vertical interpolation by advancing/ delaying the iterators. ===================================================================== Tokenizer: split each line into tokens. A token is a pair (bool,uint) that consist of the color (white=0 or black=1) and the length (nr. of sequential pixels that have that color). Modulizer: Translates tokens into modules (Requires initialization: unit value, etc.) Line Scanner: Identifies barcodes (or partial rotated barcodes) on a single line (Requires initialization by a valid Modulizer) Vertical Matcher: * concatenates partial codes * Does consistency checks (height, quiet zone, layout, etc.) * Identifies line matches that belong to the same code Semantic Checker: * Check consistency with repect to the content of the code. The vertial matcher should be optional. The semantic checker will not be implemented in the near future. ===================================================================== The whole scanning can be performed a second time on an image that is rotated by 90 deg. Depending on the format it might be useful to scan at 180 and 270 deg. as well. For the most common codes UPC-A and derivates this is not necessary because of parity encoding. ===================================================================== Tokenizer: * Stateless ===================================================================== Modulizer: * Translate tokens into modules which is simply a bit (0 is white, 1 is black). * It gets a token and splits it into modules * length-check are fuzzy with respect to the specification of the barcode type * Has different modes * Depends on unit * barcode type (fuzzyness) * Common Init pattern: * Get quiet-zone (white,q) * Get first black token and compute unit from it (according to code type) --> Hopefully all start markes for all codes start with a 1-module bar!!! * Check size of q * Choose mode * Maintains some general properties of the barcode, like number of black/white modules, unit width, quiet-zone size, absolut position (in pixel) ==================================================================== Line Scanner: * Internal State (infinit, well bounded by the length of a line/ counter automaton) * Translate sequence of modules into symbols * Depends on the barcode type * Depends on the internal state (Alphabet, parity, middle mark, etc.) * Collects a code depeneden number of modules into a module_word. * Does consitency check on the module_word: e.g. First module is 1, last module is 0. * Depending on the barcode type, parity, middle mark, alphabet, etc. different matcher (statically optimized tables) are dynamically attached to the scanner. * Depending on barcode type a certain number of modules are joined and passed as a whole to the translation table. * Encoding: a bitvector. We use uint16_t which should suffice for all codes Let (x_i)_{0 \leq i \leq n} be a module_word (bitvector). Then for all valid symbols of all codes x_0 = 1 and x_n = 0. Hence we only use (x_i)_{1 \leq i \leq n-1} for looking up the symbol. We use unit16_t. The largest code (code128) uses 11-bit module_word. Hence for the lookup we use 9 bit. The leading 16-(n-1) bits are filled up with zeros. Hence it suffices for code128 to allocate an array (of char) of size 512. This way we gain constant lookup time. Alternatively we can save memory and use a binary lookup in an uint16_t indexed map. * Postprocessing: * Checksums * Evalutate parity information * order of symbols * EAN-13: first symbol * Datastructure: std::vector< std::pair<char,bool> > where uint stores the symbol and bool stores the parity. * Translation Tables: Input: uint_32 Output: std::pair<char,bool> (symbol,parity) Matching: via hash? via switch? via BTree? --> First approach: std::map<uint_32, std::pair<char,bool> > Questions: * Is the start sequence unique to identfy the barcode-type * Shall we use a regular expression engine for the fixed size codes * For variable length codes we can use a regular expression engine as well. However, do these engines allow for arbitrary return parameters? * Shall we compile all types into one automaton or shall we provide a single automaton for each type (or both)? * Shall we use a generator or hardcode the automaton by hand? ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/bardecode/Scanner.cc��������������������������������������������������������������0000644�0000764�0000764�00000002631�11007034706�016171� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Lars Kuhtz, ExactCODE GmbH Germany. * * 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 "Scanner.hh" namespace BarDecode { std::ostream& operator<< (std::ostream& s, const code_t& t) { switch(t) { case ean8: return s << "ean8"; case ean13: return s << "ean13"; case upca: return s << "upca"; case ean8|ean13|upca: return s << "ean"; case upce: return s << "upce"; case code128: return s << "code128"; case gs1_128: return s << "GS1-128"; case code39: return s << "code39"; case code39_mod43: return s << "code39_mod43"; case code39_ext: return s << "code39_ext"; case code25i: return s << "code25i"; default: return s << "unknown barcode type"; } } }; // namespace BarDecode �������������������������������������������������������������������������������������������������������exact-image-0.9.1/bardecode/Scanner.tcc�������������������������������������������������������������0000644�0000764�0000764�00000012775�11457530260�016374� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Lars Kuhtz, ExactCODE GmbH Germany. * Copyright (C) 2010 René Rebe, ExactCODE GmbH Germany. * * 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 "scanner_utils.hh" #include "code128.hh" #include "code25i.hh" #include "code39.hh" #include "ean.hh" namespace BarDecode { namespace { ean_t ean_impl; code128_t code128_impl; code39_t code39_impl; code25i_t code25i_impl; }; // TODO make all tables static (would be nice to have something like designated initializers // like in C99 in C++ as well...) We do not have. Hence we need to work around. // possibly by encapsulating the tables into objects with constructors that // perform the initialization. template<bool v> void BarcodeIterator<v>::next() { assert( ! end()); pos_t& vx = v ? y : x; pos_t& vy = v ? x : y; while (! end() ) { if (ti == te) { vx = 0; vy = v ? tokenizer.get_x() : tokenizer.get_y(); tokenizer.next_line(token_line); ti = token_line.begin(); te = token_line.end(); } // goto next white space of psize >= min_quiet_psize, that is followed by black if ( ti+1 == te ) { ++ti; continue; } token_t t = *ti; token_t lookahead = *(ti+1); while ((! lookahead.first || t.first || t.second < min_quiet_psize) && (++ti + 1 != te) ) { // while black ... vx += t.second; t = lookahead; lookahead = *(ti+1); } if ( ti+1 == te ) { ++ti; continue; } assert(! t.first); // assert white /* ***************************** */ // preliminary checks // each (non empty) Barcode has at least 24 modules (including both quiet zones)! if (te - ti < 24) { ti = te; continue; } psize_t quiet_psize = t.second; // check quiet_zone against minimal requirement from all code types if (lookahead.second * 3 > quiet_psize) { vx += t.second; ++ti; continue;} // not enough space left on line for minimal barcode width: //if (lookahead.second/3.0 * 14 + tokenizer.get_x() >= tokenizer.get_img()->w) continue; /* ***************************** */ token_line_t::const_iterator backup_i = ti; scanner_result_t result; // try scanning for all requested barcode types if (directions&left_right && requested(code39)) { if ((result = code39_impl.scan(ti,te,x+ti->second,y,quiet_psize))) { cur_barcode = result; vx += pixel_diff(backup_i,ti); return; } } if ( directions&right_left && requested(code39)) { ti = backup_i; if ((result = code39_impl.reverse_scan(ti,te,x+ti->second,y,quiet_psize))) { cur_barcode = result; vx += pixel_diff(backup_i,ti); return; } } if ( directions&left_right && requested(code25i)) { ti = backup_i; if ((result = code25i_impl.scan(ti,te,x+ti->second,y,quiet_psize))) { cur_barcode = result; vx += pixel_diff(backup_i,ti); return; } } if ( directions&right_left && requested(code25i)) { ti = backup_i; if ((result = code25i_impl.reverse_scan(ti,te,x+ti->second,y,quiet_psize))) { cur_barcode = result; vx += pixel_diff(backup_i,ti); return; } } if ( directions&left_right && requested(code128)) { ti = backup_i; if (result = code128_impl.scan(ti,te,x+ti->second,y,quiet_psize)) { cur_barcode = result; vx += pixel_diff(backup_i,ti); return; } } if ( directions&right_left && requested(code128)) { ti = backup_i; if (result = code128_impl.reverse_scan(ti,te,x+ti->second,y,quiet_psize)) { cur_barcode = result; vx += pixel_diff(backup_i,ti); return; } } if ( directions&(left_right|right_left) && requested(ean) ) { ti = backup_i; if ((result = ean_impl.scan(ti,te,x+ti->second,y,quiet_psize,directions)) ) { cur_barcode = result; vx += pixel_diff(backup_i,ti); return; } } vx += backup_i->second; ti = ++backup_i; } } }; // namespace BarDecode ���exact-image-0.9.1/bardecode/Makefile����������������������������������������������������������������0000644�0000764�0000764�00000000202�11460575356�015737� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������include build/top.make BINARY = bardecode BINARY_EXT = $(X_LIBEXT) DEPS = CPPFLAGS += -I bardecode include build/bottom.make ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/bardecode/Tokenizer.hh������������������������������������������������������������0000644�0000764�0000764�00000020724�11457530260�016574� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Lars Kuhtz, ExactCODE GmbH Germany. * Copyright (C) 2009 - 2010 René Rebe, ExactCODE GmbH Germany. * * 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. */ #ifndef _TOKENIZER_HH_ #define _TOKENIZER_HH_ #include <utility> #include <assert.h> #include <math.h> #include <algorithm> #include "Image.hh" #include "PixelIterator.hh" namespace BarDecode { // Shall we include absolut position? typedef std::pair<bool,uint> token_t; // (color,length in pixels) typedef bool module_t; typedef double unit_t; template<bool vertical = false> class Tokenizer { public: Tokenizer(const Image* img, int concurrent_lines = 4, int line_skip = 8, threshold_t threshold = 150) : img(img), it(img,concurrent_lines,line_skip,threshold), extra(0), initial_threshold(threshold) {} virtual ~Tokenizer() {} void next_line(std::vector<token_t>& result) { assert(! end()); assert(vertical ? it.get_y() == 0 : it.get_x() == 0); result.clear(); it.set_threshold(initial_threshold); //std::cerr << "========== 0 " << it.get_threshold() << std::endl; bool color = *it; double count = 1; double lum; #define DYNAMIC_THRESHOLD #ifdef DYNAMIC_THRESHOLD double sum = 0; #endif double old_mean = it.get_lum(); for (long i = 0; i < it.get_line_length(); ++i,++it,++count) { lum = it.get_lum(); #ifdef DYNAMIC_THRESHOLD sum += lum; #endif #ifdef DYNAMIC_THRESHOLD double mean = sum / count; //std::cerr << "---------------- lum=" << lum << " sum=" << sum << " count=" << count << " mean=" << mean << std::endl; static const int contrast_threshold = 30; if ( ! color && lum > it.get_threshold() && lum < mean - contrast_threshold) { //it.set_threshold(lround(std::max((double)it.get_threshold(),std::min((mean - contrast_threshold)/2,220.0)))); it.set_threshold(lround(std::min((mean - contrast_threshold),220.0))); } else if ( ! color && lum > it.get_threshold() && (old_mean && lum < old_mean - (contrast_threshold+10))) { it.set_threshold(lround(std::min((old_mean - (contrast_threshold+10)),220.0))); } else if ( color && lum < it.get_threshold() && (lum > mean + contrast_threshold)) { //it.set_threshold(lround(std::min((double)it.get_threshold(),std::max((mean + contrast_threshold)/2,80.0)))); it.set_threshold(lround(std::max((mean + contrast_threshold),80.0))); } else if ( color && lum < it.get_threshold() && (old_mean && lum > old_mean + contrast_threshold+10)) { it.set_threshold(lround(std::max((old_mean + contrast_threshold+10),80.0))); } #if 1 //else if ( color && count > 20 && lum < it.get_threshold() && lum < mean - contrast_threshold && it.get_threshold() > initial_threshold) { else if ( color && count > 20 && lum < it.get_threshold() && lum < mean - contrast_threshold /*&& it.get_threshold() > initial_threshold*/) { color = false; it.set_threshold(lround(mean - contrast_threshold)); //it.set_threshold(initial_threshold); } else if ( color && count > 20 && lum < it.get_threshold() && lum < old_mean - (contrast_threshold+10) /*&& it.get_threshold() > initial_threshold*/) { color = false; it.set_threshold(lround(old_mean - (contrast_threshold+10))); //it.set_threshold(initial_threshold); } old_mean = mean; #endif //mean = ( *it ? std::min(mean,lum) : std::max(mean,lum)); #endif if (color != *it || i == it.get_line_length()-1) { #define SUBPIXEL_ADJUST #ifdef SUBPIXEL_ADJUST count -= extra; double extra = ( ! color ? (lum / 255.0) : (1- (lum / 255.0))); count += extra; extra = 1 - extra; #endif result.push_back(token_t(color,lround(count))); #define DYNAMIC_THRESHOLD #ifdef DYNAMIC_THRESHOLD sum = 0; #endif count = 0; color = *it; } } } // precondition: ! end() // FIXME use extra only if u is small enough such that subpixel dimensions matter token_t next() { assert(! end()); #define DYNAMIC_THRESHOLD #ifdef DYNAMIC_THRESHOLD double sum = 0; #endif double count = 0; bool color = *it; // TODO simple alternation would safe the call of operator* double lum = it.get_lum(); //double mean = lum; do { #ifdef DYNAMIC_THRESHOLD sum += lum; #endif ++count; ++it; lum = it.get_lum(); #ifdef DYNAMIC_THRESHOLD double mean = sum / count; static const int contrast_threshold = 50; if ( ! color && lum > it.get_threshold() && lum < mean - contrast_threshold) { // std::cerr << "0 adjust from " << it.get_threshold() << " to "; //it.set_threshold(lround(std::max((double)it.get_threshold(),std::min((mean - contrast_threshold)/2,220.0)))); it.set_threshold(lround(std::min((mean - contrast_threshold),220.0))); //std::cerr << it.get_threshold() << std::endl; break; } else if ( color && lum < it.get_threshold() && lum > mean + contrast_threshold) { //std::cerr << "1 adjust from " << it.get_threshold() << " to "; //it.set_threshold(lround(std::min((double)it.get_threshold(),std::max((mean + contrast_threshold)/2,80.0)))); it.set_threshold(lround(std::max((mean + contrast_threshold),80.0))); //std::cerr << it.get_threshold() << std::endl; break; } #if 1 else if ( color && count > 10 && lum < it.get_threshold() && lum < mean - contrast_threshold /* && it.get_threshold() > initial_threshold*/) { color = false; // std::cerr << "2 adjust from " << it.get_threshold() << " to "; it.set_threshold(lround(mean - contrast_threshold)); //it.set_threshold(initial_threshold); //std::cerr << it.get_threshold() << std::endl; //break; } #endif //mean = ( *it ? std::min(mean,lum) : std::max(mean,lum)); #endif } while ( ! end() && color == *it ); #define SUBPIXEL_ADJUST #ifdef SUBPIXEL_ADJUST count -= extra; double extra = ( ! color ? (lum / 255.0) : (1- (lum / 255.0))); count += extra; extra = 1 - extra; #endif return token_t(color,lround(count)); } bool end() const { return it.end(); } threshold_t get_threshold() const { return it.get_threshold(); } void set_threshold(threshold_t new_threshold) { it.set_threshold(new_threshold); } pos_t get_x() const { return it.get_x(); } pos_t get_y() const { return it.get_y(); } const Image* get_img() const { return img; } Tokenizer at(pos_t x, pos_t y) const { Tokenizer tmp = *this; tmp.it = it.at(x,y); return tmp; } protected: const Image* img; PixelIterator<vertical> it; #ifdef SUBPIXEL_ADJUST double extra; #endif threshold_t initial_threshold; }; }; // namespace BarDecode #endif // _TOKENIZER_HH_ ��������������������������������������������exact-image-0.9.1/bardecode/PixelIterator.hh��������������������������������������������������������0000644�0000764�0000764�00000022713�11457530260�017415� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Lars Kuhtz, ExactCODE GmbH Germany. * Copyright (C) 2009 - 2010 René Rebe, ExactCODE GmbH Germany. * * 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. */ #ifndef _PIXEL_ITERATOR_HH_ #define _PIXEL_ITERATOR_HH_ #include "Image.hh" #include <iterator> #include <vector> #ifdef __APPLE__ #include <sys/types.h> #endif namespace BarDecode { typedef int pos_t; typedef int threshold_t; template<bool vertical = false> class PixelIterator : public std::iterator<std::output_iterator_tag, bool, std::ptrdiff_t> { protected: typedef PixelIterator self_t; public: typedef bool value_type; PixelIterator(const Image* img, int concurrent_lines = 4, int line_skip = 8, threshold_t threshold = 0) : img(img), it_size(concurrent_lines), line_skip(line_skip), img_it(it_size), threshold(threshold), x(0), y(0), lum(0), valid_cache(false) { // FIXME insert an optimized code path for img->h <= it_size for (int i = 0; i < it_size; ++i) { img_it[i] = img->begin().at(0,std::min((int)i,img->h-1)); *img_it[i]; } } virtual ~PixelIterator() {}; self_t& operator++() { valid_cache = false; if ( x < img->w-1 ) { ++x; for (int i = 0; i < it_size; ++i) { ++img_it[i]; *img_it[i]; } } else { x = 0; int todo = (img->h-1) - y; if ( todo > line_skip + (it_size-1) ) { y += line_skip; for (int i = 0; i < it_size; ++i) { img_it[i] = img_it[i].at(x,y+(int)i); *img_it[i]; } } else if ( todo <= line_skip ) { // we are at the end //++img_it[it_size-1]; img_it[it_size-1] = img->end(); } else { y += line_skip; for (int i = 0; i < it_size; ++i) { img_it[i] = img_it[i].at(x,std::min(y+(int)i,img->h-1)); *img_it[i]; } } } return *this; }; // FIXME it seems that the median (or something similar) is the better choice. const value_type operator*() const { if (valid_cache) return cache; double tmp=0; //uint16_t min = 255; //uint16_t max = 0; for (int i = 0; i < it_size; ++i) { //min = std::min(min,img_it[i].getL()); //max = std::max(max,img_it[i].getL()); tmp += img_it[i].getL(); } //lum = (tmp - (double) (min+max)) / (double) (it_size-2); lum = tmp / it_size; cache = lum < threshold; valid_cache = true; return cache; } //value_type* operator->(); //const value_type* operator->() const; self_t at(pos_t x, pos_t y) const { // FIXME insert an optimized code path for img->h >= y+it_size self_t tmp = *this; for (int i = 0; i < it_size; ++i) { tmp.img_it[i] = tmp.img_it[i].at(x,std::min(y+(int)i,img->h)); } tmp.valid_cache = false; tmp.x = x; tmp.y = y; return tmp; } pos_t get_x() const { return x; } pos_t get_y() const { return y; } threshold_t get_threshold() const { return threshold; } void set_threshold(threshold_t new_threshold) { valid_cache = false; threshold = new_threshold; } bool end() const { return !(img_it[it_size-1] != img->end()); } double get_lum() const { if (! valid_cache) { operator*(); } return lum; } long get_x_size() const { return img->w; } long get_y_size() const { return img->h; } long get_line_length() const { return get_x_size(); } protected: const Image* img; int it_size; int line_skip; std::vector<Image::const_iterator> img_it; threshold_t threshold; pos_t x; pos_t y; mutable double lum; mutable bool cache; mutable bool valid_cache; }; // class PixelIterator<vertical = true> // vertical iteration template<> class PixelIterator<true> : public std::iterator<std::output_iterator_tag, bool, std::ptrdiff_t> { protected: typedef PixelIterator self_t; public: typedef bool value_type; PixelIterator(const Image* img, int concurrent_lines = 4, int line_skip = 8, threshold_t threshold = 0) : img(img), it_size(concurrent_lines), line_skip(line_skip), img_it(it_size), threshold(threshold), x(0), y(0), lum(0), valid_cache(false) { // FIXME insert an optimized code path for img->h <= it_size for (int i = 0; i < it_size; ++i) { img_it[i] = img->begin().at(std::min((int)i,img->w-1),0); *img_it[i]; } } virtual ~PixelIterator() {}; self_t& operator++() { valid_cache = false; if ( y < img->h-1 ) { ++y; for (int i = 0; i < it_size; ++i) { img_it[i].down(); *img_it[i]; } } else { y = 0; int todo = (img->w-1) - x; if ( todo > line_skip + (it_size-1) ) { x += line_skip; for (int i = 0; i < it_size; ++i) { img_it[i] = img_it[i].at(x+(int) i,y); *img_it[i]; } } else if ( todo <= line_skip ) { img_it[it_size-1] = img->end(); } else { x += line_skip; for (int i = 0; i < it_size; ++i) { img_it[i] = img_it[i].at(std::min(x+(int)i,img->w-1),y); *img_it[i]; } } } return *this; }; // FIXME it seems that the median (or something similar) is the better choice. const value_type operator*() const { if (valid_cache) return cache; double tmp=0; //uint16_t min = 255; //uint16_t max = 0; for (int i = 0; i < it_size; ++i) { //min = std::min(min,img_it[i].getL()); //max = std::max(max,img_it[i].getL()); tmp += img_it[i].getL(); } //lum = (tmp - (double) (min+max)) / (double) (it_size-2); lum = tmp / it_size; cache = lum < threshold; valid_cache = true; return cache; } //value_type* operator->(); //const value_type* operator->() const; self_t at(pos_t x, pos_t y) const { // FIXME insert an optimized code path for img->h >= y+it_size self_t tmp = *this; for (int i = 0; i < it_size; ++i) { tmp.img_it[i] = tmp.img_it[i].at(std::min(x+(int)i,img->w-1),y); } tmp.valid_cache = false; tmp.x = x; tmp.y = y; return tmp; } pos_t get_x() const { return x; } pos_t get_y() const { return y; } threshold_t get_threshold() const { return threshold; } void set_threshold(threshold_t new_threshold) { valid_cache = false; threshold = new_threshold; } bool end() const { return !(img_it[it_size-1] != img->end()); } double get_lum() const { if (! valid_cache) { operator*(); } return lum; } long get_x_size() const { return img->w; } long get_y_size() const { return img->h; } long get_line_length() const { return get_y_size(); } protected: const Image* img; int it_size; int line_skip; std::vector<Image::const_iterator> img_it; threshold_t threshold; pos_t x; pos_t y; mutable double lum; mutable bool cache; mutable bool valid_cache; }; // class PixelIterator<vertical = true> }; // namespace BarDecode #endif // _PIXEL_ITERATOR_HH_ �����������������������������������������������������exact-image-0.9.1/bardecode/code39.hh���������������������������������������������������������������0000644�0000764�0000764�00000031612�11472166554�015716� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Lars Kuhtz, ExactCODE GmbH Germany. * Copyright (C) 2010 René Rebe, ExactCODE GmbH Germany. * * 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. */ #ifndef _CODE39_HH_ #define _CODE39_HH_ #include "scanner_utils.hh" namespace BarDecode { struct code39_t { code39_t(); // NOTE: if the first char is SHIFT, then a further barcode is expected to // be concatenated. // Character set: A-Z0-9-. $/+% and DELIMITER // Extended set: full ascii (by use of shift characters) // Usage of extended set is not encoded, but needs to be requested explicitly. // The code is first scaned normaly. The result is translated afterwards // into extend encoding // Usage of checksum is not encoded, but needs to be requested explicitly. // If requested this is performed after completely having scanned the code. // Decoding is based on a binary encoding of the width of bars (rather than // modules). Since each symbol has 9 bars we need a table of size 512. // Otherwith we would have needed size 2^(13 modules - 2 constant modules) = 2048. // ((Maybe we could safe even a bit more by directly encoding 3 of 9 ???) template<class TIT> scanner_result_t scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t) const; template<class TIT> scanner_result_t reverse_scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t) const; bool check_bar_vector(const bar_vector_t& b,psize_t old_psize = 0) const; module_word_t get_key(const bar_vector_t& b) const; module_word_t reverse_get_key(const bar_vector_t& b) const; template<class TIT> bool expect_n(TIT& start, TIT end, psize_t old_psize) const; static const char DELIMITER = 254; static const char no_entry = 255; static const usize_t min_quiet_usize = 5; //static const usize_t min_quiet_usize = 10; static const usize_t min_quiet_usize_right = 5; DECLARE_TABLE(table,512); DECLARE_TABLE(aux,128); }; inline code39_t::code39_t() { INIT_TABLE(table,512,no_entry); PUT_IN_TABLE(table,0x34, '0'); PUT_IN_TABLE(table,0x121, '1'); PUT_IN_TABLE(table,0x61, '2'); PUT_IN_TABLE(table,0x160, '3'); PUT_IN_TABLE(table,0x31, '4'); PUT_IN_TABLE(table,0x130, '5'); PUT_IN_TABLE(table,0x70, '6'); PUT_IN_TABLE(table,0x25, '7'); PUT_IN_TABLE(table,0x124, '8'); PUT_IN_TABLE(table,0x64, '9'); PUT_IN_TABLE(table,0x109, 'A'); PUT_IN_TABLE(table,0x49, 'B'); PUT_IN_TABLE(table,0x148, 'C'); PUT_IN_TABLE(table,0x19, 'D'); PUT_IN_TABLE(table,0x118, 'E'); PUT_IN_TABLE(table,0x58, 'F'); PUT_IN_TABLE(table,0xD, 'G'); PUT_IN_TABLE(table,0x10C, 'H'); PUT_IN_TABLE(table,0x4C, 'I'); PUT_IN_TABLE(table,0x1C, 'J'); PUT_IN_TABLE(table,0x103, 'K'); PUT_IN_TABLE(table,0x43, 'L'); PUT_IN_TABLE(table,0x142, 'M'); PUT_IN_TABLE(table,0x13, 'N'); PUT_IN_TABLE(table,0x112, 'O'); PUT_IN_TABLE(table,0x52, 'P'); PUT_IN_TABLE(table,0x7, 'Q'); PUT_IN_TABLE(table,0x106, 'R'); PUT_IN_TABLE(table,0x46, 'S'); PUT_IN_TABLE(table,0x16, 'T'); PUT_IN_TABLE(table,0x181, 'U'); PUT_IN_TABLE(table,0xC1, 'V'); PUT_IN_TABLE(table,0x1C0, 'W'); PUT_IN_TABLE(table,0x91, 'X'); PUT_IN_TABLE(table,0x190, 'Y'); PUT_IN_TABLE(table,0xD0, 'Z'); PUT_IN_TABLE(table,0x85, '-'); PUT_IN_TABLE(table,0x184, '.'); PUT_IN_TABLE(table,0xC4, ' '); PUT_IN_TABLE(table,0xA8, '$'); PUT_IN_TABLE(table,0xA2, '/'); PUT_IN_TABLE(table,0x8A, '+'); PUT_IN_TABLE(table,0x2A, '%'); PUT_IN_TABLE(table,0x94, DELIMITER); INIT_TABLE(aux,128,no_entry); PUT_IN_TABLE(aux,(uint)'0', 0); PUT_IN_TABLE(aux,(uint)'1', 1); PUT_IN_TABLE(aux,(uint)'2', 2); PUT_IN_TABLE(aux,(uint)'3', 3); PUT_IN_TABLE(aux,(uint)'4', 4); PUT_IN_TABLE(aux,(uint)'5', 5); PUT_IN_TABLE(aux,(uint)'6', 6); PUT_IN_TABLE(aux,(uint)'7', 7); PUT_IN_TABLE(aux,(uint)'8', 8); PUT_IN_TABLE(aux,(uint)'9', 9); PUT_IN_TABLE(aux,(uint)'A', 10); PUT_IN_TABLE(aux,(uint)'B', 11); PUT_IN_TABLE(aux,(uint)'C', 12); PUT_IN_TABLE(aux,(uint)'D', 13); PUT_IN_TABLE(aux,(uint)'E', 14); PUT_IN_TABLE(aux,(uint)'F', 15); PUT_IN_TABLE(aux,(uint)'G', 16); PUT_IN_TABLE(aux,(uint)'H', 17); PUT_IN_TABLE(aux,(uint)'I', 18); PUT_IN_TABLE(aux,(uint)'J', 19); PUT_IN_TABLE(aux,(uint)'K', 20); PUT_IN_TABLE(aux,(uint)'L', 21); PUT_IN_TABLE(aux,(uint)'M', 22); PUT_IN_TABLE(aux,(uint)'N', 23); PUT_IN_TABLE(aux,(uint)'O', 24); PUT_IN_TABLE(aux,(uint)'P', 25); PUT_IN_TABLE(aux,(uint)'Q', 26); PUT_IN_TABLE(aux,(uint)'R', 27); PUT_IN_TABLE(aux,(uint)'S', 28); PUT_IN_TABLE(aux,(uint)'T', 29); PUT_IN_TABLE(aux,(uint)'U', 30); PUT_IN_TABLE(aux,(uint)'V', 31); PUT_IN_TABLE(aux,(uint)'W', 32); PUT_IN_TABLE(aux,(uint)'X', 33); PUT_IN_TABLE(aux,(uint)'Y', 34); PUT_IN_TABLE(aux,(uint)'Z', 35); PUT_IN_TABLE(aux,(uint)'-', 36); PUT_IN_TABLE(aux,(uint)'.', 37); PUT_IN_TABLE(aux,(uint)' ', 38); PUT_IN_TABLE(aux,(uint)'$', 39); PUT_IN_TABLE(aux,(uint)'/', 40); PUT_IN_TABLE(aux,(uint)'+', 41); PUT_IN_TABLE(aux,(uint)'%', 42); } inline module_word_t code39_t::get_key(const bar_vector_t& b) const { #ifdef STRICT u_t n_l = ((double) b.psize / 15.0); // ((b.size / (6*1+3*3)) * 1 u_t n_h = ((double) b.psize / 12.0); // ((b.size / (6*1+3*2)) * 1 u_t w_l = ((double) b.psize / 6.0); // ((b.size / (6*1+3*2)) * 2 u_t w_h = ((double) b.psize / 5.0); // ((b.size / (6*1+3*3)) * 3 #else u_t n_l = ((double) b.psize / 30.0); u_t n_h = ((double) b.psize / 8.0); u_t w_l = ((double) b.psize / 7.9); u_t w_h = ((double) b.psize / 1.0); #endif assert(b.size() == 9); module_word_t r = 0; for (uint i = 0; i < 9; ++i) { r <<= 1; if (w_l <= b[i].second && b[i].second <= w_h) r += 1; else if (! (n_l <= b[i].second && b[i].second <= n_h)) return 0; } return r; } inline module_word_t code39_t::reverse_get_key(const bar_vector_t& b) const { #ifdef STRICT u_t n_l = ((double) b.psize / 15.0); // ((b.size / (6*1+3*3)) * 1 u_t n_h = ((double) b.psize / 12.0); // ((b.size / (6*1+3*2)) * 1 u_t w_l = ((double) b.psize / 6.0); // ((b.size / (6*1+3*2)) * 2 u_t w_h = ((double) b.psize / 5.0); // ((b.size / (6*1+3*3)) * 3 #else u_t n_l = ((double) b.psize / 30.0); u_t n_h = ((double) b.psize / 8.0); u_t w_l = ((double) b.psize / 7.9); u_t w_h = ((double) b.psize / 1.0); #endif assert(b.size() == 9); module_word_t r = 0; for (int i = 8; i >= 0; --i) { r <<= 1; if (w_l <= b[i].second && b[i].second <= w_h) r += 1; else if (! (n_l <= b[i].second && b[i].second <= n_h)) return 0; } return r; } // psize = 0 means skip that test inline bool code39_t::check_bar_vector(const bar_vector_t& b,psize_t old_psize) const { // check psize // check colors assert(b.size() == 9); #if 0 return (!old_psize || fabs((long)b.psize - (long)old_psize) < 0.5 * old_psize) && b[0].first && b[8].first; #else if (old_psize && ! (fabs((long) b.psize - (long) old_psize) < 0.5 * old_psize)) { return false; } if ( ! (b[0].first && b[8].first) ) { return false; } return true; #endif } template<class TIT> bool code39_t::expect_n(TIT& start, TIT end, psize_t old_psize) const { using namespace scanner_utilities; bar_vector_t b(1); if ( get_bars(start,end,b,1) != 1 || b[0].first ) return false; #ifdef STRICT u_t n_l = ((double) old_psize / 15.0); // ((b.size / (6*1+3*3)) * 1 u_t n_h = ((double) old_psize / 12.0); // ((b.size / (6*1+3*2)) * 1 #else u_t n_l = ((double) old_psize / 30.0); u_t n_h = ((double) old_psize / 7.0); #endif return n_l <= b[0].second && b[0].second <= n_h; } template<class TIT> scanner_result_t code39_t::scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t quiet_psize) const { using namespace scanner_utilities; // try to match start marker // do relatively cheap though rough test on the first two bars only. bar_vector_t b(9); if ( get_bars(start,end,b,2) != 2 ) return scanner_result_t(); if (b[0].second > 0.8 * b[1].second) return scanner_result_t(); if (b[1].second > 3.5 * b[0].second) return scanner_result_t(); if ( add_bars(start,end,b,7) != 7 ) return scanner_result_t(); if (! check_bar_vector(b) ) return scanner_result_t(); // check quiet_zone with respect to length of the first symbol //if (quiet_psize < (double) b.psize * 0.7) return scanner_result_t(); // 10 x quiet zone if (quiet_psize < (double) b.psize * 0.4) return scanner_result_t(); // 10 x quiet zone // expect start sequence module_word_t key = get_key(b); if ( ! key || table[key] != DELIMITER ) { return scanner_result_t(); } std::string code = ""; psize_t old_psize; bool at_end = false; while (! at_end) { old_psize = b.psize; // consume narrow separator if (! expect_n(start,end,old_psize)) return scanner_result_t(); // get new symbol if ( get_bars(start,end,b,9) != 9) return scanner_result_t(); if (! check_bar_vector(b,old_psize) ) return scanner_result_t(); key = get_key(b); if (! key ) return scanner_result_t(); const uint8_t c = table[key]; switch(c) { case (uint8_t) no_entry: return scanner_result_t(); case (uint8_t) DELIMITER: at_end = true; break; default: code.push_back(c); } } return scanner_result_t(code39,code,x,y); } template<class TIT> scanner_result_t code39_t::reverse_scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t quiet_psize) const { using namespace scanner_utilities; // try to match start marker // do relatively cheap though rough test on the first two bars only. bar_vector_t b(9); if ( get_bars(start,end,b,2) != 2 ) return scanner_result_t(); if (b[0].second > 1.8 * b[1].second) return scanner_result_t(); if (b[1].second > 1.8 * b[0].second) return scanner_result_t(); if ( add_bars(start,end,b,7) != 7 ) return scanner_result_t(); if (! check_bar_vector(b) ) return scanner_result_t(); // check quiet_zone with respect to length of the first symbol if (quiet_psize < (double) b.psize * 0.4) return scanner_result_t(); // 10 x quiet zone // expect start sequence module_word_t key = reverse_get_key(b); if ( ! key || table[key] != DELIMITER ) { return scanner_result_t(); } std::string code = ""; psize_t old_psize; bool at_end = false; while (! at_end) { old_psize = b.psize; // consume narrow separator if (! expect_n(start,end,old_psize)) return scanner_result_t(); // get new symbol if ( get_bars(start,end,b,9) != 9) return scanner_result_t(); if (! check_bar_vector(b,old_psize) ) return scanner_result_t(); key = reverse_get_key(b); if (! key ) return scanner_result_t(); const uint8_t c = table[key]; switch(c) { case (uint8_t) no_entry: return scanner_result_t(); case (uint8_t) DELIMITER: at_end = true; break; default: code.push_back(c); } } return scanner_result_t(code39,std::string(code.rbegin(),code.rend()),x,y); } }; // namespace BarDecode #endif // _CODE39_HH_ ����������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/bardecode/BarDecode.hh������������������������������������������������������������0000644�0000764�0000764�00000001530�11007034706�016417� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Lars Kuhtz, ExactCODE GmbH Germany. * * 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. */ #ifndef _BARDECODE_HH_ #define _BARDECODE_HH_ #include "Scanner.hh" namespace BarDecode { }; // namespace BarDecode #endif // _BARDECODE_HH_ ������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/bardecode/code128.hh��������������������������������������������������������������0000644�0000764�0000764�00000040300�12160553167�015762� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Lars Kuhtz, ExactCODE GmbH Germany. * Copyright (C) 2009 René Rebe, ExactCODE GmbH Germany. * * 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. */ #ifndef _CODE128_HH_ #define _CODE128_HH_ #include <stdio.h> #include <list> #include "scanner_utils.hh" namespace BarDecode { struct code128_t { enum { FNC1, FNC2, FNC3, FNC4, SHIFT, CODEA, CODEB, CODEC, STARTA, STARTB, STARTC, END }; static const char no_entry = 255; enum code_set_t { code_set_a, code_set_b, code_set_c }; static const usize_t min_quiet_usize = 5; static const usize_t min_quiet_usize_right = 5; code128_t(); template<class TIT> scanner_result_t scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t) const; template<class TIT> scanner_result_t reverse_scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t) const; std::string decode128(code_set_t code_set, module_word_t mw) const; code_set_t shift_code_set(code_set_t code_set) const; module_word_t get_key(module_word_t mw) const; bool is_end_key(module_word_t key) const; bool is_start_key(module_word_t key) const; bool is_no_entry(module_word_t key) const; scanner_result_t decode_key_list(const std::list<module_word_t>& list, pos_t x, pos_t y) const; DECLARE_TABLE(table,512); DECLARE_TABLE(aaux,10); DECLARE_TABLE(baux,10); DECLARE_TABLE(caux,10); }; inline code128_t::code128_t() { // Code128 (255 indicates invalid module_word) // Based on 11 bits, where the first bit is 1 and the last bit is 0, // hence only 9 bit are used for lookup. INIT_TABLE(table,512,no_entry); PUT_IN_TABLE(table,0x166,0); PUT_IN_TABLE(table,0x136,1); PUT_IN_TABLE(table,0x133,2); PUT_IN_TABLE(table,0x4C,3); PUT_IN_TABLE(table,0x46,4); PUT_IN_TABLE(table,0x26,5); PUT_IN_TABLE(table,0x64,6); PUT_IN_TABLE(table,0x62,7); PUT_IN_TABLE(table,0x32,8); PUT_IN_TABLE(table,0x124,9); PUT_IN_TABLE(table,0x122,10); PUT_IN_TABLE(table,0x112,11); PUT_IN_TABLE(table,0xCE,12); PUT_IN_TABLE(table,0x6E,13); PUT_IN_TABLE(table,0x67,14); PUT_IN_TABLE(table,0xE6,15); PUT_IN_TABLE(table,0x76,16); PUT_IN_TABLE(table,0x73,17); PUT_IN_TABLE(table,0x139,18); PUT_IN_TABLE(table,0x12E,19); PUT_IN_TABLE(table,0x127,20); PUT_IN_TABLE(table,0x172,21); PUT_IN_TABLE(table,0x13A,22); PUT_IN_TABLE(table,0x1B7,23); PUT_IN_TABLE(table,0x1A6,24); PUT_IN_TABLE(table,0x196,25); PUT_IN_TABLE(table,0x193,26); PUT_IN_TABLE(table,0x1B2,27); PUT_IN_TABLE(table,0x19A,28); PUT_IN_TABLE(table,0x199,29); PUT_IN_TABLE(table,0x16C,30); PUT_IN_TABLE(table,0x163,31); PUT_IN_TABLE(table,0x11B,32); PUT_IN_TABLE(table,0x8C,33); PUT_IN_TABLE(table,0x2C,34); PUT_IN_TABLE(table,0x23,35); PUT_IN_TABLE(table,0xC4,36); PUT_IN_TABLE(table,0x34,37); PUT_IN_TABLE(table,0x31,38); PUT_IN_TABLE(table,0x144,39); PUT_IN_TABLE(table,0x114,40); PUT_IN_TABLE(table,0x111,41); PUT_IN_TABLE(table,0xDC,42); PUT_IN_TABLE(table,0xC7,43); PUT_IN_TABLE(table,0x37,44); PUT_IN_TABLE(table,0xEC,45); PUT_IN_TABLE(table,0xE3,46); PUT_IN_TABLE(table,0x3B,47); PUT_IN_TABLE(table,0x1BB,48); PUT_IN_TABLE(table,0x147,49); PUT_IN_TABLE(table,0x117,50); PUT_IN_TABLE(table,0x174,51); PUT_IN_TABLE(table,0x171,52); PUT_IN_TABLE(table,0x177,53); PUT_IN_TABLE(table,0x1AC,54); PUT_IN_TABLE(table,0x1A3,55); PUT_IN_TABLE(table,0x18B,56); PUT_IN_TABLE(table,0x1B4,57); PUT_IN_TABLE(table,0x1B1,58); PUT_IN_TABLE(table,0x18D,59); PUT_IN_TABLE(table,0x1BD,60); PUT_IN_TABLE(table,0x121,61); PUT_IN_TABLE(table,0x1C5,62); PUT_IN_TABLE(table,0x98,63); PUT_IN_TABLE(table,0x86,64); PUT_IN_TABLE(table,0x58,65); PUT_IN_TABLE(table,0x43,66); PUT_IN_TABLE(table,0x16,67); PUT_IN_TABLE(table,0x13,68); PUT_IN_TABLE(table,0xC8,69); PUT_IN_TABLE(table,0xC2,70); PUT_IN_TABLE(table,0x68,71); PUT_IN_TABLE(table,0x61,72); PUT_IN_TABLE(table,0x1A,73); PUT_IN_TABLE(table,0x19,74); PUT_IN_TABLE(table,0x109,75); PUT_IN_TABLE(table,0x128,76); PUT_IN_TABLE(table,0x1DD,77); PUT_IN_TABLE(table,0x10A,78); PUT_IN_TABLE(table,0x3D,79); PUT_IN_TABLE(table,0x9E,80); PUT_IN_TABLE(table,0x5E,81); PUT_IN_TABLE(table,0x4F,82); PUT_IN_TABLE(table,0xF2,83); PUT_IN_TABLE(table,0x7A,84); PUT_IN_TABLE(table,0x79,85); PUT_IN_TABLE(table,0x1D2,86); PUT_IN_TABLE(table,0x1CA,87); PUT_IN_TABLE(table,0x1C9,88); PUT_IN_TABLE(table,0x16F,89); PUT_IN_TABLE(table,0x17B,90); PUT_IN_TABLE(table,0x1DB,91); PUT_IN_TABLE(table,0xBC,92); PUT_IN_TABLE(table,0x8F,93); PUT_IN_TABLE(table,0x2F,94); PUT_IN_TABLE(table,0xF4,95); PUT_IN_TABLE(table,0xF1,96); PUT_IN_TABLE(table,0x1D4,97); PUT_IN_TABLE(table,0x1D1,98); PUT_IN_TABLE(table,0xEF,99); PUT_IN_TABLE(table,0xF7,100); PUT_IN_TABLE(table,0x1AF,101); PUT_IN_TABLE(table,0x1D7,102); PUT_IN_TABLE(table,0x142,103); PUT_IN_TABLE(table,0x148,104); PUT_IN_TABLE(table,0x14e,105); PUT_IN_TABLE(table,0x11d,106); // Range 96-105. Use offset -96 INIT_TABLE(aaux,10,255); PUT_IN_TABLE(aaux,0,FNC3); // 96 PUT_IN_TABLE(aaux,1,FNC2); // 97 PUT_IN_TABLE(aaux,2,SHIFT); // 98 PUT_IN_TABLE(aaux,3,CODEC); // 99 PUT_IN_TABLE(aaux,4,CODEB); // 100 PUT_IN_TABLE(aaux,5,FNC4); // 101 PUT_IN_TABLE(aaux,6,FNC1); // 102 PUT_IN_TABLE(aaux,7,STARTA); // 103 PUT_IN_TABLE(aaux,8,STARTB); // 104 PUT_IN_TABLE(aaux,9,STARTC); // 105 INIT_TABLE(baux,10,255); PUT_IN_TABLE(baux,0,FNC3); // 96 PUT_IN_TABLE(baux,1,FNC2); // 97 PUT_IN_TABLE(baux,2,SHIFT); // 98 PUT_IN_TABLE(baux,3,CODEC); // 99 PUT_IN_TABLE(baux,4,FNC4); // 100 PUT_IN_TABLE(baux,5,CODEA); // 101 PUT_IN_TABLE(baux,6,FNC1); // 102 PUT_IN_TABLE(baux,7,STARTA); // 103 PUT_IN_TABLE(baux,8,STARTB); // 104 PUT_IN_TABLE(baux,9,STARTC); // 105 INIT_TABLE(caux,10,255); PUT_IN_TABLE(caux,0,no_entry); // 96 PUT_IN_TABLE(caux,1,no_entry); // 97 PUT_IN_TABLE(caux,2,no_entry); // 98 PUT_IN_TABLE(caux,3,no_entry); // 99 PUT_IN_TABLE(caux,4,CODEB); // 100 PUT_IN_TABLE(caux,5,CODEA); // 101 PUT_IN_TABLE(caux,6,FNC1); // 102 PUT_IN_TABLE(caux,7,STARTA); // 103 PUT_IN_TABLE(caux,8,STARTB); // 104 PUT_IN_TABLE(caux,9,STARTC); // 105 }; inline bool code128_t::is_end_key(module_word_t key) const { return table[key] == 106; } inline bool code128_t::is_no_entry(module_word_t key) const { return table[key] == no_entry; } inline bool code128_t::is_start_key(module_word_t key) const { return table[key] >= 103 && table[key] <= 105; } // "" indicates no_entry inline std::string code128_t::decode128(code_set_t code_set, module_word_t key) const { int c = table[key]; if (c == no_entry) return ""; if (c == 106) return std::string(1,END); switch (code_set) { case code_set_c: if (c < 100) { char str[2]; sprintf(str,"%02d",c); return std::string(str); } else { return std::string(1,caux[c-96]); } break; case code_set_b: if (c < 96) { return std::string(1,c+32); } else { return std::string(1,baux[c-96]); } break; case code_set_a: if (c < 64) { return std::string(1,c+32); } else if ( c < 96 ) { return std::string(1,c-64); } else { return std::string(1,aaux[c-96]); } break; default: assert(false); return ""; } } inline module_word_t code128_t::get_key(module_word_t mw) const { // assume first bit is 1 and last bit is 0 // use only the 9 bits inbetween for lookup if ( ! ((1<<10)&mw) || (mw&1)) { return 0; } mw &= ((1<<10)-1); mw >>= 1; return mw; } inline code128_t::code_set_t code128_t::shift_code_set(code_set_t code_set) const { switch (code_set) { case code_set_a: return code_set_b; case code_set_b: return code_set_a; default: return code_set; } } // FNC1 as first symbol indicates GS1-128 // in third or subsequent position: ascii 29. // TODO FNC2 (anywhere) concatenate barcode with next barcode // TODO FNC3 initialize or reprogram the barcode reader with the current code // TODO FNC4 switch to extended ascii (latin-1 as default) // (quiet complicated usage refer to GS1 spec 5.3.3.4.2) template<class TIT> scanner_result_t code128_t::scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t quiet_psize) const { using namespace scanner_utilities; // try to match start marker bar_vector_t b(6); if (get_bars(start,end,b,2) != 2 ) return scanner_result_t(); if (b[0].second > 3 * b[1].second || b[0].second < 1.2 * b[1].second) return scanner_result_t(); if ( add_bars(start,end,b,4) != 4) return scanner_result_t(); // get a first guess for u u_t u = (double) b.psize / 11; // 11 is the number of modules of the start sequence // check if u is within max_u imposed by quiet_zone if ( u > max_u<code128_t>(quiet_psize) ) return scanner_result_t(); // expect start sequence code_set_t cur_code_set; module_word_t key = get_key(get_module_word_adjust_u(b,u,11)); std::string result = decode128(code_set_a,key); switch (result[0]) { case STARTA: cur_code_set = code_set_a; break; case STARTB: cur_code_set = code_set_b; break; case STARTC: cur_code_set = code_set_c; break; default: return scanner_result_t(); } std::list<module_word_t> key_list; key_list.push_back(key); while (! is_end_key(key) ) { // get symbol if ( get_bars(start,end,b,6) != 6 ) return scanner_result_t(); key = get_key(get_module_word_adjust_u(b,u,11)); if ( ! key || is_no_entry(key) ) return scanner_result_t(); else key_list.push_back(key); } // remove end_key key_list.pop_back(); if (key_list.size() <= 1) return scanner_result_t(); // decode key_list (including check-summing) return decode_key_list(key_list,x,y); } // Backward algorithm: // 1. match end // loop: // 2. get key // 3. check if key does not decode to no_entry (independent of table type!) // 4. store key // 5. until: starta, startb, or startc is found // 6. decode keys in reverted order and compute checksum (using code from loop body above) // return template<class TIT> scanner_result_t code128_t::reverse_scan(TIT& start, TIT end, pos_t x, pos_t y, psize_t quiet_psize) const { using namespace scanner_utilities; // try to match end marker // expect a black bar of 2 modules bar_vector_t b(7); if ( get_bars(start,end,b,2) != 2) return scanner_result_t(); if (b[0].second > 3 * b[1].second || b[0].second < 1.2 * b[1].second) return scanner_result_t(); if ( add_bars(start,end,b,5) != 5) return scanner_result_t(); // get a first guess for u u_t u = (double) b.psize / 13; // 13 is the number of modules of the end sequence // check if u is within max_u imposed by quiet_zone if ( u > max_u<code128_t>(quiet_psize) ) return scanner_result_t(); // expect end sequence (well, the first 6 bars (or 7 modules) of it) b.erase(b.begin(),++b.begin()); module_word_t key = get_key(reverse_get_module_word(b,u,11)); if ( ! is_end_key(key)) return scanner_result_t(); std::list<module_word_t> key_list; while (! is_start_key(key) ) { // get symbol if ( get_bars(start,end,b,6) != 6 ) return scanner_result_t(); key = get_key(reverse_get_module_word_adjust_u(b,u,11)); if ( ! key || is_no_entry(key) ) return scanner_result_t(); else key_list.push_front(key); } if (key_list.size() <= 1) return scanner_result_t(); // decode key_list (including check-summing) return decode_key_list(key_list,x,y); } inline scanner_result_t code128_t::decode_key_list(const std::list<module_word_t>& list, pos_t x, pos_t y) const { // initialize checksum: long checksum = table[list.front()]; long pos = 0; std::string code = ""; code_t type = code128; bool shift = false; code_set_t cur_code_set = code_set_a; for (std::list<module_word_t>::const_iterator it = list.begin(); it != --list.end(); ++it) { const module_word_t& key = *it; std::string result = decode128( (shift ? shift_code_set(cur_code_set) : cur_code_set), key); shift = false; switch (result.size()) { case 0: return scanner_result_t(); case 2: code += result; break; case 1: switch (result[0]) { case END: return scanner_result_t(); case SHIFT: shift = true; break; case STARTA: case CODEA: cur_code_set = code_set_a; break; case STARTB: case CODEB: cur_code_set = code_set_b; break; case STARTC: case CODEC: cur_code_set = code_set_c; break; case FNC1: if (pos == 1) { type = gs1_128; } else { code.push_back(29); } break; case FNC2: case FNC3: case FNC4: std::cerr << "WARNING: Function characters for code128 are not yet supported." << std::endl; break; default: code += result; } break; default: return scanner_result_t(); } // first run will be 0, last run (check-digit is ommitted in the loop) checksum += pos * (long) table[key]; ++pos; } // Checksum and return result if ( (checksum % 103) != (long) table[list.back()] ) { //std::cerr << "WARNING: checksum test for code128 failed on \""<< code << "\"." << std::endl; //std::cerr << " checksum: " << checksum << " % 103 = " << checksum % 103 << " != " << (long) table[list.back()] << std::endl; return scanner_result_t(); } else { return scanner_result_t(type,code,x,y); } } }; // namespace BarDecode #endif // _CODE128_HH_ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/bardecode/scanner_utils.hh��������������������������������������������������������0000644�0000764�0000764�00000023410�11055507507�017470� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Copyright (C) 2007 - 2008 Lars Kuhtz, ExactCODE GmbH Germany. * * 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. */ #ifndef _SCANNER_UTILS_HH_ #define _SCANNER_UTILS_HH_ #if __APPLE__ #include <sys/types.h> #endif #define PUT_IN_TABLE(a,b,c) \ a[b] = c; \ #define DECLARE_TABLE(a,s) \ char a[s]; #define INIT_TABLE(a,s,v) \ for(unsigned int i = 0; i < s; ++i) { \ a[i] = v; \ } #define FLIP(a,mask) (~a)&mask namespace BarDecode { namespace { namespace debug { void print_bar_vector(const bar_vector_t& b) { std::cerr << "[ "; for (size_t i = 0; i < b.size(); ++i) { std::cerr << "(" << b[i].first << "," << b[i].second << ") "; } std::cerr << "]" << std::endl; } }; namespace scanner_utilities { template<class CODE> u_t max_u(psize_t quiet_psize, double tolerance = 0.35) { return (quiet_psize / CODE::min_quiet_usize) * (1+tolerance); } // scanns up to c bars (possibly less) // parameter: tokenizer, num of bars // accepts a parameter for maximal size of a bar (0 for unbounded) // returns num of bars that where read // modifies the paramter vector to hold result // FIXME make use of bound --> implement support in Tokenizer! template<class TIT> uint add_bars(TIT& start, TIT end, bar_vector_t& v, uint c, psize_t bound = 0) { size_t old_size = v.size(); v.resize(old_size + c); for (uint i = 0; i < c; ++i) { if (start == end) { v.resize(old_size + i); v.psize = v.bpsize + v.wpsize; return i; } else { v[old_size + i] = *++start; if (v[old_size+i].first) v.bpsize += v[old_size+i].second; else v.wpsize += v[old_size+i].second; } } v.psize = v.bpsize + v.wpsize; return c; } template<class TIT> uint get_bars(TIT& start, TIT end, bar_vector_t& v,uint c, psize_t bound = 0) { v.resize(c); v.bpsize = 0; v.wpsize = 0; for (uint i = 0; i < c; ++i) { if (start == end) { v.resize(i); v.psize = v.bpsize + v.wpsize; return i; } else { v[i] = *++start; if (v[i].first) v.bpsize += v[i].second; else v.wpsize += v[i].second; } } v.psize = v.bpsize + v.wpsize; return c; } // u-value-handling: // * compute initial value // * use it until failure occurs // * get new value from failure token (psize/expected_modules) // * check that deviation is within tolerance // * use aggregate (e.g. mean. NOTE mean allows drifting...) // lookup returns code or failure uint modules_count(const bar_vector_t& v, u_t u) { uint result = 0; for (uint i = 0; i < v.size(); ++i) { result += lround(v[i].second/u); } return result; } // modulizer // translates a sequence of bars into an module_word (uint16_t) // for efficient lookup in array; // compute module_word from bar_vector, u-value // optional parameter: expected num of modules // retunrs module_word, num of modules, or failure (should be safe to use 0 -- or max_value?) module_word_t get_module_word(const bar_vector_t& v, u_t u, usize_t m = 0) { //assert(modules_count(v,u) <= 16); usize_t msum = 0; module_word_t tmp = 0; for(uint i = 0 ; i < v.size(); ++i) { usize_t mc = lround(v[i].second/u); // FIXME check tolerance msum += mc; if ( ! (mc < 5 && mc > 0) ) return 0; // at most 2 bit tmp <<= mc; if (v[i].first) { switch (mc) { case 1: tmp |= 0x1; break; case 2: tmp |= 0x3; break; case 3: tmp |= 0x7; break; case 4: tmp |= 0xF; break; default: assert(false); } } } if (msum != m) return 0; else { assert(modules_count(v,u) <= 16); return tmp; } } module_word_t reverse_get_module_word(const bar_vector_t& v, u_t u, usize_t m = 0) { //assert(modules_count(v,u) <= 16); usize_t msum = 0; module_word_t tmp = 0; for(int i = (int)v.size()-1 ; i >= 0; --i) { usize_t mc = lround(v[i].second/u); // FIXME check tolerance msum += mc; if ( ! (mc < 5 && mc > 0) ) return 0; // at most 2 bit tmp <<= mc; if (v[i].first) { switch (mc) { case 1: tmp |= 0x1; break; case 2: tmp |= 0x3; break; case 3: tmp |= 0x7; break; case 4: tmp |= 0xF; break; default: assert(false); } } } if (msum != m) return 0; else { assert(modules_count(v,u) <= 16); return tmp; } } module_word_t get_module_word_adjust_u(const bar_vector_t& b, u_t& u, usize_t m) { module_word_t mw = get_module_word(b,u,m); if (mw) goto end; { // try to adjust u u_t new_u = b.psize / (double) m; // if nothing changes it makes no sense to try again if (new_u != u) { if ( fabs(new_u - u) <= u*0.4 ) { u = (new_u*2.0 + u) / 3.0; } else { return 0; } mw = get_module_word(b,u,m); } } if (mw) goto end; mw = get_module_word(b,u*0.75,m); if (mw) goto end; mw = get_module_word(b,u*1.25,m); if (mw) goto end; { bar_vector_t b_tmp(b); for (size_t i = 0; i < b_tmp.size(); ++i) { if (b_tmp[i].first) b_tmp[i].second += 1; else b_tmp[i].second -= 1; } mw = get_module_word(b_tmp,u,m); } if (mw) goto end; { bar_vector_t b_tmp2(b); for (size_t i = 0; i < b_tmp2.size(); ++i) { if (! b_tmp2[i].first) b_tmp2[i].second += 1; else b_tmp2[i].second -= 1; } mw = get_module_word(b_tmp2,u,m); } end: return mw; } module_word_t reverse_get_module_word_adjust_u(const bar_vector_t& b, u_t& u, usize_t m) { module_word_t mw = reverse_get_module_word(b,u,m); if (mw) goto end; { // try to adjust u u_t new_u = b.psize / (double) m; // if nothing changes it makes no sense to try again if (new_u != u) { if ( fabs(new_u - u) <= u*0.4 ) { u = (new_u*2.0 + u) / 3.0; } else { return 0; } mw = get_module_word(b,u,m); } } if (mw) goto end; mw = get_module_word(b,u*0.75,m); if (mw) goto end; mw = get_module_word(b,u*1.25,m); if (mw) goto end; { bar_vector_t b_tmp(b); for (size_t i = 0; i < b_tmp.size(); ++i) { if (b_tmp[i].first) b_tmp[i].second += 1; else b_tmp[i].second -= 1; } mw = get_module_word(b_tmp,u,m); } if (mw) goto end; { bar_vector_t b_tmp2(b); for (size_t i = 0; i < b_tmp2.size(); ++i) { if (! b_tmp2[i].first) b_tmp2[i].second += 1; else b_tmp2[i].second -= 1; } mw = get_module_word(b_tmp2,u,m); } end: return mw; } bool get_parity(const module_word_t& w) { unsigned int tmp = 0; module_word_t x = w; while ( x != 0 ) { tmp += 1 & x; x >>= 1; } return 1 & tmp; // return parity bit } bool get_parity(const bar_vector_t& v, u_t u) { unsigned int tmp = 0; for (uint i = 0; i < v.size(); ++i) { if (v[i].first) tmp += lround(v[i].second/u); // FIXME check tolerance } return 1 & tmp; // return parity bit } }; }; }; // namespace BarDecode #endif // _SCANNER_UTILS_HH_ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/���������������������������������������������������������������������������0000755�0000764�0000764�00000000000�12467664340�013642� 5����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/cc-available.c�������������������������������������������������������������0000644�0000764�0000764�00000002146�10311235230�016266� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/cc-available.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* DESC="checking whether the C compiler works" */ int main () { int a; return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/c++-exception.c������������������������������������������������������������0000644�0000764�0000764�00000002261�10311235230�016325� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/c++-exception.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* DESC="checking whether C++ supports exceptions" */ class Exception { }; void testme () { Exception e; throw e; }; int main () { testme (); return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/c++-template.c�������������������������������������������������������������0000644�0000764�0000764�00000002276�10311235230�016150� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/c++-template.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* DESC="checking for C++ templates" */ template <typename T> class X { public: T testme (T t) { return t; } }; int main () { X<int> x; x.testme (4); return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/c++-function-template.c����������������������������������������������������0000644�0000764�0000764�00000002324�10311235230�017765� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/c++-function-template.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* DESC="checking whether C++ supports templates" */ template <typename T> class X { public: T testme (T t) { return t; } }; int main () { X<int> x; x.testme (4); return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/c++-stl.c������������������������������������������������������������������0000644�0000764�0000764�00000002436�10311235230�015135� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/c++-stl.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* DESC="checking for C++ STL support" */ #include <string> #include <vector> int main () { std::string str; const char* s = str.c_str (); std::vector<int> vec; for (std::vector<int>::iterator it = vec.begin (); it != vec.end (); ++it) (*it) = 0; return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/pkgcheck-atsui.c�����������������������������������������������������������0000644�0000764�0000764�00000002147�11072664514�016706� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/pkgcheck-x11.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* CC="cc" CFLAGS="-ObjC" LIBS="-framework Carbon" */ int main () { return 0; } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/pkgcheck-cocoa.c�����������������������������������������������������������0000644�0000764�0000764�00000002146�11072664514�016644� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/pkgcheck-x11.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* CC="cc" CFLAGS="-ObjC" LIBS="-framework Cocoa" */ int main () { return 0; } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/pkgcheck-x11.c�������������������������������������������������������������0000644�0000764�0000764�00000002371�11602044502�016155� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/pkgcheck-x11.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* CC="cc" CFLAGS="-I/usr/X11/include" LIBS="-L/usr/X11/lib64 -L/usr/X11/lib -L/usr/X11R6/lib -lX11" */ #include <stdio.h> #include <X11/Xlib.h> int main () { printf ("%d.%d\n", X_PROTOCOL, X_PROTOCOL_REVISION); return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/functions������������������������������������������������������������������0000644�0000764�0000764�00000027043�11171661676�015603� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� # Initalization # prefixes="prefix exec-prefix" dirs="bin sbin libexec data sysconf sharedstate localstatedir \ lib include info man" with_options="" feature_options="" # saved shell / Makefile config save_make="" # saved to a config.h save_h="" # Append to a variable. # var_append var seperator content # var_append() { eval "[ \"\$$1\" ] && $1=\"\${$1}$2\"" || true eval "$1=\"\${$1}\$3\"" } # Prepend to a variable. # var_insert var seperator content # var_insert() { eval "[ \"\$$1\" ] && $1=\"$2\$$1\"" || true eval "$1=\"\$3\$$1\"" } # Remove from a variable. # var_remove var seperator content # var_remove() { local a=${2//\/\\/} local b=${3//\/\\/} eval '[ "$'$1'" = "$3" ] && '$1'="" || true' eval $1'="${'$1'//$a$b$a/$2}"' eval $1'="${'$1'%$a$b}"' eval $1'="${'$1'#$b$a}"' } # Test for a key in a give "array". # in_list key values # in_list () { search=$1 ; shift while [ "$1" ] ; do [ "$1" = "$search" ] && return 0 shift done return 1 } # Uppercase given argument. # uppercase text # uppercase () { echo $1 | tr '\-a-z' _A-Z } # Remove dashes ('-') from a given argument. # undash text # undash () { echo $1 | tr '\-' _ } # Compare version with a given comperator. # check_version [ atleast, equals ] expected-version current-version # check_version () { m="$1" shouldbe="`echo "$2" | sed 's/[._-]/ /g'`" is="`echo "$3" | sed 's/[. -]/ /g'`" # better ideas welcome -ReneR set -- $shouldbe case $m in atleast) for x in $is ; do if [ "$1" -a "$x" ]; then [ $x -lt $1 ] && return 1 [ $x -gt $1 ] && return 0 fi shift done ;; equals) for x in $is ; do [ "$1" = "$x" ] || return 1 shift done ;; *) status "mode $m invalid" return 1 esac return 0 } # Generate and print a generic usage text. # usage () { cat <<- EOT 'configure' configures checks the system and adapts the package to many kinds of systems. This is a rewritten 'configure' system created by ExactCODE. It differs significantly from the typical GNU/Autoconf!g (C) 2004 - 2006 Rene Rebe <rene@exactcode.de> - License: GPL Usage: ./configure [OPTION]... Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit -V, --version display version information and exit Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --datadir=DIR read-only architecture-independent data [PREFIX/share] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --infodir=DIR info documentation [PREFIX/info] --mandir=DIR man documentation [PREFIX/man] Optional Features: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] EOT for x in $feature_options ; do echo " --enable-$x" done cat <<- EOT Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) EOT for x in $with_options ; do echo " --with-$x" done if [ "$feature_options" -o "$with_options" ] ; then if [ -f ./README -o -f ./INSTALL ] ; then cat <<- EOT Please refer to a supplied README or INSTALL file for a detailed explanation of the various custom options. EOT else cat <<- EOT Please refer to the package documentation for a detailed exmplanation of the various custom options. EOT fi fi } # Initialize some internal stage. # init () { [ "$VERSION" ] || VERSION="$VERSION_MAJOR.$VERSION_MINOR.$VERSION_MICRO" [ "$DATE" ] || DATE="`date "+%a, %d %b %Y"`" prefix="/usr/local" exec_prefix="\${prefix}" bindir="\${exec_prefix}/bin" sbindir="\${exec_prefix}/sbin" libdir="\${exec_prefix}/lib" libexecdir="\${exec_prefix}/lib" datadir="\${prefix}/share" sysconfdir="\${prefix}/etc" sharedstatedir="\${prefix}/com" localstatedirdir="\${prefix}/var" includedir="\${prefix}/include" infodir="\${prefix}/info" mandir="\${prefix}/man" save_make="prefix exec_prefix PACKAGE VERSION VERSION_MAJOR VERSION_MINOR \ VERSION_MICRO DATE" save_h="PACKAGE VERSION VERSION_MAJOR VERSION_MINOR \ VERSION_MICRO DATE" # set to be saved options and features for x in $dirs ; do var_append save_make " " "${x}dir" done for x in $with_options ; do var_append save_make " " "WITH$(uppercase $x)" var_append save_h " " "WITH$(uppercase $x)" done for x in $feature_options ; do var_append save_make " " "$(uppercase $x)" var_append save_h " " "$(uppercase $x)" done } # Save the state to a config.make and/or config.h. # save () { # initilize the config files echo -n "" > config.log echo -n "" > config.make echo -n "" > config.h for x in $save_make ; do eval echo "$x = \$$x | sed -e 's/{/(/g' -e 's/}/)/g' " >> config.make done for x in $save_h ; do # decide whether to quote the value if [ "`eval echo \\$$x | sed s/[0-9]*//g`" = "" ] ; then eval echo "\#define $x \$$x" >> config.h else eval echo "\#define $x \\\"\$$x\\\"" >> config.h fi done } # Parse the the specified command line switches. # parse_options () { errors=0 while [ "$1" ] ; do case "$1" in --without-*) pkg=${1/--without-} if in_list $pkg $with_options ; then eval WITH$(uppercase $pkg)=0 else echo "'$pkg' is not available!" : $(( ++errors )) fi ;; --with-*) pkg=${1/--with-} [[ $pkg = *=* ]] && value=${pkg/*=/} || value=1 pkg=${pkg/=*/} if in_list $pkg $with_options ; then [ "$value" = "no" ] && value=0 eval WITH$(uppercase $pkg)=$value else echo "'$pkg' is not available!" : $(( ++errors )) fi ;; --enable-*) feature=${1/--enable-} if in_list $feature $feature_options ; then eval $(uppercase $feature)=1 else echo "'$feature' is not available!" : $(( ++errors )) fi ;; --disable-*) feature=${1/--disable-} if in_list $feature $feature_options ; then eval $(uppercase $feature)=0 else echo "'$feature' is not available!" : $(( ++errors )) fi ;; --*prefix=*) prefix=${1/--} value=${prefix/*=/} prefix=${prefix/=*/} if in_list $prefix $prefixes ; then eval $(undash $prefix)="$value" else echo "'$prefix' is not a valid prefix specification!" : $(( ++errors )) fi ;; --*dir=*) dir=${1/--} value=${dir/*=/} xdir=${dir/dir=*/} dir=${dir/=*/} if in_list ${xdir} $dirs ; then eval $(undash $dir)="$value" else echo "'$dir' is not a valid directory specification!" : $(( ++errors )) fi ;; --help) usage exit 0 ;; *) echo "Unable to parse $1 ..." : $(( ++errors )) ;; esac shift done if [ $errors -gt 0 ] ; then echo "Errors while parsing arguements, exitting now!" usage exit $errors fi } # Print a status (to screen and log). # status () { echo -n "$*" | tee -a config.log } # Print a final status result (to screen and log). # status_result () { echo "$*" | tee -a config.log } # Print a fatal error (to screen and log) and exit. # status_error () { status_result "$*" exit 1 } # Run a predefined test stored in config/test-$test. # runtest () { local file="./config/test-$1" if [ ! -f $file ] ; then status_result "test $1 not found!" else desc="`grep DESC= $file | sed 's/.*DESC="\(.*\)".*/\1/'`" status "$desc ... " if sh -e $file >/dev/null 2>> config.log ; then status_result "yes" eval $2=1 else status_result "no" eval $2=0 fi fi } # Compile a test stored in config/$prog-$test. # compile program test # compile () { local errors=0 local PROG="$1" ; shift while [ "$1" ] ; do local file="config/$PROG-$1" if [ ! -f $file ] ; then status_result "test $1 not found!" : $(( ++errors )) else desc="`grep DESC= $file | sed 's/.*DESC="\(.*\)".*/\1/'`" cflags="`grep CFLAGS= $file | sed 's/.* CFLAGS="\(.*\)".*/\1/'`" libs="`grep LIBS= $file | sed 's/.* LIBS="\(.*\)".*/\1/'`" status "$desc ... " if $PROG -c $cflags $libs $file -o config.tmp \ >/dev/null 2>> config.log ; then status_result "yes" else status_result "no" : $(( ++errors )) fi fi shift done return $errors } # Check for a given system header. # headercheck program header # headercheck () { local errors=0 local PROG="$1" ; shift while [ "$1" ] ; do echo "#include <$1>" > conftest.c status "checking for header "$1" ... " if $PROG -E conftest.c >/dev/null 2>> config.log ; then status_result "found" else status_result "not found" : $(( ++errors )) fi shift done return $errors } # Check whether the specifid package is installed. # pkgcheck pkg pkg 'mode' PKG-WITH-VAR [ 'mode' flags ] [ atleast, ... ] [ version ] # e.g: pkgcheck pkg -config PKG atleast 0.9.9 # pkgcheck () { local pkg="$1" ; shift local mode="$1" ; shift local FLAGSVAR="$1" ; shift if [ $mode = lib -o $mode = header ]; then local prg="$1"; shift local args="$*"; shift $# elif [ $mode = shell ]; then local script="$1"; shift fi [ "$1" ] && local vermode="$1" ; shift [ "$1" ] && local version="$1" ; shift local found=0 local ver="" local incs="" local libs="" status "checking for package $pkg " [ "$version" ] && status "($vermode $version)" status " ... " withvar="WITH$FLAGSVAR" if [ "`eval echo \\$$withvar`" = "0" ] ; then status_result "disabled" return 1 fi case "$mode" in compile) local file="config/pkgcheck-$pkg.c" if [ ! -e $file ] ; then status_result "test not found!" else cc="`grep CC= $file | sed 's/.*CC="\(.*\)".*/\1/'`" incs="`grep CFLAGS= $file | sed 's/.* CFLAGS="\(.*\)".*/\1/'`" libs="`grep LIBS= $file | sed 's/.* LIBS="\(.*\)".*/\1/'`" if $cc $incs $libs $file -o conftest.o \ >>config.log 2>> config.log ; then found=1 ver="`./conftest.o 2>>config.log`" fi fi ;; -config) ver="`$pkg-config --version 2>/dev/null`" if [ $? = 0 -a "$ver" != "" ] ; then incs="`$pkg-config --cflags`" libs="`$pkg-config --libs`" found=1 fi ;; pkg-config) ver="`pkg-config $pkg --modversion 2>/dev/null`" if [ $? = 0 -a "$ver" != "" ] ; then incs="`pkg-config $pkg --cflags`" libs="`pkg-config $pkg --libs`" found=1 fi ;; lib) echo "int main () { return 0; }" > conftest.c if $prg $args conftest.c -o conftest.o 2> /dev/null ; then found=1 libs="$arg" # TODO: is this perfect? fi ;; header) echo "" > conftest.c for h in $args; do echo "#include <$h>" >> conftest.c ; done echo "int main () { return 0; }" >> conftest.c if $prg conftest.c -o conftest.o 2> /dev/null ; then found=1 fi ;; shell) ver="`eval $script`" if [ "$ver" ]; then found=1 fi ;; *) status_error "mode $mode unknown!" esac # version check if [ $found = 1 ]; then if [ "$version" ] ; then if check_version "$vermode" "$version" "$ver" ; then status_result "yes ($ver)" else status_result "no ($ver)" found=0 fi else status_result "yes" fi else status_result "no" fi # set WITH var (if it was not set -> optional package) [ "`eval echo \\$$withvar`" = "" ] && eval $withvar=$found [ $found = 0 ] && return 1 # fill variables var_append ${FLAGSVAR}INCS " " "$incs" var_append ${FLAGSVAR}LIBS " " "$libs" var_append save_make " " "${FLAGSVAR}INCS ${FLAGSVAR}LIBS" return 0 } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/c++-partial-template-specialization.c��������������������������������������0000644�0000764�0000764�00000002533�10366740576�022642� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/c++-partial-template-specialization.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* DESC="checking for C++ partial template specialization" */ template <typename T> class X { public: T testme (T t) { return t; } T testme2 (T t) { return t; } }; template<> int X<int>::testme (int t) { return t*2; // yes - very useful }; int main () { X<int> x; x.testme (4); return 0; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/pkgcheck-oss.c�������������������������������������������������������������0000644�0000764�0000764�00000002303�10311235230�016337� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/pkgcheck-oss.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* CC="cc" */ #include <sys/soundcard.h> int main () { int ver = SOUND_VERSION; printf ("%d.%d.%d\n", (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/cc-99.c��������������������������������������������������������������������0000644�0000764�0000764�00000002216�10311235230�014605� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/cc-99.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* DESC="checking for ANSI C 99 support" */ int main () { int a; // c99 should accept this int b; // and this, too return 0; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/c++-template-specialization.c����������������������������������������������0000644�0000764�0000764�00000002500�10311235230�021152� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/c++-template-specialization.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* DESC="checking for C++ template specialization" */ template <typename T> class X { public: T testme (T t) { return t; } }; template <> class X<int> { public: int testme (int t) { return t*2; // yes - very useful } }; int main () { X<int> x; x.testme (4); return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/c++-rtti.c�����������������������������������������������������������������0000644�0000764�0000764�00000002355�10311235230�015315� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/c++-rtti.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* DESC="checking for C++ RTTI support" */ class X { public: virtual void z () = 0; }; class XX : public X { public: virtual void z () {} }; int main () { X* x; XX* xx = dynamic_cast <XX*> (x); return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/test-pc-stl����������������������������������������������������������������0000644�0000764�0000764�00000000314�10311235230�015714� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash # DESC="checking for precompiled STL" cat > conftest.cc <<- EOT #include <bits/stdc++.h> int main () { std::cout << "STL PC" << std::endl; return 0; } EOT cc -Winvalid-pch conftest.cc ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/test-pch-support�����������������������������������������������������������0000644�0000764�0000764�00000000170�10311235230�016776� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/bash # DESC="checking for PCH support" cat > conftest.hh <<- EOT class foo { int a; }; EOT cc conftest.hh ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/c++-available.c������������������������������������������������������������0000644�0000764�0000764�00000002370�10311235230�016250� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/c++-available.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* DESC="checking whether the C++ compiler works" */ class A { public: A () { } ~A () { } int testme (bool value = true) { if (value) return 1; else return 0; } }; int main () { A a; a.testme (); return 0; } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������exact-image-0.9.1/config/pkgcheck-alsa.c������������������������������������������������������������0000644�0000764�0000764�00000002277�10311235230�016465� 0����������������������������������������������������������������������������������������������������ustar �rene����������������������������rene�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * --- GSMP-COPYRIGHT-NOTE-BEGIN --- * * This copyright note is auto-generated by ./scripts/Create-CopyPatch. * Please add additional copyright information _after_ the line containing * the GSMP-COPYRIGHT-NOTE-END tag. Otherwise it might get removed by * the ./scripts/Create-CopyPatch script. Do not edit this copyright text! * * GSMP: config/pkgcheck-alsa.c * General Sound Manipulation Program is Copyright (C) 2000 - 2004 * Valentin Ziegler and René Rebe * * 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. * * --- GSMP-COPYRIGHT-NOTE-END --- */ /* CC="cc" CFLAGS="" LIBS="-lasound" */ #include <alsa/asoundlib.h> int main () { printf ("%d.%d.%d\n", SND_LIB_MAJOR, SND_LIB_MINOR, SND_LIB_SUBMINOR); return 0; } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������