mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-24 19:02:53 +00:00
249 lines
5.7 KiB
C++
249 lines
5.7 KiB
C++
// vim: set tabstop=4 shiftwidth=4 expandtab:
|
|
/*
|
|
Gwenview: an image viewer
|
|
Copyright 2012 Aurélien Gâteau <agateau@kde.org>
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
|
|
|
|
*/
|
|
// Self
|
|
#include "cmsprofile.h"
|
|
|
|
// Local
|
|
#include <cms/cmsprofile_png.h>
|
|
#include <gvdebug.h>
|
|
#include <iodevicejpegsourcemanager.h>
|
|
#include <jpegerrormanager.h>
|
|
|
|
extern "C" {
|
|
#include <cms/iccjpeg.h>
|
|
}
|
|
|
|
// KDE
|
|
#include <KDebug>
|
|
|
|
// Qt
|
|
#include <QBuffer>
|
|
|
|
// lcms
|
|
#include <lcms2.h>
|
|
|
|
// X11
|
|
#ifdef Q_WS_X11
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xatom.h>
|
|
#include <fixx11h.h>
|
|
#include <QX11Info>
|
|
#endif
|
|
|
|
namespace Gwenview
|
|
{
|
|
|
|
#undef ENABLE_LOG
|
|
#undef LOG
|
|
//#define ENABLE_LOG
|
|
#ifdef ENABLE_LOG
|
|
#define LOG(x) kDebug() << x
|
|
#else
|
|
#define LOG(x) ;
|
|
#endif
|
|
|
|
namespace Cms
|
|
{
|
|
|
|
//- JPEG -----------------------------------------------------------------------
|
|
static cmsHPROFILE loadFromJpegData(const QByteArray& data)
|
|
{
|
|
cmsHPROFILE profile = 0;
|
|
struct jpeg_decompress_struct srcinfo;
|
|
|
|
JPEGErrorManager srcErrorManager;
|
|
srcinfo.err = &srcErrorManager;
|
|
jpeg_create_decompress(&srcinfo);
|
|
if (setjmp(srcErrorManager.jmp_buffer)) {
|
|
kError() << "libjpeg error in src\n";
|
|
return 0;
|
|
}
|
|
|
|
QBuffer buffer(const_cast<QByteArray*>(&data));
|
|
buffer.open(QIODevice::ReadOnly);
|
|
IODeviceJpegSourceManager::setup(&srcinfo, &buffer);
|
|
|
|
setup_read_icc_profile(&srcinfo);
|
|
jpeg_read_header(&srcinfo, true);
|
|
jpeg_start_decompress(&srcinfo);
|
|
|
|
uchar* profile_data;
|
|
uint profile_len;
|
|
if (read_icc_profile(&srcinfo, &profile_data, &profile_len)) {
|
|
LOG("Found a profile, length:" << profile_len);
|
|
profile = cmsOpenProfileFromMem(profile_data, profile_len);
|
|
}
|
|
|
|
jpeg_destroy_decompress(&srcinfo);
|
|
|
|
return profile;
|
|
}
|
|
|
|
//- Profile class --------------------------------------------------------------
|
|
struct ProfilePrivate
|
|
{
|
|
cmsHPROFILE mProfile;
|
|
|
|
void reset()
|
|
{
|
|
if (mProfile) {
|
|
cmsCloseProfile(mProfile);
|
|
}
|
|
mProfile = 0;
|
|
}
|
|
|
|
QString readInfo(cmsInfoType info)
|
|
{
|
|
GV_RETURN_VALUE_IF_FAIL(mProfile, QString());
|
|
wchar_t buffer[1024];
|
|
int size = cmsGetProfileInfo(mProfile, info, "en", "US", buffer, 1024);
|
|
return QString::fromWCharArray(buffer, size);
|
|
}
|
|
};
|
|
|
|
Profile::Profile()
|
|
: d(new ProfilePrivate)
|
|
{
|
|
d->mProfile = 0;
|
|
}
|
|
|
|
Profile::Profile(cmsHPROFILE hProfile)
|
|
: d(new ProfilePrivate)
|
|
{
|
|
d->mProfile = hProfile;
|
|
}
|
|
|
|
Profile::~Profile()
|
|
{
|
|
d->reset();
|
|
delete d;
|
|
}
|
|
|
|
Profile::Ptr Profile::loadFromImageData(const QByteArray& data, const QByteArray& format)
|
|
{
|
|
Profile::Ptr ptr;
|
|
cmsHPROFILE hProfile = 0;
|
|
if (format == "png") {
|
|
hProfile = loadFromPngData(data);
|
|
}
|
|
if (format == "jpeg") {
|
|
hProfile = loadFromJpegData(data);
|
|
}
|
|
if (hProfile) {
|
|
ptr = new Profile(hProfile);
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
Profile::Ptr Profile::loadFromExiv2Image(const Exiv2::Image* image)
|
|
{
|
|
Profile::Ptr ptr;
|
|
cmsHPROFILE hProfile = 0;
|
|
|
|
const Exiv2::ExifData& exifData = image->exifData();
|
|
Exiv2::ExifKey key("Exif.Image.InterColorProfile");
|
|
Exiv2::ExifData::const_iterator it = exifData.findKey(key);
|
|
if (it == exifData.end()) {
|
|
LOG("No profile found");
|
|
return ptr;
|
|
}
|
|
int size = it->size();
|
|
LOG("size:" << size);
|
|
|
|
QByteArray data;
|
|
data.resize(size);
|
|
it->copy(reinterpret_cast<Exiv2::byte*>(data.data()), Exiv2::invalidByteOrder);
|
|
hProfile = cmsOpenProfileFromMem(data, size);
|
|
|
|
if (hProfile) {
|
|
ptr = new Profile(hProfile);
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
cmsHPROFILE Profile::handle() const
|
|
{
|
|
return d->mProfile;
|
|
}
|
|
|
|
QString Profile::copyright() const
|
|
{
|
|
return d->readInfo(cmsInfoCopyright);
|
|
}
|
|
|
|
QString Profile::description() const
|
|
{
|
|
return d->readInfo(cmsInfoDescription);
|
|
}
|
|
|
|
QString Profile::manufacturer() const
|
|
{
|
|
return d->readInfo(cmsInfoManufacturer);
|
|
}
|
|
|
|
QString Profile::model() const
|
|
{
|
|
return d->readInfo(cmsInfoModel);
|
|
}
|
|
|
|
Profile::Ptr Profile::getMonitorProfile()
|
|
{
|
|
cmsHPROFILE hProfile = 0;
|
|
// Get the profile from you config file if the user has set it.
|
|
// if the user allows override through the atom, do this:
|
|
#ifdef Q_WS_X11
|
|
|
|
// get the current screen...
|
|
int screen = -1;
|
|
|
|
Atom type;
|
|
int format;
|
|
unsigned long nitems;
|
|
unsigned long bytes_after;
|
|
quint8 *str;
|
|
|
|
static Atom icc_atom = XInternAtom(QX11Info::display(), "_ICC_PROFILE", True);
|
|
|
|
if (XGetWindowProperty(QX11Info::display(),
|
|
QX11Info::appRootWindow(screen),
|
|
icc_atom,
|
|
0,
|
|
INT_MAX,
|
|
False,
|
|
XA_CARDINAL,
|
|
&type,
|
|
&format,
|
|
&nitems,
|
|
&bytes_after,
|
|
(unsigned char **) &str) == Success
|
|
) {
|
|
hProfile = cmsOpenProfileFromMem((void*)str, nitems);
|
|
}
|
|
#endif
|
|
if (!hProfile) {
|
|
hProfile = cmsCreate_sRGBProfile();
|
|
}
|
|
return Profile::Ptr(new Profile(hProfile));
|
|
}
|
|
|
|
} // namespace Cms
|
|
|
|
} // namespace Gwenview
|