Support for saving TIFFs as BigTIFF (#6690)
This commit is contained in:
parent
23408bfcb3
commit
a07c38f405
@ -2061,6 +2061,7 @@ SAMPLEFORMAT_16;16-bit floating-point
|
||||
SAMPLEFORMAT_32;24-bit floating-point
|
||||
SAMPLEFORMAT_64;32-bit floating-point
|
||||
SAVEDLG_AUTOSUFFIX;Automatically add a suffix if the file already exists
|
||||
SAVEDLG_BIGTIFF;BigTIFF
|
||||
SAVEDLG_FILEFORMAT;File format
|
||||
SAVEDLG_FILEFORMAT_FLOAT; floating-point
|
||||
SAVEDLG_FORCEFORMATOPTS;Force saving options
|
||||
|
@ -1882,7 +1882,13 @@ public:
|
||||
* @param bps can be 8 or 16 depending on the bits per pixels the output file will have
|
||||
* @param isFloat is true for saving float images. Will be ignored by file format not supporting float data
|
||||
@return the error code, 0 if none */
|
||||
virtual int saveAsTIFF (const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const = 0;
|
||||
virtual int saveAsTIFF (
|
||||
const Glib::ustring &fname,
|
||||
int bps = -1,
|
||||
bool isFloat = false,
|
||||
bool uncompressed = false,
|
||||
bool big = false
|
||||
) const = 0;
|
||||
/** @brief Sets the progress listener if you want to follow the progress of the image saving operations (optional).
|
||||
* @param pl is the pointer to the class implementing the ProgressListener interface */
|
||||
virtual void setSaveProgressListener (ProgressListener* pl) = 0;
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
return saveJPEG(fname, quality, subSamp);
|
||||
}
|
||||
|
||||
int saveAsTIFF(const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const override
|
||||
int saveAsTIFF(const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false, bool big = false) const override
|
||||
{
|
||||
return saveTIFF(fname, bps, isFloat, uncompressed);
|
||||
}
|
||||
|
@ -79,9 +79,15 @@ public:
|
||||
return saveJPEG (fname, quality, subSamp);
|
||||
}
|
||||
|
||||
int saveAsTIFF (const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const override
|
||||
int saveAsTIFF (
|
||||
const Glib::ustring &fname,
|
||||
int bps = -1,
|
||||
bool isFloat = false,
|
||||
bool uncompressed = false,
|
||||
bool big = false
|
||||
) const override
|
||||
{
|
||||
return saveTIFF (fname, bps, isFloat, uncompressed);
|
||||
return saveTIFF (fname, bps, isFloat, uncompressed, big);
|
||||
}
|
||||
|
||||
void setSaveProgressListener (ProgressListener* pl) override
|
||||
|
@ -82,9 +82,15 @@ public:
|
||||
{
|
||||
return saveJPEG (fname, quality, subSamp);
|
||||
}
|
||||
int saveAsTIFF (const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const override
|
||||
int saveAsTIFF (
|
||||
const Glib::ustring &fname,
|
||||
int bps = -1,
|
||||
bool isFloat = false,
|
||||
bool uncompressed = false,
|
||||
bool big = false
|
||||
) const override
|
||||
{
|
||||
return saveTIFF (fname, bps, isFloat, uncompressed);
|
||||
return saveTIFF (fname, bps, isFloat, uncompressed, big);
|
||||
}
|
||||
void setSaveProgressListener (ProgressListener* pl) override
|
||||
{
|
||||
|
@ -17,21 +17,17 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RawTherapee. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <png.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <tiff.h>
|
||||
#include <tiffio.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <libiptcdata/iptc-jpeg.h>
|
||||
#include <memory>
|
||||
#include "rt_math.h"
|
||||
#include "procparams.h"
|
||||
#include "utils.h"
|
||||
#include "../rtgui/options.h"
|
||||
#include "../rtgui/version.h"
|
||||
#include "../rtexif/rtexif.h"
|
||||
#include <string>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <libiptcdata/iptc-jpeg.h>
|
||||
#include <png.h>
|
||||
#include <tiff.h>
|
||||
#include <tiffio.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winsock2.h>
|
||||
@ -39,12 +35,20 @@
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include "color.h"
|
||||
#include "iccjpeg.h"
|
||||
#include "imageio.h"
|
||||
#include "iptcpairs.h"
|
||||
#include "iccjpeg.h"
|
||||
#include "color.h"
|
||||
|
||||
#include "jpeg.h"
|
||||
#include "procparams.h"
|
||||
#include "rt_math.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "../rtgui/options.h"
|
||||
#include "../rtgui/version.h"
|
||||
|
||||
#include "../rtexif/rtexif.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace rtengine;
|
||||
@ -1328,7 +1332,13 @@ int ImageIO::saveJPEG (const Glib::ustring &fname, int quality, int subSamp) con
|
||||
return IMIO_SUCCESS;
|
||||
}
|
||||
|
||||
int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool uncompressed) const
|
||||
int ImageIO::saveTIFF (
|
||||
const Glib::ustring &fname,
|
||||
int bps,
|
||||
bool isFloat,
|
||||
bool uncompressed,
|
||||
bool big
|
||||
) const
|
||||
{
|
||||
if (getWidth() < 1 || getHeight() < 1) {
|
||||
return IMIO_HEADERERROR;
|
||||
@ -1345,15 +1355,28 @@ int ImageIO::saveTIFF (const Glib::ustring &fname, int bps, bool isFloat, bool u
|
||||
int lineWidth = width * 3 * bps / 8;
|
||||
unsigned char* linebuffer = new unsigned char[lineWidth];
|
||||
|
||||
std::string mode = "w";
|
||||
|
||||
// little hack to get libTiff to use proper byte order (see TIFFClienOpen()):
|
||||
const char *mode = !exifRoot ? "w" : (exifRoot->getOrder() == rtexif::INTEL ? "wl" : "wb");
|
||||
if (exifRoot) {
|
||||
if (exifRoot->getOrder() == rtexif::INTEL) {
|
||||
mode += 'l';
|
||||
} else {
|
||||
mode += 'b';
|
||||
}
|
||||
}
|
||||
|
||||
if (big) {
|
||||
mode += '8';
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
FILE *file = g_fopen_withBinaryAndLock (fname);
|
||||
int fileno = _fileno(file);
|
||||
int osfileno = _get_osfhandle(fileno);
|
||||
TIFF* out = TIFFFdOpen (osfileno, fname.c_str(), mode);
|
||||
TIFF* out = TIFFFdOpen (osfileno, fname.c_str(), mode.c_str());
|
||||
#else
|
||||
TIFF* out = TIFFOpen(fname.c_str(), mode);
|
||||
TIFF* out = TIFFOpen(fname.c_str(), mode.c_str());
|
||||
int fileno = TIFFFileno (out);
|
||||
#endif
|
||||
|
||||
|
@ -113,7 +113,13 @@ public:
|
||||
|
||||
int savePNG (const Glib::ustring &fname, int bps = -1) const;
|
||||
int saveJPEG (const Glib::ustring &fname, int quality = 100, int subSamp = 3) const;
|
||||
int saveTIFF (const Glib::ustring &fname, int bps = -1, bool isFloat = false, bool uncompressed = false) const;
|
||||
int saveTIFF (
|
||||
const Glib::ustring &fname,
|
||||
int bps = -1,
|
||||
bool isFloat = false,
|
||||
bool uncompressed = false,
|
||||
bool big = false
|
||||
) const;
|
||||
|
||||
cmsHPROFILE getEmbeddedProfile () const;
|
||||
void getEmbeddedProfileData (int& length, unsigned char*& pdata) const;
|
||||
|
@ -264,6 +264,7 @@ bool BatchQueue::saveBatchQueue ()
|
||||
<< saveFormat.tiffBits << '|' << (saveFormat.tiffFloat ? 1 : 0) << '|' << saveFormat.tiffUncompressed << '|'
|
||||
<< saveFormat.saveParams << '|' << entry->forceFormatOpts << '|'
|
||||
<< entry->fast_pipeline << '|'
|
||||
<< saveFormat.bigTiff << '|'
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
@ -331,6 +332,7 @@ bool BatchQueue::loadBatchQueue ()
|
||||
const auto saveParams = nextIntOr (options.saveFormat.saveParams);
|
||||
const auto forceFormatOpts = nextIntOr (options.forceFormatOpts);
|
||||
const auto fast = nextIntOr(false);
|
||||
const auto bigTiff = nextIntOr (options.saveFormat.bigTiff);
|
||||
|
||||
rtengine::procparams::ProcParams pparams;
|
||||
|
||||
@ -370,6 +372,7 @@ bool BatchQueue::loadBatchQueue ()
|
||||
saveFormat.tiffBits = tiffBits;
|
||||
saveFormat.tiffFloat = tiffFloat == 1;
|
||||
saveFormat.tiffUncompressed = tiffUncompressed != 0;
|
||||
saveFormat.bigTiff = bigTiff != 0;
|
||||
saveFormat.saveParams = saveParams != 0;
|
||||
entry->forceFormatOpts = forceFormatOpts != 0;
|
||||
} else {
|
||||
@ -693,7 +696,13 @@ rtengine::ProcessingJob* BatchQueue::imageReady(rtengine::IImagefloat* img)
|
||||
int err = 0;
|
||||
|
||||
if (saveFormat.format == "tif") {
|
||||
err = img->saveAsTIFF (fname, saveFormat.tiffBits, saveFormat.tiffFloat, saveFormat.tiffUncompressed);
|
||||
err = img->saveAsTIFF (
|
||||
fname,
|
||||
saveFormat.tiffBits,
|
||||
saveFormat.tiffFloat,
|
||||
saveFormat.tiffUncompressed,
|
||||
saveFormat.bigTiff
|
||||
);
|
||||
} else if (saveFormat.format == "png") {
|
||||
err = img->saveAsPNG (fname, saveFormat.pngBits);
|
||||
} else if (saveFormat.format == "jpg") {
|
||||
|
@ -201,6 +201,9 @@ std::tuple<Glib::ustring, bool> BatchQueueEntry::getToolTip (int x, int y) const
|
||||
if (saveFormat.tiffUncompressed) {
|
||||
tooltip += Glib::ustring::compose("\n%1", M("SAVEDLG_TIFFUNCOMPRESSED"));
|
||||
}
|
||||
if (saveFormat.bigTiff) {
|
||||
tooltip += Glib::ustring::compose("\n%1", M("SAVEDLG_BIGTIFF"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2013,7 +2013,7 @@ bool EditorPanel::idle_saveImage (ProgressConnector<rtengine::IImagefloat*> *pc,
|
||||
img->setSaveProgressListener (parent->getProgressListener());
|
||||
|
||||
if (sf.format == "tif")
|
||||
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fname, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed),
|
||||
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fname, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed, sf.bigTiff),
|
||||
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
|
||||
else if (sf.format == "png")
|
||||
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsPNG), fname, sf.pngBits),
|
||||
@ -2270,7 +2270,7 @@ bool EditorPanel::saveImmediately (const Glib::ustring &filename, const SaveForm
|
||||
if (gimpPlugin) {
|
||||
err = img->saveAsTIFF (filename, 32, true, true);
|
||||
} else if (sf.format == "tif") {
|
||||
err = img->saveAsTIFF (filename, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed);
|
||||
err = img->saveAsTIFF (filename, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed, sf.bigTiff);
|
||||
} else if (sf.format == "png") {
|
||||
err = img->saveAsPNG (filename, sf.pngBits);
|
||||
} else if (sf.format == "jpg") {
|
||||
@ -2380,7 +2380,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector<rtengine::IImagefloat*> *p
|
||||
|
||||
ProgressConnector<int> *ld = new ProgressConnector<int>();
|
||||
img->setSaveProgressListener (parent->getProgressListener());
|
||||
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fileName, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed),
|
||||
ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fileName, sf.tiffBits, sf.tiffFloat, sf.tiffUncompressed, sf.bigTiff),
|
||||
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_sentToGimp), ld, img, fileName));
|
||||
} else {
|
||||
Glib::ustring msg_ = Glib::ustring ("<b> Error during image processing\n</b>");
|
||||
|
@ -313,6 +313,7 @@ void Options::setDefaults()
|
||||
saveFormat.tiffBits = 16;
|
||||
saveFormat.tiffFloat = false;
|
||||
saveFormat.tiffUncompressed = true;
|
||||
saveFormat.bigTiff = false;
|
||||
saveFormat.saveParams = true;
|
||||
|
||||
saveFormatBatch.format = "jpg";
|
||||
@ -1046,6 +1047,10 @@ void Options::readFromFile(Glib::ustring fname)
|
||||
saveFormat.tiffUncompressed = keyFile.get_boolean("Output", "TiffUncompressed");
|
||||
}
|
||||
|
||||
if (keyFile.has_key("Output", "BigTiff")) {
|
||||
saveFormat.bigTiff = keyFile.get_boolean("Output", "BigTiff");
|
||||
}
|
||||
|
||||
if (keyFile.has_key("Output", "SaveProcParams")) {
|
||||
saveFormat.saveParams = keyFile.get_boolean("Output", "SaveProcParams");
|
||||
}
|
||||
@ -2447,6 +2452,7 @@ void Options::saveToFile(Glib::ustring fname)
|
||||
keyFile.set_integer("Output", "TiffBps", saveFormat.tiffBits);
|
||||
keyFile.set_boolean("Output", "TiffFloat", saveFormat.tiffFloat);
|
||||
keyFile.set_boolean("Output", "TiffUncompressed", saveFormat.tiffUncompressed);
|
||||
keyFile.set_boolean("Output", "BigTiff", saveFormat.bigTiff);
|
||||
keyFile.set_boolean("Output", "SaveProcParams", saveFormat.saveParams);
|
||||
|
||||
keyFile.set_string("Output", "FormatBatch", saveFormatBatch.format);
|
||||
|
@ -72,6 +72,7 @@ struct SaveFormat {
|
||||
int _tiff_bits,
|
||||
bool _tiff_float,
|
||||
bool _tiff_uncompressed,
|
||||
bool _big_tiff,
|
||||
bool _save_params
|
||||
) :
|
||||
format(_format),
|
||||
@ -81,6 +82,7 @@ struct SaveFormat {
|
||||
tiffBits(_tiff_bits),
|
||||
tiffFloat(_tiff_float),
|
||||
tiffUncompressed(_tiff_uncompressed),
|
||||
bigTiff(_big_tiff),
|
||||
saveParams(_save_params)
|
||||
{
|
||||
}
|
||||
@ -98,6 +100,7 @@ struct SaveFormat {
|
||||
_tiff_bits,
|
||||
_tiff_float,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
)
|
||||
{
|
||||
@ -114,6 +117,7 @@ struct SaveFormat {
|
||||
int tiffBits;
|
||||
bool tiffFloat;
|
||||
bool tiffUncompressed;
|
||||
bool bigTiff;
|
||||
bool saveParams;
|
||||
};
|
||||
|
||||
|
@ -100,6 +100,11 @@ SaveFormatPanel::SaveFormatPanel () : listener (nullptr)
|
||||
tiffUncompressed->signal_toggled().connect( sigc::mem_fun(*this, &SaveFormatPanel::formatChanged));
|
||||
tiffUncompressed->show_all();
|
||||
|
||||
bigTiff = new Gtk::CheckButton (M("SAVEDLG_BIGTIFF"));
|
||||
setExpandAlignProperties(bigTiff, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
|
||||
bigTiff->signal_toggled().connect( sigc::mem_fun(*this, &SaveFormatPanel::formatChanged));
|
||||
bigTiff->show_all();
|
||||
|
||||
|
||||
// --------------------- MAIN BOX
|
||||
|
||||
@ -114,12 +119,14 @@ SaveFormatPanel::SaveFormatPanel () : listener (nullptr)
|
||||
attach (*hb1, 0, 0, 1, 1);
|
||||
attach (*jpegOpts, 0, 1, 1, 1);
|
||||
attach (*tiffUncompressed, 0, 2, 1, 1);
|
||||
attach (*bigTiff, 0, 3, 1, 1);
|
||||
attach (*savesPP, 0, 4, 1, 2);
|
||||
}
|
||||
SaveFormatPanel::~SaveFormatPanel ()
|
||||
{
|
||||
delete jpegQual;
|
||||
delete tiffUncompressed;
|
||||
delete bigTiff;
|
||||
}
|
||||
|
||||
void SaveFormatPanel::init (SaveFormat &sf)
|
||||
@ -158,6 +165,7 @@ void SaveFormatPanel::init (SaveFormat &sf)
|
||||
jpegQual->setValue(sf.jpegQuality);
|
||||
savesPP->set_active(sf.saveParams);
|
||||
tiffUncompressed->set_active(sf.tiffUncompressed);
|
||||
bigTiff->set_active(sf.bigTiff);
|
||||
|
||||
listener = tmp;
|
||||
}
|
||||
@ -175,6 +183,7 @@ SaveFormat SaveFormatPanel::getFormat ()
|
||||
sf.jpegQuality = jpegQual->getValue();
|
||||
sf.jpegSubSamp = jpegSubSamp->get_active_row_number() + 1;
|
||||
sf.tiffUncompressed = tiffUncompressed->get_active();
|
||||
sf.bigTiff = bigTiff->get_active();
|
||||
sf.saveParams = savesPP->get_active();
|
||||
|
||||
return sf;
|
||||
@ -193,12 +202,15 @@ void SaveFormatPanel::formatChanged ()
|
||||
if (fr == "jpg") {
|
||||
jpegOpts->show_all();
|
||||
tiffUncompressed->hide();
|
||||
bigTiff->hide();
|
||||
} else if (fr == "png") {
|
||||
jpegOpts->hide();
|
||||
tiffUncompressed->hide();
|
||||
bigTiff->hide();
|
||||
} else if (fr == "tif") {
|
||||
jpegOpts->hide();
|
||||
tiffUncompressed->show_all();
|
||||
bigTiff->show_all();
|
||||
}
|
||||
|
||||
if (listener) {
|
||||
|
@ -39,6 +39,7 @@ class SaveFormatPanel : public Gtk::Grid, public AdjusterListener, public rtengi
|
||||
protected:
|
||||
Adjuster* jpegQual;
|
||||
Gtk::CheckButton* tiffUncompressed;
|
||||
Gtk::CheckButton* bigTiff;
|
||||
MyComboBoxText* format;
|
||||
MyComboBoxText* jpegSubSamp;
|
||||
Gtk::Grid* formatOpts;
|
||||
|
Loading…
x
Reference in New Issue
Block a user