"Fossies" - the Fresh Open Source Software Archive

Member "rawtherapee-5.7/rtengine/imageio.cc" (10 Sep 2019, 50568 Bytes) of package /linux/misc/rawtherapee-5.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "imageio.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.6_vs_5.7.

    1 /*
    2  *  This file is part of RawTherapee.
    3  *
    4  *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
    5  *  Copyright (c) 2010 Oliver Duis <www.oliverduis.de>
    6  *
    7  *  RawTherapee is free software: you can redistribute it and/or modify
    8  *  it under the terms of the GNU General Public License as published by
    9  *  the Free Software Foundation, either version 3 of the License, or
   10  *  (at your option) any later version.
   11  *
   12  *  RawTherapee is distributed in the hope that it will be useful,
   13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15  *  GNU General Public License for more details.
   16  *
   17  *  You should have received a copy of the GNU General Public License
   18  *  along with RawTherapee.  If not, see <https://www.gnu.org/licenses/>.
   19  */
   20 #include <png.h>
   21 #include <glib/gstdio.h>
   22 #include <tiff.h>
   23 #include <tiffio.h>
   24 #include <cstdio>
   25 #include <cstring>
   26 #include <fcntl.h>
   27 #include <libiptcdata/iptc-jpeg.h>
   28 #include "rt_math.h"
   29 #include "procparams.h"
   30 #include "../rtgui/options.h"
   31 #include "../rtgui/version.h"
   32 
   33 #ifdef WIN32
   34 #include <winsock2.h>
   35 #else
   36 #include <netinet/in.h>
   37 #endif
   38 
   39 #include "imageio.h"
   40 #include "iptcpairs.h"
   41 #include "iccjpeg.h"
   42 #include "color.h"
   43 
   44 #include "jpeg.h"
   45 
   46 using namespace std;
   47 using namespace rtengine;
   48 using namespace rtengine::procparams;
   49 
   50 namespace
   51 {
   52 
   53 // Opens a file for binary writing and request exclusive lock (cases were you need "wb" mode plus locking)
   54 FILE* g_fopen_withBinaryAndLock(const Glib::ustring& fname)
   55 {
   56 
   57 #ifdef WIN32
   58 
   59     // Use native function to disallow sharing, i.e. lock the file for exclusive access.
   60     // This is important to e.g. prevent Windows Explorer from crashing RT due to concurrently scanning an image file.
   61     std::unique_ptr<wchar_t, GFreeFunc> wfname (reinterpret_cast<wchar_t*>(g_utf8_to_utf16 (fname.c_str (), -1, NULL, NULL, NULL)), g_free);
   62 
   63     HANDLE hFile = CreateFileW ( wfname.get (), GENERIC_READ | GENERIC_WRITE, 0 /* no sharing allowed */, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
   64     FILE* f = nullptr;
   65 
   66     if (hFile != INVALID_HANDLE_VALUE) {
   67         f = _fdopen (_open_osfhandle ((intptr_t)hFile, 0), "wb");
   68     }
   69 
   70 #else
   71 
   72     FILE* f = ::g_fopen (fname.c_str (), "wb");
   73 
   74 #endif
   75 
   76     return f;
   77 }
   78 
   79 }
   80 
   81 Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid header.", "Error while reading header.", "File reading error", "Image format not supported."};
   82 
   83 // For only copying the raw input data
   84 void ImageIO::setMetadata (const rtexif::TagDirectory* eroot)
   85 {
   86     if (exifRoot != nullptr) {
   87         delete exifRoot;
   88         exifRoot = nullptr;
   89     }
   90 
   91     if (eroot) {
   92         rtexif::TagDirectory* td = eroot->clone (nullptr);
   93 
   94         // make IPTC and XMP pass through
   95         td->keepTag(0x83bb);  // IPTC
   96         td->keepTag(0x02bc);  // XMP
   97 
   98         exifRoot = td;
   99     }
  100 }
  101 
  102 // For merging with RT specific data
  103 void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::procparams::ExifPairs& exif, const rtengine::procparams::IPTCPairs& iptcc)
  104 {
  105 
  106     // store exif info
  107     exifChange->clear();
  108     *exifChange = exif;
  109 
  110     if (exifRoot != nullptr) {
  111         delete exifRoot;
  112         exifRoot = nullptr;
  113     }
  114 
  115     if (eroot) {
  116         exifRoot = eroot->clone (nullptr);
  117     }
  118 
  119     if (iptc != nullptr) {
  120         iptc_data_free (iptc);
  121         iptc = nullptr;
  122     }
  123 
  124     // build iptc structures for libiptcdata
  125     if (iptcc.empty()) {
  126         return;
  127     }
  128 
  129     iptc = iptc_data_new ();
  130 
  131     const unsigned char utf8Esc[] = {0x1B, '%', 'G'};
  132     IptcDataSet * ds = iptc_dataset_new ();
  133     iptc_dataset_set_tag (ds, IPTC_RECORD_OBJECT_ENV, IPTC_TAG_CHARACTER_SET);
  134     iptc_dataset_set_data (ds, utf8Esc, 3, IPTC_DONT_VALIDATE);
  135     iptc_data_add_dataset (iptc, ds);
  136     iptc_dataset_unref (ds);
  137 
  138     for (rtengine::procparams::IPTCPairs::const_iterator i = iptcc.begin(); i != iptcc.end(); ++i) {
  139         if (i->first == "Keywords" && !(i->second.empty())) {
  140             for (unsigned int j = 0; j < i->second.size(); j++) {
  141                 IptcDataSet * ds = iptc_dataset_new ();
  142                 iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_KEYWORDS);
  143                 iptc_dataset_set_data (ds, (const unsigned char*)i->second.at(j).c_str(), min(static_cast<size_t>(64), i->second.at(j).bytes()), IPTC_DONT_VALIDATE);
  144                 iptc_data_add_dataset (iptc, ds);
  145                 iptc_dataset_unref (ds);
  146             }
  147 
  148             continue;
  149         } else if (i->first == "SupplementalCategories" && !(i->second.empty())) {
  150             for (unsigned int j = 0; j < i->second.size(); j++) {
  151                 IptcDataSet * ds = iptc_dataset_new ();
  152                 iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_SUPPL_CATEGORY);
  153                 iptc_dataset_set_data (ds, (const unsigned char*)i->second.at(j).c_str(), min(static_cast<size_t>(32), i->second.at(j).bytes()), IPTC_DONT_VALIDATE);
  154                 iptc_data_add_dataset (iptc, ds);
  155                 iptc_dataset_unref (ds);
  156             }
  157 
  158             continue;
  159         }
  160 
  161         for (int j = 0; j < 16; j++)
  162             if (i->first == strTags[j].field && !(i->second.empty())) {
  163                 IptcDataSet * ds = iptc_dataset_new ();
  164                 iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, strTags[j].tag);
  165                 iptc_dataset_set_data (ds, (const unsigned char*)i->second.at(0).c_str(), min(strTags[j].size, i->second.at(0).bytes()), IPTC_DONT_VALIDATE);
  166                 iptc_data_add_dataset (iptc, ds);
  167                 iptc_dataset_unref (ds);
  168             }
  169     }
  170 
  171     iptc_data_sort (iptc);
  172 }
  173 
  174 void ImageIO::setOutputProfile  (const char* pdata, int plen)
  175 {
  176 
  177     delete [] profileData;
  178 
  179     if (pdata) {
  180         profileData = new char [plen];
  181         memcpy (profileData, pdata, plen);
  182     } else {
  183         profileData = nullptr;
  184     }
  185 
  186     profileLength = plen;
  187 }
  188 
  189 ImageIO::ImageIO() :
  190     pl(nullptr),
  191     embProfile(nullptr),
  192     profileData(nullptr),
  193     profileLength(0),
  194     loadedProfileData(nullptr),
  195     loadedProfileDataJpg(false),
  196     loadedProfileLength(0),
  197     exifChange(new procparams::ExifPairs),
  198     iptc(nullptr),
  199     exifRoot(nullptr),
  200     sampleFormat(IIOSF_UNKNOWN),
  201     sampleArrangement(IIOSA_UNKNOWN)
  202 {
  203 }
  204 
  205 ImageIO::~ImageIO ()
  206 {
  207 
  208     if (embProfile) {
  209         cmsCloseProfile(embProfile);
  210     }
  211 
  212     deleteLoadedProfileData();
  213     delete exifRoot;
  214     delete [] profileData;
  215 }
  216 
  217 void png_read_data(png_struct_def  *png_ptr, unsigned char *data, size_t length);
  218 void png_write_data(png_struct_def *png_ptr, unsigned char *data, size_t length);
  219 void png_flush(png_struct_def *png_ptr);
  220 
  221 int ImageIO::getPNGSampleFormat (const Glib::ustring &fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement)
  222 {
  223     FILE *file = g_fopen (fname.c_str (), "rb");
  224 
  225     if (!file) {
  226         return IMIO_CANNOTREADFILE;
  227     }
  228 
  229     //reading PNG header
  230     unsigned char header[8];
  231 
  232     if (fread (header, 1, 8, file) != 8 || png_sig_cmp (header, 0, 8)) {
  233         fclose(file);
  234         return IMIO_HEADERERROR;
  235     }
  236 
  237     //initializing main structures
  238     png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
  239 
  240     if (!png) {
  241         fclose (file);
  242         return IMIO_HEADERERROR;
  243     }
  244 
  245     png_infop info = png_create_info_struct (png);
  246     png_infop end_info = png_create_info_struct (png);
  247 
  248     if (!end_info || !info) {
  249         png_destroy_read_struct (&png, &info, &end_info);
  250         fclose (file);
  251         return IMIO_HEADERERROR;
  252     }
  253 
  254     if (setjmp (png_jmpbuf(png))) {
  255         png_destroy_read_struct (&png, &info, &end_info);
  256         fclose (file);
  257         return IMIO_READERROR;
  258     }
  259 
  260     //set up png read
  261     png_set_read_fn (png, file, png_read_data);
  262     png_set_sig_bytes (png, 8);
  263 
  264     png_read_info(png, info);
  265 
  266     //retrieving image information
  267     png_uint_32 width, height;
  268     int bit_depth, color_type, interlace_type, compression_type, filter_method;
  269     png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method);
  270 
  271     png_destroy_read_struct (&png, &info, &end_info);
  272     fclose (file);
  273 
  274     if (interlace_type != PNG_INTERLACE_NONE) {
  275         return IMIO_VARIANTNOTSUPPORTED;
  276     }
  277 
  278     if (bit_depth == 8) {
  279         sArrangement = IIOSA_CHUNKY;
  280         sFormat = IIOSF_UNSIGNED_CHAR;
  281         return IMIO_SUCCESS;
  282     } else if (bit_depth == 16) {
  283         sArrangement = IIOSA_CHUNKY;
  284         sFormat = IIOSF_UNSIGNED_SHORT;
  285         return IMIO_SUCCESS;
  286     } else {
  287         sArrangement = IIOSA_UNKNOWN;
  288         sFormat = IIOSF_UNKNOWN;
  289         return IMIO_VARIANTNOTSUPPORTED;
  290     }
  291 }
  292 
  293 int ImageIO::loadPNG  (const Glib::ustring &fname)
  294 {
  295 
  296     FILE *file = g_fopen (fname.c_str (), "rb");
  297 
  298     if (!file) {
  299         return IMIO_CANNOTREADFILE;
  300     }
  301 
  302     if (pl) {
  303         pl->setProgressStr ("PROGRESSBAR_LOADPNG");
  304         pl->setProgress (0.0);
  305     }
  306 
  307     //reading PNG header
  308     unsigned char header[8];
  309 
  310     if (fread (header, 1, 8, file) != 8 || png_sig_cmp (header, 0, 8)) {
  311         fclose(file);
  312         return IMIO_HEADERERROR;
  313     }
  314 
  315     //initializing main structures
  316     png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
  317 
  318     if (!png) {
  319         fclose (file);
  320         return IMIO_HEADERERROR;
  321     }
  322 
  323     // silence the warning about "invalid" sRGB profiles -- see #4260
  324 #if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && defined(PNG_SET_OPTION_SUPPORTED)
  325     png_set_option(png, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
  326 #endif
  327 
  328     png_infop info = png_create_info_struct (png);
  329     png_infop end_info = png_create_info_struct (png);
  330 
  331     if (!end_info || !info) {
  332         png_destroy_read_struct (&png, &info, &end_info);
  333         fclose (file);
  334         return IMIO_HEADERERROR;
  335     }
  336 
  337     if (setjmp (png_jmpbuf(png))) {
  338         png_destroy_read_struct (&png, &info, &end_info);
  339         fclose (file);
  340         return IMIO_READERROR;
  341     }
  342 
  343     //set up png read
  344     png_set_read_fn (png, file, png_read_data);
  345     png_set_sig_bytes (png, 8);
  346 
  347     png_read_info(png, info);
  348 
  349     embProfile = nullptr;
  350 
  351     //retrieving image information
  352     png_uint_32 width, height;
  353     int bit_depth, color_type, interlace_type, compression_type, filter_method;
  354     png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method);
  355 
  356     if (color_type == PNG_COLOR_TYPE_PALETTE || interlace_type != PNG_INTERLACE_NONE )  {
  357         // we don't support interlaced png or png with palette
  358         png_destroy_read_struct (&png, &info, &end_info);
  359         fclose (file);
  360         printf("%s uses an unsupported feature: <palette-indexed colors|interlacing>. Skipping.\n", fname.data());
  361         return IMIO_VARIANTNOTSUPPORTED;
  362     }
  363 
  364     if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
  365         png_set_gray_to_rgb(png);
  366     }
  367 
  368     if (png_get_valid(png, info, PNG_INFO_tRNS)) {
  369         png_set_tRNS_to_alpha(png);
  370     }
  371 
  372     if (color_type & PNG_COLOR_MASK_ALPHA) {
  373         png_set_strip_alpha(png);
  374     }
  375 
  376     // reading the embedded ICC profile if any
  377     if (png_get_valid(png, info, PNG_INFO_iCCP)) {
  378         png_charp name;
  379         int compression_type;
  380 #if PNG_LIBPNG_VER < 10500
  381         png_charp profdata;
  382 #else
  383         png_bytep profdata;
  384 #endif
  385         png_uint_32 proflen;
  386         png_get_iCCP(png, info, &name, &compression_type, &profdata, &proflen);
  387         embProfile = cmsOpenProfileFromMem(profdata, proflen);
  388         loadedProfileData = new char[proflen];
  389         memcpy(loadedProfileData, profdata, proflen);
  390     }
  391 
  392     //setting gamma
  393     double gamma;
  394 
  395     if (png_get_gAMA(png, info, &gamma)) {
  396         png_set_gamma(png, 1.0 / gamma, gamma);    // use gamma from metadata
  397     } else {
  398         png_set_gamma(png, 2.2, 1.0 / 2.2);    // no gamma in metadata, suppose gamma 2.2
  399     }
  400 
  401 //  if (bps==8 && bit_depth==16) png_set_strip_16(png);
  402 
  403     //updating png info struct
  404     png_read_update_info(png, info);
  405     png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_method);
  406 
  407     allocate (width, height);
  408 
  409     int rowlen = width * 3 * bit_depth / 8;
  410     unsigned char *row = new unsigned char [rowlen];
  411 
  412     // set a new jump point to avoid memory leak
  413     if (setjmp (png_jmpbuf(png))) {
  414         png_destroy_read_struct (&png, &info, &end_info);
  415         fclose (file);
  416         delete [] row;
  417         return IMIO_READERROR;
  418     }
  419 
  420     for (unsigned int i = 0; i < height; i++) {
  421 
  422         png_read_row (png, (png_byte*)row, nullptr);
  423 
  424         if (bit_depth == 16) { // convert scanline to host byte order
  425             unsigned short* srow = (unsigned short*)row;
  426 
  427             for (unsigned int j = 0; j < width * 3; j++) {
  428                 srow[j] = ntohs (srow[j]);
  429             }
  430         }
  431 
  432         setScanline (i, row, bit_depth);
  433 
  434         if (pl && !(i % 100)) {
  435             pl->setProgress ((double)(i + 1) / height);
  436         }
  437     }
  438 
  439     png_read_end (png, nullptr);
  440     png_destroy_read_struct (&png, &info, &end_info);
  441 
  442     delete [] row;
  443     fclose(file);
  444 
  445     if (pl) {
  446         pl->setProgressStr ("PROGRESSBAR_READY");
  447         pl->setProgress (1.0);
  448     }
  449 
  450     return IMIO_SUCCESS;
  451 }
  452 
  453 typedef struct  {
  454     struct jpeg_error_mgr pub;  /* "public" fields */
  455     jmp_buf setjmp_buffer;  /* for return to caller */
  456 } my_error_mgr;
  457 
  458 void my_error_exit (j_common_ptr cinfo)
  459 {
  460     /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */
  461     my_error_mgr *myerr = (my_error_mgr*) cinfo->err;
  462     /* Always display the message. */
  463     /* We could postpone this until after returning, if we chose. */
  464     (*cinfo->err->output_message) (cinfo);
  465 
  466     /* Return control to the setjmp point */
  467 #if defined( WIN32 ) && defined( __x86_64__ ) && !defined(__clang__)
  468     __builtin_longjmp(myerr->setjmp_buffer, 1);
  469 #else
  470     longjmp(myerr->setjmp_buffer, 1);
  471 #endif
  472 }
  473 
  474 
  475 int ImageIO::loadJPEGFromMemory (const char* buffer, int bufsize)
  476 {
  477     jpeg_decompress_struct cinfo;
  478     jpeg_create_decompress(&cinfo);
  479     jpeg_memory_src (&cinfo, (const JOCTET*)buffer, bufsize);
  480 
  481     /* We use our private extension JPEG error handler.
  482        Note that this struct must live as long as the main JPEG parameter
  483        struct, to avoid dangling-pointer problems.
  484     */
  485     my_error_mgr jerr;
  486     /* We set up the normal JPEG error routines, then override error_exit. */
  487     cinfo.err = jpeg_std_error(&jerr.pub);
  488     jerr.pub.error_exit = my_error_exit;
  489 
  490     /* Establish the setjmp return context for my_error_exit to use. */
  491 #if defined( WIN32 ) && defined( __x86_64__ ) && !defined(__clang__)
  492 
  493     if (__builtin_setjmp(jerr.setjmp_buffer)) {
  494 #else
  495 
  496     if (setjmp(jerr.setjmp_buffer)) {
  497 #endif
  498         /* If we get here, the JPEG code has signaled an error.
  499            We need to clean up the JPEG object and return.
  500         */
  501         jpeg_destroy_decompress(&cinfo);
  502         return IMIO_READERROR;
  503     }
  504 
  505 
  506     if (pl) {
  507         pl->setProgressStr ("PROGRESSBAR_LOADJPEG");
  508         pl->setProgress (0.0);
  509 
  510     }
  511 
  512     setup_read_icc_profile (&cinfo);
  513 
  514     jpeg_read_header(&cinfo, TRUE);
  515 
  516     deleteLoadedProfileData();
  517     loadedProfileDataJpg = true;
  518     bool hasprofile = read_icc_profile (&cinfo, (JOCTET**)&loadedProfileData, (unsigned int*)&loadedProfileLength);
  519 
  520     if (hasprofile) {
  521         embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength);
  522     } else {
  523         embProfile = nullptr;
  524     }
  525 
  526     jpeg_start_decompress(&cinfo);
  527 
  528     unsigned int width = cinfo.output_width;
  529     unsigned int height = cinfo.output_height;
  530 
  531     allocate (width, height);
  532 
  533     unsigned char *row = new unsigned char[width * 3];
  534 
  535     while (cinfo.output_scanline < height) {
  536         if (jpeg_read_scanlines(&cinfo, &row, 1) < 1) {
  537             jpeg_finish_decompress(&cinfo);
  538             jpeg_destroy_decompress(&cinfo);
  539             delete [] row;
  540             return IMIO_READERROR;
  541         }
  542 
  543         setScanline (cinfo.output_scanline - 1, row, 8, cinfo.num_components);
  544 
  545         if (pl && !(cinfo.output_scanline % 100)) {
  546             pl->setProgress ((double)(cinfo.output_scanline) / cinfo.output_height);
  547         }
  548     }
  549 
  550     delete [] row;
  551 
  552     jpeg_finish_decompress(&cinfo);
  553     jpeg_destroy_decompress(&cinfo);
  554 
  555     if (pl) {
  556         pl->setProgressStr ("PROGRESSBAR_READY");
  557         pl->setProgress (1.0);
  558     }
  559 
  560     return IMIO_SUCCESS;
  561 }
  562 
  563 int ImageIO::loadJPEG (const Glib::ustring &fname)
  564 {
  565     FILE *file = g_fopen(fname.c_str (), "rb");
  566 
  567     if (!file) {
  568         return IMIO_CANNOTREADFILE;
  569     }
  570 
  571     jpeg_decompress_struct cinfo;
  572     jpeg_error_mgr jerr;
  573     cinfo.err = my_jpeg_std_error(&jerr);
  574     jpeg_create_decompress(&cinfo);
  575 
  576     my_jpeg_stdio_src (&cinfo, file);
  577 
  578 #if defined( WIN32 ) && defined( __x86_64__ ) && !defined(__clang__)
  579     if ( __builtin_setjmp((reinterpret_cast<rt_jpeg_error_mgr*>(cinfo.src))->error_jmp_buf) == 0 ) {
  580 #else
  581     if ( setjmp((reinterpret_cast<rt_jpeg_error_mgr*>(cinfo.src))->error_jmp_buf) == 0 ) {
  582 #endif
  583         if (pl) {
  584             pl->setProgressStr ("PROGRESSBAR_LOADJPEG");
  585             pl->setProgress (0.0);
  586         }
  587 
  588         setup_read_icc_profile (&cinfo);
  589 
  590         //jpeg_stdio_src(&cinfo,file);
  591         jpeg_read_header(&cinfo, TRUE);
  592 
  593         //if JPEG is CMYK, then abort reading
  594         if (cinfo.jpeg_color_space == JCS_CMYK || cinfo.jpeg_color_space == JCS_YCCK) {
  595             jpeg_destroy_decompress(&cinfo);
  596             return IMIO_READERROR;
  597         }
  598 
  599         cinfo.out_color_space = JCS_RGB;
  600 
  601         deleteLoadedProfileData();
  602         loadedProfileDataJpg = true;
  603         bool hasprofile = read_icc_profile (&cinfo, (JOCTET**)&loadedProfileData, (unsigned int*)&loadedProfileLength);
  604 
  605         if (hasprofile) {
  606             embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength);
  607         } else {
  608             embProfile = nullptr;
  609         }
  610 
  611         jpeg_start_decompress(&cinfo);
  612 
  613         unsigned int width = cinfo.output_width;
  614         unsigned int height = cinfo.output_height;
  615 
  616         allocate (width, height);
  617 
  618         unsigned char *row = new unsigned char[width * 3];
  619 
  620         while (cinfo.output_scanline < height) {
  621             if (jpeg_read_scanlines(&cinfo, &row, 1) < 1) {
  622                 jpeg_finish_decompress(&cinfo);
  623                 jpeg_destroy_decompress(&cinfo);
  624                 delete [] row;
  625                 return IMIO_READERROR;
  626             }
  627 
  628             setScanline (cinfo.output_scanline - 1, row, 8);
  629 
  630             if (pl && !(cinfo.output_scanline % 100)) {
  631                 pl->setProgress ((double)(cinfo.output_scanline) / cinfo.output_height);
  632             }
  633         }
  634 
  635         delete [] row;
  636 
  637         jpeg_finish_decompress(&cinfo);
  638         jpeg_destroy_decompress(&cinfo);
  639         fclose(file);
  640 
  641         if (pl) {
  642             pl->setProgressStr ("PROGRESSBAR_READY");
  643             pl->setProgress (1.0);
  644         }
  645 
  646         return IMIO_SUCCESS;
  647     } else {
  648         jpeg_destroy_decompress(&cinfo);
  649         return IMIO_READERROR;
  650     }
  651 }
  652 
  653 int ImageIO::getTIFFSampleFormat (const Glib::ustring &fname, IIOSampleFormat &sFormat, IIOSampleArrangement &sArrangement)
  654 {
  655 #ifdef WIN32
  656     wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL);
  657     TIFF* in = TIFFOpenW (wfilename, "r");
  658     g_free (wfilename);
  659 #else
  660     TIFF* in = TIFFOpen(fname.c_str(), "r");
  661 #endif
  662 
  663     if (in == nullptr) {
  664         return IMIO_CANNOTREADFILE;
  665     }
  666 
  667     uint16 bitspersample = 0, samplesperpixel = 0, sampleformat = 0;
  668     int hasTag = TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
  669     hasTag &= TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
  670 
  671     if (!hasTag) {
  672         // These are needed
  673         TIFFClose(in);
  674         sFormat = IIOSF_UNKNOWN;
  675         return IMIO_VARIANTNOTSUPPORTED;
  676     }
  677 
  678     if (!TIFFGetField(in, TIFFTAG_SAMPLEFORMAT, &sampleformat))
  679         /*
  680          * WARNING: This is a dirty hack!
  681          * We assume that files which doesn't contain the TIFFTAG_SAMPLEFORMAT tag
  682          * (which is the case with uncompressed TIFFs produced by RT!) are RGB files,
  683          * but that may be not true.   --- Hombre
  684          */
  685     {
  686         sampleformat = SAMPLEFORMAT_UINT;
  687     }
  688 
  689     uint16 config;
  690     TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config);
  691 
  692     if (config == PLANARCONFIG_CONTIG) {
  693         sArrangement = IIOSA_CHUNKY;
  694     } else {
  695         sFormat = IIOSF_UNKNOWN;
  696         sArrangement = IIOSA_UNKNOWN;
  697         TIFFClose(in);
  698         return IMIO_VARIANTNOTSUPPORTED;
  699     }
  700 
  701     uint16 photometric;
  702 
  703     if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric)) {
  704         TIFFClose(in);
  705         return IMIO_VARIANTNOTSUPPORTED;
  706     }
  707 
  708     uint16 compression;
  709 
  710     if (photometric == PHOTOMETRIC_LOGLUV)
  711         if (!TIFFGetField(in, TIFFTAG_COMPRESSION, &compression)) {
  712             compression = COMPRESSION_NONE;
  713         }
  714 
  715     TIFFClose(in);
  716 
  717     if (photometric == PHOTOMETRIC_RGB || photometric == PHOTOMETRIC_MINISBLACK) {
  718         if ((samplesperpixel == 1 || samplesperpixel == 3 || samplesperpixel == 4) && sampleformat == SAMPLEFORMAT_UINT) {
  719             if (bitspersample == 8) {
  720                 sFormat = IIOSF_UNSIGNED_CHAR;
  721                 return IMIO_SUCCESS;
  722             }
  723 
  724             if (bitspersample == 16) {
  725                 sFormat = IIOSF_UNSIGNED_SHORT;
  726                 return IMIO_SUCCESS;
  727             }
  728         } else if ((samplesperpixel == 3 || samplesperpixel == 4) && sampleformat == SAMPLEFORMAT_IEEEFP) {
  729             if (bitspersample==16) {
  730                 sFormat = IIOSF_FLOAT16;
  731                 return IMIO_SUCCESS;
  732             }
  733             if (bitspersample == 24) {
  734                 sFormat = IIOSF_FLOAT24;
  735                 return IMIO_SUCCESS;
  736             }
  737             if (bitspersample == 32) {
  738                 sFormat = IIOSF_FLOAT32;
  739                 return IMIO_SUCCESS;
  740             }
  741         }
  742     } else if ((samplesperpixel == 3 || samplesperpixel == 4) && photometric == PHOTOMETRIC_LOGLUV) {
  743         if (compression == COMPRESSION_SGILOG24) {
  744             sFormat = IIOSF_LOGLUV24;
  745             return IMIO_SUCCESS;
  746         } else if (compression == COMPRESSION_SGILOG) {
  747             sFormat = IIOSF_LOGLUV32;
  748             return IMIO_SUCCESS;
  749         }
  750     }
  751 
  752     return IMIO_VARIANTNOTSUPPORTED;
  753 }
  754 
  755 int ImageIO::loadTIFF (const Glib::ustring &fname)
  756 {
  757 
  758     static MyMutex thumbMutex;
  759     MyMutex::MyLock lock(thumbMutex);
  760 
  761     if(!options.serializeTiffRead) {
  762         lock.release();
  763     }
  764 
  765 #ifdef WIN32
  766     wchar_t *wfilename = (wchar_t*)g_utf8_to_utf16 (fname.c_str(), -1, NULL, NULL, NULL);
  767     TIFF* in = TIFFOpenW (wfilename, "r");
  768     g_free (wfilename);
  769 #else
  770     TIFF* in = TIFFOpen(fname.c_str(), "r");
  771 #endif
  772 
  773     if (in == nullptr) {
  774         return IMIO_CANNOTREADFILE;
  775     }
  776 
  777     if (pl) {
  778         pl->setProgressStr ("PROGRESSBAR_LOADTIFF");
  779         pl->setProgress (0.0);
  780     }
  781 
  782     int width, height;
  783     TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width);
  784     TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height);
  785 
  786     uint16 bitspersample, samplesperpixel;
  787     int hasTag = TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
  788     hasTag &= TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
  789 
  790     if (!hasTag) {
  791         // These are needed
  792         TIFFClose(in);
  793         return IMIO_VARIANTNOTSUPPORTED;
  794     }
  795 
  796     uint16 config;
  797     TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config);
  798 
  799     if (config != PLANARCONFIG_CONTIG) {
  800         TIFFClose(in);
  801         return IMIO_VARIANTNOTSUPPORTED;
  802     }
  803 
  804     if (sampleFormat & (IIOSF_LOGLUV24 | IIOSF_LOGLUV32)) {
  805         TIFFSetField(in, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_FLOAT);
  806     }
  807 
  808     /*
  809      * We could use the min/max values set in TIFFTAG_SMINSAMPLEVALUE and
  810      * TIFFTAG_SMAXSAMPLEVALUE, but for now, we normalize the image to the
  811      * effective minimum and maximum values
  812      */
  813     if (options.rtSettings.verbose) {
  814         printf("Information of \"%s\":\n", fname.c_str());
  815         uint16 tiffDefaultScale, tiffBaselineExposure, tiffLinearResponseLimit;
  816         if (TIFFGetField(in, TIFFTAG_DEFAULTSCALE, &tiffDefaultScale)) {
  817             printf("   DefaultScale: %d\n", tiffDefaultScale);
  818         }
  819         else
  820             printf("   No DefaultScale value!\n");
  821         if (TIFFGetField(in, TIFFTAG_BASELINEEXPOSURE, &tiffBaselineExposure)) {
  822             printf("   BaselineExposure: %d\n", tiffBaselineExposure);
  823         }
  824         else
  825             printf("   No BaselineExposure value!\n");
  826         if (TIFFGetField(in, TIFFTAG_LINEARRESPONSELIMIT, &tiffLinearResponseLimit)) {
  827             printf("   LinearResponseLimit: %d\n", tiffLinearResponseLimit);
  828         }
  829         else
  830             printf("   No LinearResponseLimit value!\n");
  831 
  832         uint16 tiffMinValue, tiffMaxValue;
  833         if (TIFFGetField(in, TIFFTAG_SMINSAMPLEVALUE, &tiffMinValue)) {
  834             printf("   MinValue: %d\n", tiffMinValue);
  835         }
  836         else
  837             printf("   No minimum value!\n");
  838         if (TIFFGetField(in, TIFFTAG_SMAXSAMPLEVALUE, &tiffMaxValue)) {
  839             printf("   MaxValue: %d\n\n", tiffMaxValue);
  840         }
  841         else
  842             printf("   No maximum value!\n\n");
  843         printf("   Those values are not taken into account, the image data are normalized to a [0;1] range\n\n");
  844     }
  845 
  846     char* profdata;
  847     deleteLoadedProfileData();
  848     loadedProfileDataJpg = false;
  849 
  850     if (TIFFGetField(in, TIFFTAG_ICCPROFILE, &loadedProfileLength, &profdata)) {
  851         embProfile = cmsOpenProfileFromMem (profdata, loadedProfileLength);
  852         loadedProfileData = new char [loadedProfileLength];
  853         memcpy (loadedProfileData, profdata, loadedProfileLength);
  854     } else {
  855         embProfile = nullptr;
  856     }
  857 
  858     allocate (width, height);
  859 
  860     unsigned char* linebuffer = new unsigned char[TIFFScanlineSize(in) * (samplesperpixel == 1 ? 3 : 1)];
  861 
  862     for (int row = 0; row < height; row++) {
  863         if (TIFFReadScanline(in, linebuffer, row, 0) < 0) {
  864             TIFFClose(in);
  865             delete [] linebuffer;
  866             return IMIO_READERROR;
  867         }
  868 
  869         if (samplesperpixel > 3) {
  870             for (int i = 0; i < width; i++) {
  871                 memcpy (linebuffer + i * 3 * bitspersample / 8, linebuffer + i * samplesperpixel * bitspersample / 8, 3 * bitspersample / 8);
  872             }
  873         }
  874         else if (samplesperpixel == 1) {
  875             const size_t bytes = bitspersample / 8;
  876             for (int i = width - 1; i >= 0; --i) {
  877                 const unsigned char* const src = linebuffer + i * bytes;
  878                 unsigned char* const dest = linebuffer + i * 3 * bytes;
  879                 memcpy(dest + 2 * bytes, src, bytes);
  880                 memcpy(dest + 1 * bytes, src, bytes);
  881                 memcpy(dest + 0 * bytes, src, bytes);
  882             }
  883         }
  884 
  885         setScanline (row, linebuffer, bitspersample);
  886 
  887         if (pl && !(row % 100)) {
  888             pl->setProgress ((double)(row + 1) / height);
  889         }
  890     }
  891 
  892     TIFFClose(in);
  893     delete [] linebuffer;
  894 
  895     if (pl) {
  896         pl->setProgressStr ("PROGRESSBAR_READY");
  897         pl->setProgress (1.0);
  898     }
  899 
  900     return IMIO_SUCCESS;
  901 }
  902 
  903 int ImageIO::loadPPMFromMemory(const char* buffer, int width, int height, bool swap, int bps)
  904 {
  905     allocate (width, height);
  906 
  907     int line_length(width * 3 * (bps / 8));
  908 
  909     if ( swap && bps > 8 ) {
  910         char swapped[line_length];
  911 
  912         for ( int row = 0; row < height; ++row ) {
  913             ::rtengine::swab(((const char*)buffer) + (row * line_length), swapped, line_length);
  914             setScanline(row, (unsigned char*)&swapped[0], bps);
  915         }
  916     } else {
  917         for ( int row = 0; row < height; ++row ) {
  918             setScanline(row, ((const unsigned char*)buffer) + (row * line_length), bps);
  919         }
  920     }
  921 
  922     return IMIO_SUCCESS;
  923 }
  924 
  925 
  926 namespace {
  927 
  928 // Taken from Darktable -- src/imageio/format/png.c
  929 //
  930 /* Write EXIF data to PNG file.
  931  * Code copied from DigiKam's libs/dimg/loaders/pngloader.cpp.
  932  * The EXIF embedding is defined by ImageMagicK.
  933  * It is documented in the ExifTool page:
  934  * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html
  935  *
  936  * ..and in turn copied from ufraw. thanks to udi and colleagues
  937  * for making useful code much more readable and discoverable ;)
  938  */
  939 
  940 void PNGwriteRawProfile(png_struct *ping, png_info *ping_info, const char *profile_type, guint8 *profile_data, png_uint_32 length)
  941 {
  942     png_textp text;
  943     long i;
  944     guint8 *sp;
  945     png_charp dp;
  946     png_uint_32 allocated_length, description_length;
  947 
  948     const guint8 hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
  949     text = static_cast<png_textp>(png_malloc(ping, sizeof(png_text)));
  950     description_length = strlen(profile_type);
  951     allocated_length = length * 2 + (length >> 5) + 20 + description_length;
  952 
  953     text[0].text = static_cast<png_charp>(png_malloc(ping, allocated_length));
  954     text[0].key = static_cast<png_charp>(png_malloc(ping, 80));
  955     text[0].key[0] = '\0';
  956 
  957     g_strlcat(text[0].key, "Raw profile type ", 80);
  958     g_strlcat(text[0].key, profile_type, 80);
  959 
  960     sp = profile_data;
  961     dp = text[0].text;
  962     *dp++ = '\n';
  963 
  964     g_strlcpy(dp, profile_type, allocated_length);
  965 
  966     dp += description_length;
  967     *dp++ = '\n';
  968     *dp = '\0';
  969 
  970     g_snprintf(dp, allocated_length - strlen(text[0].text), "%8lu ", static_cast<unsigned long int>(length));
  971 
  972     dp += 8;
  973 
  974     for(i = 0; i < long(length); i++)
  975     {
  976         if(i % 36 == 0) *dp++ = '\n';
  977 
  978         *(dp++) = hex[((*sp >> 4) & 0x0f)];
  979         *(dp++) = hex[((*sp++) & 0x0f)];
  980     }
  981 
  982     *dp++ = '\n';
  983     *dp = '\0';
  984     text[0].text_length = (dp - text[0].text);
  985     text[0].compression = -1;
  986 
  987     if(text[0].text_length <= allocated_length) png_set_text(ping, ping_info, text, 1);
  988 
  989     png_free(ping, text[0].text);
  990     png_free(ping, text[0].key);
  991     png_free(ping, text);
  992 }
  993 
  994 } // namespace
  995 
  996 int ImageIO::savePNG  (const Glib::ustring &fname, int bps) const
  997 {
  998     if (getWidth() < 1 || getHeight() < 1) {
  999         return IMIO_HEADERERROR;
 1000     }
 1001 
 1002     FILE* const file = g_fopen_withBinaryAndLock (fname);
 1003 
 1004     if (!file) {
 1005         return IMIO_CANNOTWRITEFILE;
 1006     }
 1007 
 1008     if (pl) {
 1009         pl->setProgressStr ("PROGRESSBAR_SAVEPNG");
 1010         pl->setProgress (0.0);
 1011     }
 1012 
 1013     png_structp png = png_create_write_struct (PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
 1014 
 1015     if (!png) {
 1016         fclose (file);
 1017         return IMIO_HEADERERROR;
 1018     }
 1019 
 1020     // silence the warning about "invalid" sRGB profiles -- see #4260
 1021 #if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && defined(PNG_SET_OPTION_SUPPORTED)
 1022     png_set_option(png, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
 1023 #endif
 1024     
 1025     png_infop info = png_create_info_struct(png);
 1026 
 1027     if (!info) {
 1028         png_destroy_write_struct (&png, nullptr);
 1029         fclose (file);
 1030         return IMIO_HEADERERROR;
 1031     }
 1032 
 1033     if (setjmp(png_jmpbuf(png))) {
 1034         png_destroy_write_struct (&png, &info);
 1035         fclose(file);
 1036         return IMIO_CANNOTWRITEFILE;
 1037     }
 1038 
 1039     png_set_write_fn (png, file, png_write_data, png_flush);
 1040 
 1041     png_set_filter(png, 0, PNG_FILTER_PAETH);
 1042     png_set_compression_level(png, 6);
 1043     png_set_compression_strategy(png, 3);
 1044 
 1045     int width = getWidth ();
 1046     int height = getHeight ();
 1047 
 1048     if (bps < 0) {
 1049         bps = getBPS ();
 1050     }
 1051     if (bps > 16) {
 1052         bps = 16;
 1053     }
 1054 
 1055     png_set_IHDR(png, info, width, height, bps, PNG_COLOR_TYPE_RGB,
 1056                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE);
 1057 
 1058     if (profileData) {
 1059 #if PNG_LIBPNG_VER < 10500
 1060         png_charp profdata = reinterpret_cast<png_charp>(profileData);
 1061 #else
 1062         png_bytep profdata = reinterpret_cast<png_bytep>(profileData);
 1063 #endif
 1064         png_set_iCCP(png, info, const_cast<png_charp>("icc"), 0, profdata, profileLength);
 1065     }
 1066 
 1067     {
 1068         // buffer for the exif and iptc
 1069         unsigned int bufferSize;
 1070         unsigned char* buffer = nullptr; // buffer will be allocated in createTIFFHeader
 1071         unsigned char* iptcdata = nullptr;
 1072         unsigned int iptclen = 0;
 1073 
 1074         if (iptc && iptc_data_save (iptc, &iptcdata, &iptclen) && iptcdata) {
 1075             iptc_data_free_buf (iptc, iptcdata);
 1076             iptcdata = nullptr;
 1077         }
 1078 
 1079         int size = rtexif::ExifManager::createPNGMarker(exifRoot, *exifChange, width, height, bps, (char*)iptcdata, iptclen, buffer, bufferSize);
 1080 
 1081         if (iptcdata) {
 1082             iptc_data_free_buf (iptc, iptcdata);
 1083         }
 1084         if (buffer && size) {
 1085             PNGwriteRawProfile(png, info, "exif", buffer, size);
 1086             delete[] buffer;
 1087         }
 1088     }
 1089 
 1090 
 1091     int rowlen = width * 3 * bps / 8;
 1092     unsigned char *row = new unsigned char [rowlen];
 1093 
 1094     png_write_info(png, info);
 1095 
 1096     for (int i = 0; i < height; i++) {
 1097         getScanline (i, row, bps);
 1098 
 1099         if (bps == 16) {
 1100             // convert to network byte order
 1101 #if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
 1102             for (int j = 0; j < width * 6; j += 2) {
 1103                 unsigned char tmp = row[j];
 1104                 row[j] = row[j + 1];
 1105                 row[j + 1] = tmp;
 1106             }
 1107 
 1108 #endif
 1109         }
 1110 
 1111         png_write_row (png, (png_byte*)row);
 1112 
 1113         if (pl && !(i % 100)) {
 1114             pl->setProgress ((double)(i + 1) / height);
 1115         }
 1116     }
 1117 
 1118     png_write_end(png, info);
 1119     png_destroy_write_struct(&png, &info);
 1120 
 1121     delete [] row;
 1122     fclose (file);
 1123 
 1124     if (pl) {
 1125         pl->setProgressStr ("PROGRESSBAR_READY");
 1126         pl->setProgress (1.0);
 1127     }
 1128 
 1129     return IMIO_SUCCESS;
 1130 }
 1131 
 1132 
 1133 
 1134 // Quality 0..100, subsampling: 1=low quality, 2=medium, 3=high
 1135 int ImageIO::saveJPEG (const Glib::ustring &fname, int quality, int subSamp) const
 1136 {
 1137     if (getWidth() < 1 || getHeight() < 1) {
 1138         return IMIO_HEADERERROR;
 1139     }
 1140 
 1141     FILE* const file = g_fopen_withBinaryAndLock (fname);
 1142 
 1143     if (!file) {
 1144         return IMIO_CANNOTWRITEFILE;
 1145     }
 1146 
 1147     jpeg_compress_struct cinfo;
 1148     /* We use our private extension JPEG error handler.
 1149        Note that this struct must live as long as the main JPEG parameter
 1150        struct, to avoid dangling-pointer problems.
 1151     */
 1152     my_error_mgr jerr;
 1153     /* We set up the normal JPEG error routines, then override error_exit. */
 1154     cinfo.err = jpeg_std_error(&jerr.pub);
 1155     jerr.pub.error_exit = my_error_exit;
 1156 
 1157     /* Establish the setjmp return context for my_error_exit to use. */
 1158 #if defined( WIN32 ) && defined( __x86_64__ ) && !defined(__clang__)
 1159 
 1160     if (__builtin_setjmp(jerr.setjmp_buffer)) {
 1161 #else
 1162 
 1163     if (setjmp(jerr.setjmp_buffer)) {
 1164 #endif
 1165         /* If we get here, the JPEG code has signaled an error.
 1166            We need to clean up the JPEG object, close the file, remove the already saved part of the file and return.
 1167         */
 1168         jpeg_destroy_compress(&cinfo);
 1169         fclose(file);
 1170         g_remove (fname.c_str());
 1171         return IMIO_CANNOTWRITEFILE;
 1172     }
 1173 
 1174     jpeg_create_compress (&cinfo);
 1175 
 1176 
 1177 
 1178     if (pl) {
 1179         pl->setProgressStr ("PROGRESSBAR_SAVEJPEG");
 1180         pl->setProgress (0.0);
 1181     }
 1182 
 1183     jpeg_stdio_dest (&cinfo, file);
 1184 
 1185     int width = getWidth ();
 1186     int height = getHeight ();
 1187 
 1188     cinfo.image_width  = width;
 1189     cinfo.image_height = height;
 1190     cinfo.in_color_space = JCS_RGB;
 1191     cinfo.input_components = 3;
 1192     jpeg_set_defaults (&cinfo);
 1193     cinfo.write_JFIF_header = FALSE;
 1194 
 1195     // compute optimal Huffman coding tables for the image. Bit slower to generate, but size of result image is a bit less (default was FALSE)
 1196     cinfo.optimize_coding = TRUE;
 1197 
 1198     // Since math coprocessors are common these days, FLOAT should be a bit more accurate AND fast (default is ISLOW)
 1199     // (machine dependency is not really an issue, since we all run on x86 and having exactly the same file is not a requirement)
 1200     cinfo.dct_method = JDCT_FLOAT;
 1201 
 1202     if (quality >= 0 && quality <= 100) {
 1203         jpeg_set_quality (&cinfo, quality, true);
 1204     }
 1205 
 1206     cinfo.comp_info[1].h_samp_factor = cinfo.comp_info[1].v_samp_factor = 1;
 1207     cinfo.comp_info[2].h_samp_factor = cinfo.comp_info[2].v_samp_factor = 1;
 1208 
 1209     if (subSamp == 1) {
 1210         // Best compression, default of the JPEG library:  2x2, 1x1, 1x1 (4:2:0)
 1211         cinfo.comp_info[0].h_samp_factor = cinfo.comp_info[0].v_samp_factor = 2;
 1212     } else if (subSamp == 2) {
 1213         // Widely used normal ratio 2x1, 1x1, 1x1 (4:2:2)
 1214         cinfo.comp_info[0].h_samp_factor = 2;
 1215         cinfo.comp_info[0].v_samp_factor = 1;
 1216     } else if (subSamp == 3) {
 1217         // Best quality 1x1 1x1 1x1 (4:4:4)
 1218         cinfo.comp_info[0].h_samp_factor = cinfo.comp_info[0].v_samp_factor = 1;
 1219     }
 1220 
 1221     jpeg_start_compress(&cinfo, TRUE);
 1222 
 1223     // buffer for exif and iptc markers
 1224     unsigned char* buffer = new unsigned char[165535]; //FIXME: no buffer size check so it can be overflowed in createJPEGMarker() for large tags, and then software will crash
 1225     unsigned int size;
 1226 
 1227     // assemble and write exif marker
 1228     if (exifRoot) {
 1229         int size = rtexif::ExifManager::createJPEGMarker (exifRoot, *exifChange, cinfo.image_width, cinfo.image_height, buffer);
 1230 
 1231         if (size > 0 && size < 65530) {
 1232             jpeg_write_marker(&cinfo, JPEG_APP0 + 1, buffer, size);
 1233         }
 1234     }
 1235 
 1236     // assemble and write iptc marker
 1237     if (iptc) {
 1238         unsigned char* iptcdata;
 1239         bool error = false;
 1240 
 1241         if (iptc_data_save (iptc, &iptcdata, &size)) {
 1242             if (iptcdata) {
 1243                 iptc_data_free_buf (iptc, iptcdata);
 1244             }
 1245 
 1246             error = true;
 1247         }
 1248 
 1249         int bytes = 0;
 1250 
 1251         if (!error && (bytes = iptc_jpeg_ps3_save_iptc (nullptr, 0, iptcdata, size, buffer, 65532)) < 0) {
 1252             error = true;
 1253         }
 1254 
 1255         if (iptcdata) {
 1256             iptc_data_free_buf (iptc, iptcdata);
 1257         }
 1258 
 1259         if (!error) {
 1260             jpeg_write_marker(&cinfo, JPEG_APP0 + 13, buffer, bytes);
 1261         }
 1262     }
 1263 
 1264     delete [] buffer;
 1265 
 1266     // write icc profile to the output
 1267     if (profileData) {
 1268         write_icc_profile (&cinfo, (JOCTET*)profileData, profileLength);
 1269     }
 1270 
 1271     // write image data
 1272     int rowlen = width * 3;
 1273     unsigned char *row = new unsigned char [rowlen];
 1274 
 1275     /* To avoid memory leaks we establish a new setjmp return context for my_error_exit to use. */
 1276 #if defined( WIN32 ) && defined( __x86_64__ ) && !defined(__clang__)
 1277 
 1278     if (__builtin_setjmp(jerr.setjmp_buffer)) {
 1279 #else
 1280 
 1281     if (setjmp(jerr.setjmp_buffer)) {
 1282 #endif
 1283         /* If we get here, the JPEG code has signaled an error.
 1284            We need to clean up the JPEG object, close the file, remove the already saved part of the file and return.
 1285         */
 1286         delete [] row;
 1287         jpeg_destroy_compress(&cinfo);
 1288         fclose(file);
 1289         g_remove (fname.c_str());
 1290         return IMIO_CANNOTWRITEFILE;
 1291     }
 1292 
 1293     while (cinfo.next_scanline < cinfo.image_height) {
 1294 
 1295         getScanline (cinfo.next_scanline, row, 8);
 1296 
 1297         if (jpeg_write_scanlines (&cinfo, &row, 1) < 1) {
 1298             jpeg_destroy_compress (&cinfo);
 1299             delete [] row;
 1300             fclose (file);
 1301             g_remove (fname.c_str());
 1302             return IMIO_CANNOTWRITEFILE;
 1303         }
 1304 
 1305         if (pl && !(cinfo.next_scanline % 100)) {
 1306             pl->setProgress ((double)(cinfo.next_scanline) / cinfo.image_height);
 1307         }
 1308     }
 1309 
 1310     jpeg_finish_compress (&cinfo);
 1311     jpeg_destroy_compress (&cinfo);
 1312 
 1313     delete [] row;
 1314 
 1315     fclose (file);
 1316 
 1317     if (pl) {
 1318         pl->setProgressStr ("PROGRESSBAR_READY");
 1319         pl->setProgress (1.0);
 1320     }
 1321 
 1322     return IMIO_SUCCESS;
 1323 }
 1324 
 1325 int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool uncompressed) const
 1326 {
 1327     if (getWidth() < 1 || getHeight() < 1) {
 1328         return IMIO_HEADERERROR;
 1329     }
 1330 
 1331     bool writeOk = true;
 1332     int width = getWidth ();
 1333     int height = getHeight ();
 1334 
 1335     if (bps < 0) {
 1336         bps = getBPS ();
 1337     }
 1338 
 1339     int lineWidth = width * 3 * bps / 8;
 1340     unsigned char* linebuffer = new unsigned char[lineWidth];
 1341 
 1342     // little hack to get libTiff to use proper byte order (see TIFFClienOpen()):
 1343     const char *mode = !exifRoot ? "w" : (exifRoot->getOrder() == rtexif::INTEL ? "wl" : "wb");
 1344 #ifdef WIN32
 1345     FILE *file = g_fopen_withBinaryAndLock (fname);
 1346     int fileno = _fileno(file);
 1347     int osfileno = _get_osfhandle(fileno);
 1348     TIFF* out = TIFFFdOpen (osfileno, fname.c_str(), mode);
 1349 #else
 1350     TIFF* out = TIFFOpen(fname.c_str(), mode);
 1351     int fileno = TIFFFileno (out);
 1352 #endif
 1353 
 1354     if (!out) {
 1355         delete [] linebuffer;
 1356         return IMIO_CANNOTWRITEFILE;
 1357     }
 1358 
 1359     if (pl) {
 1360         pl->setProgressStr ("PROGRESSBAR_SAVETIFF");
 1361         pl->setProgress (0.0);
 1362     }
 1363 
 1364     bool applyExifPatch = false;
 1365 
 1366     if (exifRoot) {
 1367         rtexif::TagDirectory* cl = (const_cast<rtexif::TagDirectory*> (exifRoot))->clone (nullptr);
 1368 
 1369         // ------------------ remove some unknown top level tags which produce warnings when opening a tiff (might be useless) -----------------
 1370 
 1371         rtexif::Tag *removeTag = cl->getTag (0x9003);
 1372 
 1373         if (removeTag) {
 1374             removeTag->setKeep (false);
 1375         }
 1376 
 1377         removeTag = cl->getTag (0x9211);
 1378 
 1379         if (removeTag) {
 1380             removeTag->setKeep (false);
 1381         }
 1382 
 1383         // ------------------ Apply list of change -----------------
 1384 
 1385         for (auto currExifChange : *exifChange) {
 1386             cl->applyChange (currExifChange.first, currExifChange.second);
 1387         }
 1388 
 1389         rtexif::Tag *tag = cl->getTag (TIFFTAG_EXIFIFD);
 1390 
 1391         if (tag && tag->isDirectory()) {
 1392             rtexif::TagDirectory *exif = tag->getDirectory();
 1393 
 1394             if (exif)   {
 1395                 int exif_size = exif->calculateSize();
 1396                 unsigned char *buffer = new unsigned char[exif_size + 8];
 1397                 // TIFFOpen writes out the header and sets file pointer at position 8
 1398 
 1399                 exif->write (8, buffer);
 1400 
 1401                 write (fileno, buffer + 8, exif_size);
 1402 
 1403                 delete [] buffer;
 1404                 // let libtiff know that scanlines or any other following stuff should go
 1405                 // at a different offset:
 1406                 TIFFSetWriteOffset (out, exif_size + 8);
 1407                 TIFFSetField (out, TIFFTAG_EXIFIFD, 8);
 1408                 applyExifPatch = true;
 1409             }
 1410         }
 1411 
 1412         //TODO Even though we are saving EXIF IFD - MakerNote still comes out screwed.
 1413 
 1414         if ((tag = cl->getTag (TIFFTAG_MODEL)) != nullptr) {
 1415             TIFFSetField (out, TIFFTAG_MODEL, tag->getValue());
 1416         }
 1417 
 1418         if ((tag = cl->getTag (TIFFTAG_MAKE)) != nullptr) {
 1419             TIFFSetField (out, TIFFTAG_MAKE, tag->getValue());
 1420         }
 1421 
 1422         if ((tag = cl->getTag (TIFFTAG_DATETIME)) != nullptr) {
 1423             TIFFSetField (out, TIFFTAG_DATETIME, tag->getValue());
 1424         }
 1425 
 1426         if ((tag = cl->getTag (TIFFTAG_ARTIST)) != nullptr) {
 1427             TIFFSetField (out, TIFFTAG_ARTIST, tag->getValue());
 1428         }
 1429 
 1430         if ((tag = cl->getTag (TIFFTAG_COPYRIGHT)) != nullptr) {
 1431             TIFFSetField (out, TIFFTAG_COPYRIGHT, tag->getValue());
 1432         }
 1433 
 1434         delete cl;
 1435     }
 1436 
 1437     unsigned char* iptcdata = nullptr;
 1438     unsigned int iptclen = 0;
 1439 
 1440     if (iptc && iptc_data_save (iptc, &iptcdata, &iptclen)) {
 1441         if (iptcdata) {
 1442             iptc_data_free_buf (iptc, iptcdata);
 1443             iptcdata = nullptr;
 1444         }
 1445     }
 1446 
 1447 #if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
 1448         bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::MOTOROLA;
 1449 #else
 1450         bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::INTEL;
 1451 #endif
 1452     if (iptcdata) {
 1453         rtexif::Tag iptcTag(nullptr, rtexif::lookupAttrib (rtexif::ifdAttribs, "IPTCData"));
 1454         iptcTag.initLongArray((char*)iptcdata, iptclen);
 1455         if (needsReverse) {
 1456             unsigned char *ptr = iptcTag.getValue();
 1457             for (int a = 0; a < iptcTag.getCount(); ++a) {
 1458                 unsigned char cc;
 1459                 cc = ptr[3];
 1460                 ptr[3] = ptr[0];
 1461                 ptr[0] = cc;
 1462                 cc = ptr[2];
 1463                 ptr[2] = ptr[1];
 1464                 ptr[1] = cc;
 1465                 ptr += 4;
 1466             }
 1467         }
 1468         TIFFSetField (out, TIFFTAG_RICHTIFFIPTC, iptcTag.getCount(), (long*)iptcTag.getValue());
 1469         iptc_data_free_buf (iptc, iptcdata);
 1470     }
 1471 
 1472     TIFFSetField (out, TIFFTAG_SOFTWARE, "RawTherapee " RTVERSION);
 1473     TIFFSetField (out, TIFFTAG_IMAGEWIDTH, width);
 1474     TIFFSetField (out, TIFFTAG_IMAGELENGTH, height);
 1475     TIFFSetField (out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
 1476     TIFFSetField (out, TIFFTAG_SAMPLESPERPIXEL, 3);
 1477     TIFFSetField (out, TIFFTAG_ROWSPERSTRIP, height);
 1478     TIFFSetField (out, TIFFTAG_BITSPERSAMPLE, bps);
 1479     TIFFSetField (out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
 1480     TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
 1481     TIFFSetField (out, TIFFTAG_COMPRESSION, uncompressed ? COMPRESSION_NONE : COMPRESSION_ADOBE_DEFLATE);
 1482     TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, (bps == 16 || bps == 32) && isFloat ? SAMPLEFORMAT_IEEEFP : SAMPLEFORMAT_UINT);
 1483 
 1484     if (!uncompressed) {
 1485         TIFFSetField (out, TIFFTAG_PREDICTOR, (bps == 16 || bps == 32) && isFloat ? PREDICTOR_FLOATINGPOINT : PREDICTOR_HORIZONTAL);
 1486     }
 1487     if (profileData) {
 1488         TIFFSetField (out, TIFFTAG_ICCPROFILE, profileLength, profileData);
 1489     }
 1490 
 1491     for (int row = 0; row < height; row++) {
 1492         getScanline (row, linebuffer, bps, isFloat);
 1493 
 1494         if (bps == 16) {
 1495             if(needsReverse && !uncompressed && isFloat) {
 1496                 for(int i = 0; i < lineWidth; i += 2) {
 1497                     char temp = linebuffer[i];
 1498                     linebuffer[i] = linebuffer[i + 1];
 1499                     linebuffer[i + 1] = temp;
 1500                 }
 1501             }
 1502         } else if (bps == 32) {
 1503             if(needsReverse && !uncompressed) {
 1504                 for(int i = 0; i < lineWidth; i += 4) {
 1505                     char temp = linebuffer[i];
 1506                     linebuffer[i] = linebuffer[i + 3];
 1507                     linebuffer[i + 3] = temp;
 1508                     temp = linebuffer[i + 1];
 1509                     linebuffer[i + 1] = linebuffer[i + 2];
 1510                     linebuffer[i + 2] = temp;
 1511                 }
 1512             }
 1513         }
 1514 
 1515         if (TIFFWriteScanline (out, linebuffer, row, 0) < 0) {
 1516             TIFFClose (out);
 1517             delete [] linebuffer;
 1518             return IMIO_CANNOTWRITEFILE;
 1519         }
 1520 
 1521         if (pl && !(row % 100)) {
 1522             pl->setProgress ((double)(row + 1) / height);
 1523         }
 1524     }
 1525 
 1526     if (TIFFFlush(out) != 1) {
 1527         writeOk = false;
 1528     }
 1529 
 1530     /************************************************************************************************************
 1531      *
 1532      * Hombre: This is a dirty hack to update the Exif tag data type to 0x0004 so that Windows can understand it.
 1533      *         libtiff will set this data type to 0x000d and doesn't provide any mechanism to update it before
 1534      *         dumping to the file.
 1535      *
 1536      */
 1537     if (applyExifPatch) {
 1538         unsigned char b[10];
 1539         uint16 tagCount = 0;
 1540         lseek(fileno, 4, SEEK_SET);
 1541         read(fileno, b, 4);
 1542         uint32 ifd0Offset = rtexif::sget4(b, exifRoot->getOrder());
 1543         lseek(fileno, ifd0Offset, SEEK_SET);
 1544         read(fileno, b, 2);
 1545         tagCount = rtexif::sget2(b, exifRoot->getOrder());
 1546         for (size_t i = 0; i < tagCount ; ++i) {
 1547             uint16 tagID = 0;
 1548             read(fileno, b, 2);
 1549             tagID = rtexif::sget2(b, exifRoot->getOrder());
 1550             if (tagID == 0x8769) {
 1551                 rtexif::sset2(4, b, exifRoot->getOrder());
 1552                 write(fileno, b, 2);
 1553                 break;
 1554             } else {
 1555                 read(fileno, b, 10);
 1556             }
 1557         }
 1558     }
 1559     /************************************************************************************************************/
 1560 
 1561 
 1562     TIFFClose (out);
 1563 #ifdef WIN32
 1564     fclose (file);
 1565 #endif
 1566 
 1567     delete [] linebuffer;
 1568 
 1569     if (pl) {
 1570         pl->setProgressStr ("PROGRESSBAR_READY");
 1571         pl->setProgress (1.0);
 1572     }
 1573 
 1574     if(writeOk) {
 1575         return IMIO_SUCCESS;
 1576     } else {
 1577         g_remove (fname.c_str());
 1578         return IMIO_CANNOTWRITEFILE;
 1579     }
 1580 }
 1581 
 1582 // PNG read and write routines:
 1583 
 1584 void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
 1585 {
 1586     png_size_t check;
 1587 
 1588     /* fread() returns 0 on error, so it is OK to store this in a png_size_t
 1589      * instead of an int, which is what fread() actually returns.
 1590      */
 1591     check = (png_size_t)fread(data, (png_size_t)1, length, (FILE *)png_get_io_ptr(png_ptr));
 1592 
 1593     if (check != length) {
 1594         png_error(png_ptr, "Read Error");
 1595     }
 1596 }
 1597 
 1598 void png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
 1599 {
 1600     png_uint_32 check;
 1601 
 1602     check = fwrite(data, 1, length, (FILE *)png_get_io_ptr(png_ptr));
 1603 
 1604     if (check != length) {
 1605         png_error(png_ptr, "Write Error");
 1606     }
 1607 }
 1608 
 1609 void png_flush(png_structp png_ptr)
 1610 {
 1611     FILE *io_ptr;
 1612     io_ptr = (FILE *)(png_get_io_ptr(png_ptr));
 1613 
 1614     if (io_ptr != nullptr) {
 1615         fflush(io_ptr);
 1616     }
 1617 }
 1618 
 1619 int ImageIO::load (const Glib::ustring &fname)
 1620 {
 1621 
 1622     if (hasPngExtension(fname)) {
 1623         return loadPNG (fname);
 1624     } else if (hasJpegExtension(fname)) {
 1625         return loadJPEG (fname);
 1626     } else if (hasTiffExtension(fname)) {
 1627         return loadTIFF (fname);
 1628     } else {
 1629         return IMIO_FILETYPENOTSUPPORTED;
 1630     }
 1631 }
 1632 
 1633 int ImageIO::save (const Glib::ustring &fname) const
 1634 {
 1635     if (hasPngExtension(fname)) {
 1636         return savePNG (fname);
 1637     } else if (hasJpegExtension(fname)) {
 1638         return saveJPEG (fname);
 1639     } else if (hasTiffExtension(fname)) {
 1640         return saveTIFF (fname);
 1641     } else {
 1642         return IMIO_FILETYPENOTSUPPORTED;
 1643     }
 1644 }
 1645 
 1646 void ImageIO::setProgressListener (ProgressListener* l)
 1647 {
 1648     pl = l;
 1649 }
 1650 
 1651 void ImageIO::setSampleFormat(IIOSampleFormat sFormat)
 1652 {
 1653     sampleFormat = sFormat;
 1654 }
 1655 
 1656 IIOSampleFormat ImageIO::getSampleFormat() const
 1657 {
 1658     return sampleFormat;
 1659 }
 1660 
 1661 void ImageIO::setSampleArrangement(IIOSampleArrangement sArrangement)
 1662 {
 1663     sampleArrangement = sArrangement;
 1664 }
 1665 
 1666 IIOSampleArrangement ImageIO::getSampleArrangement() const
 1667 {
 1668     return sampleArrangement;
 1669 }
 1670 
 1671 cmsHPROFILE ImageIO::getEmbeddedProfile () const
 1672 {
 1673     return embProfile;
 1674 }
 1675 
 1676 void ImageIO::getEmbeddedProfileData (int& length, unsigned char*& pdata) const
 1677 {
 1678     length = loadedProfileLength;
 1679     pdata = (unsigned char*)loadedProfileData;
 1680 }
 1681 
 1682 MyMutex& ImageIO::mutex ()
 1683 {
 1684     return imutex;
 1685 }
 1686 
 1687 void ImageIO::deleteLoadedProfileData( )
 1688 {
 1689     if(loadedProfileData) {
 1690         if(loadedProfileDataJpg) {
 1691             free(loadedProfileData);
 1692         } else {
 1693             delete[] loadedProfileData;
 1694         }
 1695     }
 1696 
 1697     loadedProfileData = nullptr;
 1698 }