Summary: | libjpeg JPEG subsampling setting is not user-controlable | ||
---|---|---|---|
Product: | [Applications] digikam | Reporter: | Jean-Marc Liotier <jm> |
Component: | Plugin-DImg-JPEG | Assignee: | Digikam Developers <digikam-bugs-null> |
Status: | RESOLVED FIXED | ||
Severity: | wishlist | ||
Priority: | NOR | ||
Version: | 0.9.1 | ||
Target Milestone: | --- | ||
Platform: | Ubuntu | ||
OS: | Linux | ||
Latest Commit: | Version Fixed In: | 0.9.3 | |
Sentry Crash Report: |
Description
Jean-Marc Liotier
2007-09-05 21:01:38 UTC
Jean Marc, I have take a look into Gimp source code. following chroma subsampling options are available : 2x2 1x1 1x1 2x1 1x1 1x1 1x1 1x1 1x1 Following WikiPedia page : http://en.wikipedia.org/wiki/Chroma_subsampling Where are these options ??? This is another non homogenous stuff in Gimp... Also, "2x2 1x1 1x1" and others are not really easy to understand for common users. Something like "no subsampling" (best quality), "medium subsampling" (medium quality), and "high subsampling" (low quality) is more user friendly. I willpatch svn to provide 3 options from gimp, but using ratio subsampling value as option label. I'm waiting your tips to improve this point... Gilles Caulier Jean Marc, Note than from gimp source code, "1x1 1x1 1x1" is 4:2:2. Still: - "2x1 1x1 1x1" - "2x2 1x1 1x1" It's not really clear for me... Somebody understand the gimp logic (@^!...) ??? Gilles Maybe this helps a bit: http://www.ftgimp.com/help/C/filters/jpeg.html This one is interesting: http://www.mail-archive.com/gimp-user@lists.xcf.berkeley.edu/msg13130.html > Note than from gimp source code, "1x1 1x1 1x1" is 4:2:2. Still: In this text http://photo.net/bboard/q-and-a-fetch-msg?msg_id=009Heq Bill Tuthill writes: """GIMP allows users to select all three types of chroma subsampling: 1x1,1x1,1x1 (ImageMagick 1x1 AKA 4:4:4), 2x1,1x1,1x1 (AKA 4:2:2), and smallest 2x2,1x1,1x1 (ImageMagick 2x1 AKA 4:1:1).""" http://photo.net/learn/jpeg/ one also provides a lot of info... Jean Marc, The gimp doc is wrong !!! Look page 70 of http://docs.gimp.org/en.pdf We can read : // ----------------------------------------------------------- Subsampling Human eye is not sensitive in the same way all over color spectrum. Compression can use this to consider as identical slightly different colors. Three methods are available : • 2x2, 1x1, 1x1 : important compression; suits images with weak borders but tends to denature colors. • 1x1, 1x1, 1x1 : preserves borders and contrasting colors, but compression is less. • 1x1, 1x1, 1x1 (4:2:2) : between other both. // ----------------------------------------------------------- There are both "1x1, 1x1, 1x1" (:=((( After investiguations using wikipedia page, i will set in digiKam : "High chroma subsampling" ==> 2x2 1x1 1x1 "Medium chroma subsampling" ==> 2x1 1x1 1x1 (4:2:2) "Low chroma subsampling" ==> 1x1 1x1 1x1 I will set the "Low chroma subsampling as default value because we always want to preserve the _best_ image quality. If user want a lower quality, it must change it in settings. Gilles Caulier Gilles, note that this might cause confusion ;-) "Low chroma subsampling" --> high quality "High chroma subsampling" --> low quality It is not unlikely to always think wrong here ;-) Maybe what you suggested before "no subsampling (best quality)", "medium subsampling (medium quality)", and "high subsampling (low quality)" is better? Sorry for coming late... Indeed you spotted an error in the Gimp documentation. I'll try to notify a maintainer. A comment by Thom Sharp on the Photo.net article gives interesting clarification of the origins and uses of various subsampling settings. I think it summarizes it quite well : "Within the professional cinematography, video, and imaging industries, chroma subsampling is expressed using the Y:Cr:Cb notation. This notation was originally devised to convey the horizontal (not vertical) resolution ratios of the Cr (red) and Cb (blue) channels to the horizontal resolution of Y (luminance). 4:4:4, therefore, indicates the absence of horizontal subsampling (1:1), while the 4:2:2 and 4:1:1 formats indicate that the Cr and Cb channels each horizontally boast 50% (4:2:2), and 25% (4:1:1), of Y's horizontal resolution. While less common, a 4:2:1 format also exists, yielding 2:1 horizontal Cr resolution vs. Y, and 4:1 horizontal Cb resolution vs. Y. This exploits the lower sensitivity to blue than red definition in human vision. Unfortunately, the Y:Cr:Cb notation often causes confusion because it was "hacked" after its introduction to express vertical subsampling levels in addition to horizontal ones. For example, while 4:2:0 seems to suggest 2:1 Cr vs. Y horizontally and the total lack of Cb, it actually indicates that both Cr and Cb are present, and that each is subsampled 2:1 vs. Y horizontally *and* vertically. The reason this "makes sense" is because, in vertical subsampling, only one of the two chroma subchannels is sampled per horizontal line (co-siting). Therefore, scanline 1 contains only Cr at 50% of Y's horizontal resolution (4:2:0), while scanline 2 contains only Cb at 50% of Y's horizontal resolution (4:0:2), etc. Upon decoding, Cr and Cb are vertically interpolated to form a vertical average. But in encoded form, it's literally "4:2:0". The 4:1:0 format uses the same technique, whereby Cr and Cb are alternately present (2:1 averaged vertical chroma resolution), and each boasts 25% (4:1) of the horizontal resolution of Y. Summary: - 4:4:4 (PSP 1x1 1x1 1x1) - CrH 100% - CbH 100% - CrV 100% - CbV 100% - 4:2:2 (PSP 2x1 1x1 1x1) - CrH 50% - CbH 50% - CrV 100% - CbV 100% - 4:1:1 (PSP 4x1 1x1 1x1) - CrH 25% - CbH 25% - CrV 100% - CbV 100% - 4:2:0 (PSP 2x2 1x1 1x1) - CrH 50% - CbH 50% - CrV 50% - CbV 50% - 4:1:0 (PSP 4x2 1x1 1x1) - CrH 25% - CbH 25% - CrV 50% - CbV 50% Uses : - 4:4:4 - High-end imaging/cinematography processing, high quality JPEG (used by Photoshop's higher quality levels) - 4:2:2 - D-1, D-5, D-9 (a.k.a. Digital-S), Ampex DCT, Digital Betacam, Betacam SX, DVCPRO-50, studio/high profile MPEG-2, good quality JPEG - 4:2:0 - PAL DV, PAL DVCAM, main profile MPEG-2 (e.g. DVD, American SDTV and HDTV, SD and HD DVB), average quality JPEG (used by Photoshop's lower quality levels) - 4:1:1 - D-7, NTSC DV, NTSC DVCAM, DVCPRO, low quality JPEG - 4:1:0 - Some low-bandwidth video/image codecs (worse than VHS chroma) Canon cameras (and many other manufacturers) use 2:1 chroma subsampling when converting in-camera from RAW to JPEG, so the default setting should not be higher than 4:2:2 since a higher setting would merely increase file size with no gain of quality. Additionally, 4:2:2 is widely considered as a medium quality JPEG so that could be a good default. I second Gille's suggestion of three quality levels : "High chroma subsampling" ==> 2x2 1x1 1x1 "Medium chroma subsampling" ==> 2x1 1x1 1x1 (4:2:2) "Low chroma subsampling" ==> 1x1 1x1 1x1 But I would choose "Medium chroma subsampling" as the default since a lower subsampling is overkill for most digital photographers, including the immense majority of DSLR users and an even higher proportion of Digikam users. Gimp documentation bug submitted at http://bugzilla.gnome.org/show_bug.cgi?id=474564 SVN commit 709439 by cgilles: digiKam from KDE3 branch : provide settings to adjust JPEG subsampling factor when new JPEG file is created by editor. TODO: KDE4PORT CCBUGS: 149578 M +44 -6 libs/dimg/loaders/jpegloader.cpp M +37 -4 libs/dimg/loaders/jpegsettings.cpp M +3 -0 libs/dimg/loaders/jpegsettings.h M +2 -1 libs/widgets/common/filesaveoptionsbox.cpp M +10 -10 project/project.kdevelop M +5 -2 utilities/imageeditor/canvas/dimginterface.cpp M +4 -0 utilities/imageeditor/canvas/iofilesettingscontainer.h M +2 -0 utilities/imageeditor/editor/editorwindow.cpp M +2 -0 utilities/setup/setupiofiles.cpp --- branches/extragear/kde3/graphics/digikam/libs/dimg/loaders/jpegloader.cpp #709438:709439 @@ -503,19 +503,57 @@ QVariant qualityAttr = imageGetAttribute("quality"); int quality = qualityAttr.isValid() ? qualityAttr.toInt() : 90; - + if (quality < 0) quality = 90; if (quality > 100) quality = 100; - + + QVariant subSamplingAttr = imageGetAttribute("subsampling"); + int subsampling = subSamplingAttr.isValid() ? subSamplingAttr.toInt() : 1; // Medium + jpeg_set_defaults(&cinfo); - // B.K.O #130996: set horizontal and vertical Subsampling factor to 1 for a best - // quality of color picture compression. - cinfo.comp_info[0].h_samp_factor = 1; - cinfo.comp_info[0].v_samp_factor = 1; + // B.K.O #149578: set horizontal and vertical chroma subsampling factor to encoder. + // See this page for details: http://en.wikipedia.org/wiki/Chroma_subsampling + switch (subsampling) + { + case 1: // 2x1, 1x1, 1x1 (4:2:2) : Medium + { + DDebug() << "Using LibJPEG medium chroma-subsampling (4:2:2)" << endl; + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + break; + } + case 2: // 2x2, 1x1, 1x1 (4:1:1) : High + { + DDebug() << "Using LibJPEG high chroma-subsampling (4:1:1)" << endl; + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + break; + } + default: // 1x1 1x1 1x1 (4:4:4) : None + { + DDebug() << "Using LibJPEG none chroma-subsampling (4:4:4)" << endl; + cinfo.comp_info[0].h_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + break; + } + } + jpeg_set_quality(&cinfo, quality, true); jpeg_start_compress(&cinfo, true); --- branches/extragear/kde3/graphics/digikam/libs/dimg/loaders/jpegsettings.cpp #709438:709439 @@ -27,6 +27,7 @@ #include <qlabel.h> #include <qlayout.h> #include <qwhatsthis.h> +#include <qcombobox.h> // KDE includes. @@ -54,12 +55,16 @@ labelJPEGcompression = 0; JPEGcompression = 0; labelWarning = 0; + subSamplingCB = 0; } QGridLayout *JPEGGrid; QLabel *labelJPEGcompression; + QLabel *labelSubSampling; + QComboBox *subSamplingCB; + KActiveLabel *labelWarning; KIntNumInput *JPEGcompression; @@ -94,11 +99,30 @@ d->labelWarning->setLineWidth(1); d->labelWarning->setFrameShape(QFrame::Box); + d->labelSubSampling = new QLabel(i18n("Chroma subsampling:"), this); + + d->subSamplingCB = new QComboBox(false, this); + d->subSamplingCB->insertItem(i18n("None")); // 1x1, 1x1, 1x1 (4:4:4) + d->subSamplingCB->insertItem(i18n("Medium")); // 2x1, 1x1, 1x1 (4:2:2) + d->subSamplingCB->insertItem(i18n("High")); // 2x2, 1x1, 1x1 (4:1:1) + QWhatsThis::add(d->subSamplingCB, i18n("<p>The level of chroma subsampling for JPEG images:<p>" + "<b>None</b>: use 4:4:4 ratio. It does not have any chroma " + "subsampling at all. This preserves borders and contrasting " + "colors, but compression is less<p>" + "<b>Medium</b>: use 4:2:2 ratio. Medium compression; reduces " + "the bandwidth for the picture by one-third with little to " + "no visual difference<p>" + "<b>High</b>: use 4:1:1 ratio. Important compression; suits " + "images with weak borders but tends to denature colors<p>" + "<b>Note: JPEG use a lossy compression image algorithm.</b>")); + d->JPEGGrid->addMultiCellWidget(d->labelJPEGcompression, 0, 0, 0, 0); - d->JPEGGrid->addMultiCellWidget(d->JPEGcompression, 0, 0, 1, 1); - d->JPEGGrid->addMultiCellWidget(d->labelWarning, 0, 0, 2, 2); + d->JPEGGrid->addMultiCellWidget(d->JPEGcompression, 0, 0, 1, 1); + d->JPEGGrid->addMultiCellWidget(d->labelSubSampling, 1, 1, 0, 0); + d->JPEGGrid->addMultiCellWidget(d->subSamplingCB, 1, 1, 1, 1); + d->JPEGGrid->addMultiCellWidget(d->labelWarning, 0, 1, 2, 2); d->JPEGGrid->setColStretch(1, 10); - d->JPEGGrid->setRowStretch(1, 10); + d->JPEGGrid->setRowStretch(2, 10); } JPEGSettings::~JPEGSettings() @@ -116,5 +140,14 @@ return d->JPEGcompression->value(); } +void JPEGSettings::setSubSamplingValue(int val) +{ + d->subSamplingCB->setCurrentItem(val); +} + +int JPEGSettings::getSubSamplingValue() +{ + return d->subSamplingCB->currentItem(); +} + } // namespace Digikam - --- branches/extragear/kde3/graphics/digikam/libs/dimg/loaders/jpegsettings.h #709438:709439 @@ -49,6 +49,9 @@ void setCompressionValue(int val); int getCompressionValue(); + void setSubSamplingValue(int val); + int getSubSamplingValue(); + private: JPEGSettingsPriv* d; --- branches/extragear/kde3/graphics/digikam/libs/widgets/common/filesaveoptionsbox.cpp #709438:709439 @@ -159,6 +159,7 @@ KConfig* config = kapp->config(); config->setGroup("ImageViewer Settings"); config->writeEntry("JPEGCompression", d->JPEGOptions->getCompressionValue()); + config->writeEntry("JPEGSubSampling", d->JPEGOptions->getSubSamplingValue()); config->writeEntry("PNGCompression", d->PNGOptions->getCompressionValue()); config->writeEntry("TIFFCompression", d->TIFFOptions->getCompression()); config->writeEntry("JPEG2000Compression", d->JPEG2000Options->getCompressionValue()); @@ -171,6 +172,7 @@ KConfig* config = kapp->config(); config->setGroup("ImageViewer Settings"); d->JPEGOptions->setCompressionValue( config->readNumEntry("JPEGCompression", 75) ); + d->JPEGOptions->setCompressionValue( config->readNumEntry("JPEGSubSampling", 1) ); // Medium subsampling d->PNGOptions->setCompressionValue( config->readNumEntry("PNGCompression", 9) ); d->TIFFOptions->setCompression(config->readBoolEntry("TIFFCompression", false)); d->JPEG2000Options->setCompressionValue( config->readNumEntry("JPEG2000Compression", 75) ); @@ -178,4 +180,3 @@ } } // namespace Digikam - --- branches/extragear/kde3/graphics/digikam/project/project.kdevelop #709438:709439 @@ -12,10 +12,10 @@ </keywords> <projectdirectory>./</projectdirectory> <absoluteprojectpath>false</absoluteprojectpath> - <description/> + <description></description> <ignoreparts/> <projectname>digikam</projectname> - <defaultencoding/> + <defaultencoding></defaultencoding> </general> <kdevfileview> <groups> @@ -75,10 +75,10 @@ <general> <dbgshell>libtool</dbgshell> <programargs/> - <gdbpath/> - <configGdbScript/> - <runShellScript/> - <runGdbScript/> + <gdbpath></gdbpath> + <configGdbScript></configGdbScript> + <runShellScript></runShellScript> + <runGdbScript></runGdbScript> <breakonloadinglibs>true</breakonloadinglibs> <separatetty>false</separatetty> <floatingtoolbar>false</floatingtoolbar> @@ -113,12 +113,12 @@ <run> <directoryradio>build</directoryradio> <customdirectory>/</customdirectory> - <mainprogram>digikam/digikam/digikam</mainprogram> - <programargs/> + <mainprogram>/home/gilles/Documents/Devel/SVN/branches/graphics/digikam/digikam/digikam</mainprogram> + <programargs></programargs> <terminal>false</terminal> <autocompile>false</autocompile> <envvars/> - <globaldebugarguments/> + <globaldebugarguments></globaldebugarguments> <globalcwd>../digikam</globalcwd> <useglobalprogram>true</useglobalprogram> <autoinstall>false</autoinstall> @@ -192,7 +192,7 @@ <includePaths>.;</includePaths> </codecompletion> <creategettersetter> - <prefixGet/> + <prefixGet></prefixGet> <prefixSet>set</prefixSet> <prefixVariable>m_,_</prefixVariable> <parameterName>theValue</parameterName> --- branches/extragear/kde3/graphics/digikam/utilities/imageeditor/canvas/dimginterface.cpp #709438:709439 @@ -549,8 +549,11 @@ // JPEG file format. if ( mimeType.upper() == QString("JPG") || mimeType.upper() == QString("JPEG") || - mimeType.upper() == QString("JPE")) - d->image.setAttribute("quality", iofileSettings->JPEGCompression); + mimeType.upper() == QString("JPE")) + { + d->image.setAttribute("quality", iofileSettings->JPEGCompression); + d->image.setAttribute("subsampling", iofileSettings->JPEGSubSampling); + } // PNG file format. if ( mimeType.upper() == QString("PNG") ) --- branches/extragear/kde3/graphics/digikam/utilities/imageeditor/canvas/iofilesettingscontainer.h #709438:709439 @@ -43,6 +43,7 @@ IOFileSettingsContainer() { JPEGCompression = 75; + JPEGSubSampling = 1; // Medium subsampling PNGCompression = 9; TIFFCompression = false; JPEG2000Compression = 75; @@ -56,6 +57,9 @@ // JPEG quality value. int JPEGCompression; + // JPEG chroma subsampling value. + int JPEGSubSampling; + // PNG compression value. int PNGCompression; --- branches/extragear/kde3/graphics/digikam/utilities/imageeditor/editor/editorwindow.cpp #709438:709439 @@ -858,6 +858,8 @@ (float)config->readNumEntry("JPEGCompression", 75) + 26.0 - (75.0/100.0)); + m_IOFileSettings->JPEGSubSampling = config->readNumEntry("JPEGSubSampling", 1); // Medium subsampling + // PNG compression slider settings : 1 - 9 ==> libpng settings : 100 - 1. m_IOFileSettings->PNGCompression = (int)(((1.0-100.0)/8.0)* (float)config->readNumEntry("PNGCompression", 1) --- branches/extragear/kde3/graphics/digikam/utilities/setup/setupiofiles.cpp #709438:709439 @@ -114,6 +114,7 @@ KConfig* config = kapp->config(); config->setGroup("ImageViewer Settings"); config->writeEntry("JPEGCompression", d->JPEGOptions->getCompressionValue()); + config->writeEntry("JPEGSubSampling", d->JPEGOptions->getSubSamplingValue()); config->writeEntry("PNGCompression", d->PNGOptions->getCompressionValue()); config->writeEntry("TIFFCompression", d->TIFFOptions->getCompression()); config->writeEntry("JPEG2000Compression", d->JPEG2000Options->getCompressionValue()); @@ -126,6 +127,7 @@ KConfig* config = kapp->config(); config->setGroup("ImageViewer Settings"); d->JPEGOptions->setCompressionValue(config->readNumEntry("JPEGCompression", 75) ); + d->JPEGOptions->setCompressionValue( config->readNumEntry("JPEGSubSampling", 1) ); // Medium subsampling d->PNGOptions->setCompressionValue(config->readNumEntry("PNGCompression", 9) ); d->TIFFOptions->setCompression(config->readBoolEntry("TIFFCompression", false)); d->JPEG2000Options->setCompressionValue( config->readNumEntry("JPEG2000Compression", 75) ); The inverse relationship between the amount of chroma subsampling and the resulting quality level could be confusing to some users. Maybe we should try to find an alternative wording to the high/medium/low options. Thanks for the patch. And the "QWhatsThis" comments probably provide enough explanations to reduce the confusion of novice users - though this will have to be tested on real novice users... There is another interesting point in the http://photo.net/learn/jpeg/ article: "Trying to improve the appearance of a Jpeg image by re-compressing at a higher quality setting achieves very little (except an increase in file-size)." Therefore one should use the same quality setting on save with which the image was created. This is discussed further in the section "Jpegdump"; this tools allows to estimate the IJG quality settings for any given Jpeg. So shouldn't this be used as setting for saving? Best, Arnd Ad #c13: what about #c6 ? (I hate those mid-air collisions with own postings ;-) Good point Arnd. Indeed using the input image's own subsampling setting as a default for saving it would be quite sensible : from a user's point of view, the application would just do the right thing and that would be one less option for 95% of users to worry about. I guess that this is the kind of simplification that Digikam strives for. Now from a developper's point of view this is of course qui a bit more work... SVN commit 709455 by cgilles: digiKam from trunk (KDE4) : provide settings to adjust JPEG subsampling factor when new JPEG file is created by editor. BUG: 149578 M +42 -4 libs/dimg/loaders/jpegloader.cpp M +39 -4 libs/dimg/loaders/jpegsettings.cpp M +3 -0 libs/dimg/loaders/jpegsettings.h M +2 -1 libs/widgets/common/filesaveoptionsbox.cpp M +2 -0 project/project.kdevelop M +5 -2 utilities/imageeditor/canvas/dimginterface.cpp M +4 -0 utilities/imageeditor/canvas/iofilesettingscontainer.h M +2 -0 utilities/imageeditor/editor/editorwindow.cpp M +2 -0 utilities/setup/setupiofiles.cpp --- trunk/extragear/graphics/digikam/libs/dimg/loaders/jpegloader.cpp #709454:709455 @@ -532,13 +532,51 @@ if (quality > 100) quality = 100; + QVariant subSamplingAttr = imageGetAttribute("subsampling"); + int subsampling = subSamplingAttr.isValid() ? subSamplingAttr.toInt() : 1; // Medium + jpeg_set_defaults(&cinfo); - // B.K.O #130996: set horizontal and vertical Subsampling factor to 1 for a best - // quality of color picture compression. - cinfo.comp_info[0].h_samp_factor = 1; - cinfo.comp_info[0].v_samp_factor = 1; + // B.K.O #149578: set horizontal and vertical chroma subsampling factor to encoder. + // See this page for details: http://en.wikipedia.org/wiki/Chroma_subsampling + switch (subsampling) + { + case 1: // 2x1, 1x1, 1x1 (4:2:2) : Medium + { + DDebug() << "Using LibJPEG medium chroma-subsampling (4:2:2)" << endl; + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + break; + } + case 2: // 2x2, 1x1, 1x1 (4:1:1) : High + { + DDebug() << "Using LibJPEG high chroma-subsampling (4:1:1)" << endl; + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 2; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + break; + } + default: // 1x1 1x1 1x1 (4:4:4) : None + { + DDebug() << "Using LibJPEG none chroma-subsampling (4:4:4)" << endl; + cinfo.comp_info[0].h_samp_factor = 1; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + break; + } + } + jpeg_set_quality(&cinfo, quality, true); jpeg_start_compress(&cinfo, true); --- trunk/extragear/graphics/digikam/libs/dimg/loaders/jpegsettings.cpp #709454:709455 @@ -28,6 +28,7 @@ #include <QLayout> #include <QFrame> #include <QGridLayout> +#include <QComboBox> // KDE includes. @@ -54,14 +55,18 @@ labelJPEGcompression = 0; JPEGcompression = 0; labelWarning = 0; + labelSubSampling = 0; + subSamplingCB = 0; } QGridLayout *JPEGGrid; QLabel *labelJPEGcompression; - QLabel *labelWarning; + QLabel *labelSubSampling; + QComboBox *subSamplingCB; + KIntNumInput *JPEGcompression; }; @@ -96,11 +101,31 @@ d->labelWarning->setLineWidth(1); d->labelWarning->setFrameShape(QFrame::Box); + d->labelSubSampling = new QLabel(i18n("Chroma subsampling:"), this); + + d->subSamplingCB = new QComboBox(this); + d->subSamplingCB->insertItem(0, i18n("None")); // 1x1, 1x1, 1x1 (4:4:4) + d->subSamplingCB->insertItem(1, i18n("Medium")); // 2x1, 1x1, 1x1 (4:2:2) + d->subSamplingCB->insertItem(2, i18n("High")); // 2x2, 1x1, 1x1 (4:1:1) + d->subSamplingCB->setWhatsThis( i18n("<p>The level of chroma subsampling for JPEG images:<p>" + "<b>None</b>: use 4:4:4 ratio. It does not have any chroma " + "subsampling at all. This preserves borders and contrasting " + "colors, but compression is less<p>" + "<b>Medium</b>: use 4:2:2 ratio. Medium compression; reduces " + "the bandwidth for the picture by one-third with little to " + "no visual difference<p>" + "<b>High</b>: use 4:1:1 ratio. Important compression; suits " + "images with weak borders but tends to denature colors<p>" + "<b>Note: JPEG use a lossy compression image algorithm.</b>")); + + d->JPEGGrid->addWidget(d->labelJPEGcompression, 0, 0, 1, 1); - d->JPEGGrid->addWidget(d->JPEGcompression, 0, 1, 1, 1); - d->JPEGGrid->addWidget(d->labelWarning, 0, 2, 1, 1); + d->JPEGGrid->addWidget(d->JPEGcompression, 0, 1, 1, 1); + d->JPEGGrid->addWidget(d->labelSubSampling, 1, 0, 1, 1); + d->JPEGGrid->addWidget(d->subSamplingCB, 1, 1, 1, 1); + d->JPEGGrid->addWidget(d->labelWarning, 0, 2, 1, 1); d->JPEGGrid->setColumnStretch(1, 10); - d->JPEGGrid->setRowStretch(1, 10); + d->JPEGGrid->setRowStretch(2, 10); d->JPEGGrid->setAlignment(d->JPEGcompression, Qt::AlignCenter); d->JPEGGrid->setMargin(KDialog::spacingHint()); d->JPEGGrid->setSpacing(KDialog::spacingHint()); @@ -121,4 +146,14 @@ return d->JPEGcompression->value(); } +void JPEGSettings::setSubSamplingValue(int val) +{ + d->subSamplingCB->setCurrentIndex(val); +} + +int JPEGSettings::getSubSamplingValue() +{ + return d->subSamplingCB->currentIndex(); +} + } // namespace Digikam --- trunk/extragear/graphics/digikam/libs/dimg/loaders/jpegsettings.h #709454:709455 @@ -49,6 +49,9 @@ void setCompressionValue(int val); int getCompressionValue(); + void setSubSamplingValue(int val); + int getSubSamplingValue(); + private: JPEGSettingsPriv* d; --- trunk/extragear/graphics/digikam/libs/widgets/common/filesaveoptionsbox.cpp #709454:709455 @@ -164,6 +164,7 @@ KSharedConfig::Ptr config = KGlobal::config(); KConfigGroup group = config->group("ImageViewer Settings"); group.writeEntry("JPEGCompression", d->JPEGOptions->getCompressionValue()); + group.writeEntry("JPEGSubSampling", d->JPEGOptions->getSubSamplingValue()); group.writeEntry("PNGCompression", d->PNGOptions->getCompressionValue()); group.writeEntry("TIFFCompression", d->TIFFOptions->getCompression()); group.writeEntry("JPEG2000Compression", d->JPEG2000Options->getCompressionValue()); @@ -176,6 +177,7 @@ KSharedConfig::Ptr config = KGlobal::config(); KConfigGroup group = config->group("ImageViewer Settings"); d->JPEGOptions->setCompressionValue( group.readEntry("JPEGCompression", 75) ); + d->JPEGOptions->setCompressionValue( group.readEntry("JPEGSubSampling", 1) ); // Medium subsampling d->PNGOptions->setCompressionValue( group.readEntry("PNGCompression", 9) ); d->TIFFOptions->setCompression( group.readEntry("TIFFCompression", false) ); d->JPEG2000Options->setCompressionValue( group.readEntry("JPEG2000Compression", 75) ); @@ -183,4 +185,3 @@ } } // namespace Digikam - --- trunk/extragear/graphics/digikam/project/project.kdevelop #709454:709455 @@ -158,6 +158,8 @@ <projectname>project</projectname> <projectname>project</projectname> <projectname>project</projectname> + <projectname>project</projectname> + <projectname>project</projectname> </general> <kdevfileview> <groups> --- trunk/extragear/graphics/digikam/utilities/imageeditor/canvas/dimginterface.cpp #709454:709455 @@ -3,7 +3,7 @@ * This file is a part of digiKam project * http://www.digikam.org * - * Date : 2003-01-15 + * Date : 2003-01-15 * Description : DImg interface for image editor * * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu> @@ -552,7 +552,10 @@ // JPEG file format. if ( mimeType.toUpper() == QString("JPG") || mimeType.toUpper() == QString("JPEG") || mimeType.toUpper() == QString("JPE")) - d->image.setAttribute("quality", iofileSettings->JPEGCompression); + { + d->image.setAttribute("quality", iofileSettings->JPEGCompression); + d->image.setAttribute("subsampling", iofileSettings->JPEGSubSampling); + } // PNG file format. if ( mimeType.toUpper() == QString("PNG") ) --- trunk/extragear/graphics/digikam/utilities/imageeditor/canvas/iofilesettingscontainer.h #709454:709455 @@ -43,6 +43,7 @@ IOFileSettingsContainer() { JPEGCompression = 75; + JPEGSubSampling = 1; // Medium subsampling PNGCompression = 9; TIFFCompression = false; JPEG2000Compression = 75; @@ -56,6 +57,9 @@ // JPEG quality value. int JPEGCompression; + // JPEG chroma subsampling value. + int JPEGSubSampling; + // PNG compression value. int PNGCompression; --- trunk/extragear/graphics/digikam/utilities/imageeditor/editor/editorwindow.cpp #709454:709455 @@ -818,6 +818,8 @@ (float)group.readEntry("JPEGCompression", 75) + 26.0 - (75.0/100.0)); + m_IOFileSettings->JPEGSubSampling = group.readEntry("JPEGSubSampling", 1); // Medium subsampling + // PNG compression slider settings : 1 - 9 ==> libpng settings : 100 - 1. m_IOFileSettings->PNGCompression = (int)(((1.0-100.0)/8.0)* (float)group.readEntry("PNGCompression", 1) --- trunk/extragear/graphics/digikam/utilities/setup/setupiofiles.cpp #709454:709455 @@ -118,6 +118,7 @@ KSharedConfig::Ptr config = KGlobal::config(); KConfigGroup group = config->group(QString("ImageViewer Settings")); group.writeEntry("JPEGCompression", d->JPEGOptions->getCompressionValue()); + group.writeEntry("JPEGSubSampling", d->JPEGOptions->getSubSamplingValue()); group.writeEntry("PNGCompression", d->PNGOptions->getCompressionValue()); group.writeEntry("TIFFCompression", d->TIFFOptions->getCompression()); group.writeEntry("JPEG2000Compression", d->JPEG2000Options->getCompressionValue()); @@ -130,6 +131,7 @@ KSharedConfig::Ptr config = KGlobal::config(); KConfigGroup group = config->group(QString("ImageViewer Settings")); d->JPEGOptions->setCompressionValue(group.readEntry("JPEGCompression", 75) ); + d->JPEGOptions->setCompressionValue(group.readEntry("JPEGSubSampling", 1) ); // Medium subsampling d->PNGOptions->setCompressionValue(group.readEntry("PNGCompression", 9) ); d->TIFFOptions->setCompression(group.readEntry("TIFFCompression", false)); d->JPEG2000Options->setCompressionValue( group.readEntry("JPEG2000Compression", 75) ); Ad #c15 and #c17: just in case, it seems that the code downloadable at http://www.programmersheaven.com/download/17054/download.aspx could be used as basis for the detection of the jpeg compression level. SVN commit 709928 by cgilles: kipi-plugins RAW converter : set JPEG subsampling factor to Medium. CCBUGS: 149578 M +11 -4 rawdecodingiface.cpp --- branches/extragear/kde3/libs/kipi-plugins/rawconverter/rawdecodingiface.cpp #709927:709928 @@ -223,10 +223,17 @@ cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); - // B.K.O #130996: set horizontal and vertical Subsampling factor - // to 1 for a best quality of color picture compression. - cinfo.comp_info[0].h_samp_factor = 1; - cinfo.comp_info[0].v_samp_factor = 1; + + // B.K.O #149578: set encoder horizontal and vertical chroma subsampling + // factor to 2x1, 1x1, 1x1 (4:2:2) : Medium subsampling. + // See this page for details: http://en.wikipedia.org/wiki/Chroma_subsampling + cinfo.comp_info[0].h_samp_factor = 2; + cinfo.comp_info[0].v_samp_factor = 1; + cinfo.comp_info[1].h_samp_factor = 1; + cinfo.comp_info[1].v_samp_factor = 1; + cinfo.comp_info[2].h_samp_factor = 1; + cinfo.comp_info[2].v_samp_factor = 1; + jpeg_set_quality(&cinfo, 100, true); jpeg_start_compress(&cinfo, true); Jean marc, Do you know another important settings to adjust image quality with JPEG encoder which is missing in digiKam ? If yes, please open a new file in this room... Thanks in advance Gilles |