JPG sub sampling setting

see issue 1502
This commit is contained in:
Oliver Duis
2012-07-21 08:38:46 +02:00
parent a335c22d85
commit 98615e7f65
14 changed files with 74 additions and 14 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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; }

View File

@@ -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

View File

@@ -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; }

View File

@@ -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";

View 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>";

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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];