JPG sub sampling setting
see issue 1502
This commit is contained in:
@@ -796,6 +796,11 @@ SAVEDLG_PUTTOQUEUETAIL;An das Ende der Warteschlange für Verarbeitung legen
|
||||
SAVEDLG_PUTTOQUEUE;In Warteschlange für Verarbeitung legen
|
||||
SAVEDLG_SAVEIMMEDIATELY;Sofort speichern
|
||||
SAVEDLG_SAVESPP;Prozessparameter mit dem Bild speichern
|
||||
SAVEDLG_SUBSAMP;Subsampling
|
||||
SAVEDLG_SUBSAMP_1;Beste Kompression
|
||||
SAVEDLG_SUBSAMP_2;Ausbalanciert
|
||||
SAVEDLG_SUBSAMP_3;Beste Qualität
|
||||
SAVEDLG_SUBSAMP_TOOLTIP;Beste Kompression: 4:1:1\nAusbalanciert: 4:2:2\nBeste Qualität: 4:4:4
|
||||
SAVEDLG_TIFFFILTER;TIFF-Datei
|
||||
SAVEDLG_TIFFUNCOMPRESSED;Uncompressed TIFF
|
||||
TOOLBAR_TOOLTIP_CROP;Ausschnitt wählen <b>C</b>\n\nZum Verschieben des Ausschnitts muss die Umschalttaste gedrückt gehalten werden
|
||||
|
@@ -807,6 +807,11 @@ SAVEDLG_PUTTOQUEUETAIL;Put to the end of the processing queue
|
||||
SAVEDLG_PUTTOQUEUE;Put into processing queue
|
||||
SAVEDLG_SAVEIMMEDIATELY;Save immediately
|
||||
SAVEDLG_SAVESPP;Save processing parameters with image
|
||||
SAVEDLG_SUBSAMP;Subsampling
|
||||
SAVEDLG_SUBSAMP_1;Best compression
|
||||
SAVEDLG_SUBSAMP_2;Balanced
|
||||
SAVEDLG_SUBSAMP_3;Best quality
|
||||
SAVEDLG_SUBSAMP_TOOLTIP;Best Compression: 4:1:1\nBalanced: 4:2:2\nBest quality: 4:4:4
|
||||
SAVEDLG_TIFFFILTER;TIFF files
|
||||
SAVEDLG_TIFFUNCOMPRESSED;Uncompressed TIFF
|
||||
SAVEDLG_WARNFILENAME;File will be named
|
||||
|
@@ -56,7 +56,7 @@ namespace rtengine {
|
||||
* @param fname is the name of the file
|
||||
* @param quality is the quality of the jpeg (0...100), set it to -1 to use default
|
||||
@return the error code, 0 if none */
|
||||
virtual int saveAsJPEG (Glib::ustring fname, int quality = 100)=0;
|
||||
virtual int saveAsJPEG (Glib::ustring fname, int quality = 100, int subSamp = 3 )=0;
|
||||
/** Saves the image to file in a tif format.
|
||||
* @param fname is the name of the file
|
||||
* @param bps can be 8 or 16 depending on the bits per pixels the output file will have
|
||||
|
@@ -80,7 +80,7 @@ class Image16 : public ImageIO, public IImage16 {
|
||||
virtual int getBitsPerPixel () { return 16; }
|
||||
virtual int saveToFile (Glib::ustring fname) { return save (fname); }
|
||||
virtual int saveAsPNG (Glib::ustring fname, int compression = -1, int bps = -1) { return savePNG (fname, compression, bps); }
|
||||
virtual int saveAsJPEG (Glib::ustring fname, int quality = 100) { return saveJPEG (fname, quality); }
|
||||
virtual int saveAsJPEG (Glib::ustring fname, int quality = 100, int subSamp = 3) { return saveJPEG (fname, quality, subSamp); }
|
||||
virtual int saveAsTIFF (Glib::ustring fname, int bps = -1, bool uncompressed = false) { return saveTIFF (fname, bps, uncompressed); }
|
||||
virtual void setSaveProgressListener (ProgressListener* pl) { return setProgressListener (pl); }
|
||||
virtual void free () { delete this; }
|
||||
|
@@ -60,7 +60,7 @@ class Image8 : public ImageIO, public IImage8 {
|
||||
virtual int getBitsPerPixel () { return 16; }
|
||||
virtual int saveToFile (Glib::ustring fname) { return save (fname); }
|
||||
virtual int saveAsPNG (Glib::ustring fname, int compression = -1, int bps = -1) { return savePNG (fname, compression, bps); }
|
||||
virtual int saveAsJPEG (Glib::ustring fname, int quality = 100) { return saveJPEG (fname, quality); }
|
||||
virtual int saveAsJPEG (Glib::ustring fname, int quality = 100, int subSamp = 3) { return saveJPEG (fname, quality, subSamp); }
|
||||
virtual int saveAsTIFF (Glib::ustring fname, int bps = -1, bool uncompressed = false) { return saveTIFF (fname, bps, uncompressed); }
|
||||
virtual void setSaveProgressListener (ProgressListener* pl) { setProgressListener (pl); }
|
||||
virtual void free () { delete this; }
|
||||
|
@@ -81,7 +81,7 @@ class Imagefloat : public ImageIO, public IImagefloat {
|
||||
virtual int getBitsPerPixel () { return 16; }
|
||||
virtual int saveToFile (Glib::ustring fname) { return save (fname); }
|
||||
virtual int saveAsPNG (Glib::ustring fname, int compression = -1, int bps = -1) { return savePNG (fname, compression, bps); }
|
||||
virtual int saveAsJPEG (Glib::ustring fname, int quality = 100) { return saveJPEG (fname, quality); }
|
||||
virtual int saveAsJPEG (Glib::ustring fname, int quality = 100, int subSamp = 3) { return saveJPEG (fname, quality, subSamp); }
|
||||
virtual int saveAsTIFF (Glib::ustring fname, int bps = -1, bool uncompressed = false) { return saveTIFF (fname, bps, uncompressed); }
|
||||
virtual void setSaveProgressListener (ProgressListener* pl) { return setProgressListener (pl); }
|
||||
virtual void free () { delete this; }
|
||||
|
@@ -610,7 +610,8 @@ int ImageIO::savePNG (Glib::ustring fname, int compression, volatile int bps) {
|
||||
}
|
||||
|
||||
|
||||
int ImageIO::saveJPEG (Glib::ustring fname, int quality) {
|
||||
// Quality 0..100, subsampling: 1=low quality, 2=medium, 3=high
|
||||
int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp) {
|
||||
|
||||
jpeg_compress_struct cinfo;
|
||||
jpeg_error_mgr jerr;
|
||||
@@ -650,6 +651,20 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality) {
|
||||
if (quality>=0 && quality<=100)
|
||||
jpeg_set_quality (&cinfo, quality, true);
|
||||
|
||||
cinfo.comp_info[1].h_samp_factor=cinfo.comp_info[1].v_samp_factor = 1;
|
||||
cinfo.comp_info[2].h_samp_factor=cinfo.comp_info[2].v_samp_factor = 1;
|
||||
|
||||
if (subSamp==1) {
|
||||
// Best compression, default of the JPEG library: 2x2, 1x1, 1x1 (4:1:1)
|
||||
cinfo.comp_info[0].h_samp_factor=cinfo.comp_info[0].v_samp_factor = 2;
|
||||
} else if (subSamp==2) {
|
||||
// Widely used normal ratio 2x1, 1x1, 1x1 (4:2:2)
|
||||
cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 1;
|
||||
} else if (subSamp==3) {
|
||||
// Best quality 1x1 1x1 1x1 (4:4:4)
|
||||
cinfo.comp_info[0].h_samp_factor=cinfo.comp_info[0].v_samp_factor = 1;
|
||||
}
|
||||
|
||||
jpeg_start_compress(&cinfo, TRUE);
|
||||
|
||||
// buffer for exif and iptc markers
|
||||
|
@@ -76,7 +76,7 @@ class ImageIO {
|
||||
int loadPPMFromMemory(const char* buffer,int width,int height, bool swap, int bps);
|
||||
|
||||
int savePNG (Glib::ustring fname, int compression = -1, volatile int bps = -1);
|
||||
int saveJPEG (Glib::ustring fname, int quality = 100);
|
||||
int saveJPEG (Glib::ustring fname, int quality = 100, int subSamp=3);
|
||||
int saveTIFF (Glib::ustring fname, int bps = -1, bool uncompressed = false);
|
||||
|
||||
cmsHPROFILE getEmbeddedProfile () { return embProfile; }
|
||||
|
@@ -391,7 +391,7 @@ rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImage16* img) {
|
||||
else if (saveFormat.format=="png")
|
||||
err = img->saveAsPNG (fname, saveFormat.pngCompression, saveFormat.pngBits);
|
||||
else if (saveFormat.format=="jpg")
|
||||
err = img->saveAsJPEG (fname, saveFormat.jpegQuality);
|
||||
err = img->saveAsJPEG (fname, saveFormat.jpegQuality, saveFormat.jpegSubSamp);
|
||||
img->free ();
|
||||
|
||||
if (err) throw "Unable to save output file";
|
||||
|
@@ -949,7 +949,7 @@ bool EditorPanel::idle_saveImage (ProgressConnector<rtengine::IImage16*> *pc, Gl
|
||||
ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsPNG), fname, sf.pngCompression, sf.pngBits),
|
||||
sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fname, sf));
|
||||
else if (sf.format=="jpg")
|
||||
ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsJPEG), fname, sf.jpegQuality),
|
||||
ld->startFunc (sigc::bind(sigc::mem_fun(img, &rtengine::IImage16::saveAsJPEG), fname, sf.jpegQuality, sf.jpegSubSamp),
|
||||
sigc::bind(sigc::mem_fun(*this,&EditorPanel::idle_imageSaved), ld, img, fname, sf));
|
||||
} else {
|
||||
Glib::ustring msg_ = Glib::ustring("<b>") + fname + ": Error during image processing\n</b>";
|
||||
|
@@ -196,7 +196,8 @@ void Options::setDefaults () {
|
||||
saveAsDialogHeight = 600;
|
||||
savesParamsAtExit = true;
|
||||
saveFormat.format = "jpg";
|
||||
saveFormat.jpegQuality = 100;
|
||||
saveFormat.jpegQuality = 90;
|
||||
saveFormat.jpegSubSamp = 2;
|
||||
saveFormat.pngCompression = 6;
|
||||
saveFormat.pngBits = 8;
|
||||
saveFormat.tiffBits = 8;
|
||||
@@ -204,7 +205,8 @@ void Options::setDefaults () {
|
||||
saveFormat.saveParams = true;
|
||||
|
||||
saveFormatBatch.format = "jpg";
|
||||
saveFormatBatch.jpegQuality = 100;
|
||||
saveFormatBatch.jpegQuality = 90;
|
||||
saveFormatBatch.jpegSubSamp = 2;
|
||||
saveFormatBatch.pngCompression = 6;
|
||||
saveFormatBatch.pngBits = 8;
|
||||
saveFormatBatch.tiffBits = 8;
|
||||
@@ -507,6 +509,7 @@ if (keyFile.has_group ("External Editor")) {
|
||||
if (keyFile.has_group ("Output")) {
|
||||
if (keyFile.has_key ("Output", "Format")) saveFormat.format = keyFile.get_string ("Output", "Format");
|
||||
if (keyFile.has_key ("Output", "JpegQuality")) saveFormat.jpegQuality = keyFile.get_integer ("Output", "JpegQuality");
|
||||
if (keyFile.has_key ("Output", "JpegSubSamp")) saveFormat.jpegSubSamp = keyFile.get_integer ("Output", "JpegSubSamp");
|
||||
if (keyFile.has_key ("Output", "PngCompression")) saveFormat.pngCompression = keyFile.get_integer ("Output", "PngCompression");
|
||||
if (keyFile.has_key ("Output", "PngBps")) saveFormat.pngBits = keyFile.get_integer ("Output", "PngBps");
|
||||
if (keyFile.has_key ("Output", "TiffBps")) saveFormat.tiffBits = keyFile.get_integer ("Output", "TiffBps");
|
||||
@@ -516,6 +519,7 @@ if (keyFile.has_group ("Output")) {
|
||||
|
||||
if (keyFile.has_key ("Output", "FormatBatch")) saveFormatBatch.format = keyFile.get_string ("Output", "FormatBatch");
|
||||
if (keyFile.has_key ("Output", "JpegQualityBatch")) saveFormatBatch.jpegQuality = keyFile.get_integer ("Output", "JpegQualityBatch");
|
||||
if (keyFile.has_key ("Output", "JpegSubSampBatch")) saveFormatBatch.jpegSubSamp = keyFile.get_integer ("Output", "JpegSubSampBatch");
|
||||
if (keyFile.has_key ("Output", "PngCompressionBatch")) saveFormatBatch.pngCompression = keyFile.get_integer ("Output", "PngCompressionBatch");
|
||||
if (keyFile.has_key ("Output", "PngBpsBatch")) saveFormatBatch.pngBits = keyFile.get_integer ("Output", "PngBpsBatch");
|
||||
if (keyFile.has_key ("Output", "TiffBpsBatch")) saveFormatBatch.tiffBits = keyFile.get_integer ("Output", "TiffBpsBatch");
|
||||
@@ -793,6 +797,7 @@ int Options::saveToFile (Glib::ustring fname) {
|
||||
|
||||
keyFile.set_string ("Output", "Format", saveFormat.format);
|
||||
keyFile.set_integer ("Output", "JpegQuality", saveFormat.jpegQuality);
|
||||
keyFile.set_integer ("Output", "JpegSubSamp", saveFormat.jpegSubSamp);
|
||||
keyFile.set_integer ("Output", "PngCompression", saveFormat.pngCompression);
|
||||
keyFile.set_integer ("Output", "PngBps", saveFormat.pngBits);
|
||||
keyFile.set_integer ("Output", "TiffBps", saveFormat.tiffBits);
|
||||
@@ -801,6 +806,7 @@ int Options::saveToFile (Glib::ustring fname) {
|
||||
|
||||
keyFile.set_string ("Output", "FormatBatch", saveFormatBatch.format);
|
||||
keyFile.set_integer ("Output", "JpegQualityBatch", saveFormatBatch.jpegQuality);
|
||||
keyFile.set_integer ("Output", "JpegSubSampBatch", saveFormatBatch.jpegSubSamp);
|
||||
keyFile.set_integer ("Output", "PngCompressionBatch", saveFormatBatch.pngCompression);
|
||||
keyFile.set_integer ("Output", "PngBpsBatch", saveFormatBatch.pngBits);
|
||||
keyFile.set_integer ("Output", "TiffBpsBatch", saveFormatBatch.tiffBits);
|
||||
|
@@ -41,6 +41,7 @@ class SaveFormat {
|
||||
int pngBits;
|
||||
int pngCompression;
|
||||
int jpegQuality;
|
||||
int jpegSubSamp; // 1=best compression, 3=best quality
|
||||
int tiffBits;
|
||||
bool tiffUncompressed;
|
||||
bool saveParams;
|
||||
|
@@ -25,6 +25,25 @@ SaveFormatPanel::SaveFormatPanel () : listener (NULL) {
|
||||
jpegqual = new Adjuster (M("SAVEDLG_JPEGQUAL"), 0, 100, 1, 100);
|
||||
jpegqual->setAdjusterListener (this);
|
||||
jpegqual->show ();
|
||||
|
||||
jpegSubSampBox = Gtk::manage (new Gtk::HBox ());
|
||||
|
||||
jpegSubSampHead=Gtk::manage (new Gtk::Label (M("SAVEDLG_SUBSAMP") + Glib::ustring(":")) );
|
||||
jpegSubSampHead->show ();
|
||||
jpegSubSampBox->pack_start (*jpegSubSampHead, Gtk::PACK_SHRINK, 4);
|
||||
|
||||
jpegSubSamp = Gtk::manage (new MyComboBoxText ());
|
||||
jpegSubSamp->append_text (M("SAVEDLG_SUBSAMP_1"));
|
||||
jpegSubSamp->append_text (M("SAVEDLG_SUBSAMP_2"));
|
||||
jpegSubSamp->append_text (M("SAVEDLG_SUBSAMP_3"));
|
||||
jpegSubSamp->set_tooltip_text (M("SAVEDLG_SUBSAMP_TOOLTIP"));
|
||||
jpegSubSamp->set_active (2);
|
||||
jpegSubSamp->signal_changed().connect( sigc::mem_fun(*this, &SaveFormatPanel::formatChanged) );
|
||||
jpegSubSamp->show ();
|
||||
|
||||
jpegSubSampBox->pack_end (*jpegSubSamp);
|
||||
jpegSubSampBox->show ();
|
||||
|
||||
pngcompr = new Adjuster (M("SAVEDLG_PNGCOMPR"), 0, 6, 1, 6);
|
||||
pngcompr->setAdjusterListener (this);
|
||||
pngcompr->show ();
|
||||
@@ -49,6 +68,7 @@ SaveFormatPanel::SaveFormatPanel () : listener (NULL) {
|
||||
|
||||
formatopts = Gtk::manage (new Gtk::VBox ());
|
||||
formatopts->pack_start (*jpegqual, Gtk::PACK_SHRINK, 4);
|
||||
formatopts->pack_start (*jpegSubSampBox, Gtk::PACK_SHRINK, 4);
|
||||
pack_start (*formatopts, Gtk::PACK_SHRINK, 4);
|
||||
|
||||
savespp = Gtk::manage (new Gtk::CheckButton (M("SAVEDLG_SAVESPP")));
|
||||
@@ -87,6 +107,8 @@ void SaveFormatPanel::init (SaveFormat &sf) {
|
||||
else if (sf.format=="tif" && sf.tiffBits==8)
|
||||
format->set_active (1);
|
||||
|
||||
jpegSubSamp->set_active (sf.jpegSubSamp-1);
|
||||
|
||||
pngcompr->setValue (sf.pngCompression);
|
||||
jpegqual->setValue (sf.jpegQuality);
|
||||
savespp->set_active (sf.saveParams);
|
||||
@@ -110,6 +132,7 @@ SaveFormat SaveFormatPanel::getFormat () {
|
||||
sf.tiffBits = 8;
|
||||
sf.pngCompression = (int) pngcompr->getValue ();
|
||||
sf.jpegQuality = (int) jpegqual->getValue ();
|
||||
sf.jpegSubSamp = jpegSubSamp->get_active_row_number()+1;
|
||||
sf.tiffUncompressed = tiffuncompressed->get_active();
|
||||
sf.saveParams = savespp->get_active ();
|
||||
return sf;
|
||||
@@ -117,9 +140,10 @@ SaveFormat SaveFormatPanel::getFormat () {
|
||||
|
||||
void SaveFormatPanel::formatChanged () {
|
||||
|
||||
if (oformat==0)
|
||||
if (oformat==0) {
|
||||
removeIfThere (formatopts, jpegqual);
|
||||
else if (oformat==3 || oformat==4)
|
||||
removeIfThere (formatopts, jpegSubSampBox);
|
||||
} else if (oformat==3 || oformat==4)
|
||||
removeIfThere (formatopts, pngcompr);
|
||||
else if (oformat==1 || oformat==2)
|
||||
removeIfThere (formatopts, tiffuncompressed);
|
||||
@@ -129,9 +153,10 @@ void SaveFormatPanel::formatChanged () {
|
||||
return;
|
||||
|
||||
Glib::ustring fr = fstr[act];
|
||||
if (fr=="jpg")
|
||||
if (fr=="jpg") {
|
||||
formatopts->pack_start (*jpegqual, Gtk::PACK_SHRINK,4);
|
||||
else if (fr=="png")
|
||||
formatopts->pack_start (*jpegSubSampBox, Gtk::PACK_SHRINK,4);
|
||||
} else if (fr=="png")
|
||||
formatopts->pack_start (*pngcompr, Gtk::PACK_SHRINK,4);
|
||||
else if (fr=="tif")
|
||||
formatopts->pack_start (*tiffuncompressed, Gtk::PACK_SHRINK,4);
|
||||
|
@@ -38,7 +38,10 @@ class SaveFormatPanel : public Gtk::VBox, public AdjusterListener {
|
||||
Adjuster* pngcompr;
|
||||
Gtk::CheckButton* tiffuncompressed;
|
||||
MyComboBoxText* format;
|
||||
MyComboBoxText* jpegSubSamp;
|
||||
Gtk::VBox* formatopts;
|
||||
Gtk::HBox* jpegSubSampBox;
|
||||
Gtk::Label* jpegSubSampHead;
|
||||
int oformat;
|
||||
FormatChangeListener* listener;
|
||||
Glib::ustring fstr[5];
|
||||
|
Reference in New Issue
Block a user