Commit d7be2d56 authored by Casper Boemann's avatar Casper Boemann

Cut and paste is now colorspace independent.

We now preserve colorspace during internal cut and 
paste. And we give the user some options on paste
from external applications.

The settings-colormanagement has been reworked to 
reflect the changes.

svn path=/trunk/koffice/; revision=489378
parent 912f363d
......@@ -717,7 +717,7 @@ KisUndoAdapter *KisPaintDeviceImpl::undoAdapter() const
return 0;
}
void KisPaintDeviceImpl::convertFromQImage(const QImage& image,
void KisPaintDeviceImpl::convertFromQImage(const QImage& image, const QString &srcProfileName,
Q_INT32 offsetX, Q_INT32 offsetY)
{
QImage img = image;
......@@ -738,7 +738,8 @@ void KisPaintDeviceImpl::convertFromQImage(const QImage& image,
else {
#endif
Q_UINT8 * dstData = new Q_UINT8[img.width() * img.height() * pixelSize()];
KisMetaRegistry::instance()->csRegistry() ->getColorSpace(KisID("RGBA",""),"")->convertPixelsTo(img.bits(), dstData, colorSpace(), img.width() * img.height());
KisMetaRegistry::instance()->csRegistry() ->getColorSpace(KisID("RGBA",""),srcProfileName) ->
convertPixelsTo(img.bits(), dstData, colorSpace(), img.width() * img.height());
writeBytes(dstData, offsetX, offsetY, img.width(), img.height());
// }
}
......
......@@ -185,8 +185,9 @@ public:
/**
* Fill this paint device with the data from img; starting at (offsetX, offsetY)
* @param srcProfileName name of the RGB profile to interpret the img as. "" is interpreted as sRGB
*/
virtual void convertFromQImage(const QImage& img, Q_INT32 offsetX = 0, Q_INT32 offsetY = 0);
virtual void convertFromQImage(const QImage& img, const QString &srcProfileName, Q_INT32 offsetX = 0, Q_INT32 offsetY = 0);
/**
* Create an RGBA QImage from a rectangle in the paint device.
......
......@@ -215,7 +215,7 @@ KisLayerSP KisPattern::image(KisColorSpace * colorSpace) {
Q_CHECK_PTR(layer);
layer->convertFromQImage(m_img);
layer->convertFromQImage(m_img,"");
m_colorspaces[colorSpace->id().id()] = layer;
return layer;
......
......@@ -177,8 +177,26 @@ KisColorSpace * KisColorSpaceFactoryRegistry::getColorSpace(const KisID & csID,
KisColorSpace * KisColorSpaceFactoryRegistry::getColorSpace(const KisID & csID, const KisProfile * profile)
{
if( profile ) {
return getColorSpace( csID, profile->productName());
if( profile )
{
KisColorSpace *cs = getColorSpace( csID, profile->productName());
if(!cs)
{
// The profile was not stored and thus not the combination either
KisColorSpaceFactory *csf = get(csID);
if(!csf)
return 0;
KisColorSpace *cs = csf -> createColorSpace(this, const_cast<KisProfile *>(profile));
if(!cs )
return 0;
QString name = csID.id() + "<comb>" + profile->productName();
m_csMap[name] = cs;
}
return cs;
} else {
return getColorSpace( csID, "");
}
......
......@@ -51,7 +51,7 @@ inline uint UINT8_BLEND(uint a, uint b, uint alpha)
// Signed arithmetic is needed since a-b might be negative
int c = ((int(a) - int(b)) * int(alpha)) >> 8;
return uint(c) + b;
return uint(c + b);
}
inline uint UINT16_MULT(uint a, uint b)
......@@ -77,7 +77,7 @@ inline uint UINT16_BLEND(uint a, uint b, uint alpha)
// However refactored to (a-b)*alpha + b since that saves a multiplication
// Signed arithmetic is needed since a-b might be negative
int c = ((int(a) - int(b)) * int(alpha)) >> 16;
return uint(c) + b;
return uint(c + b);
}
inline uint UINT8_TO_UINT16(uint c)
......
......@@ -78,10 +78,11 @@ public:
* Fill this paint device with the data from img; starting at (offsetX, offsetY)
*
* @param img The QImage to convert from. We will use the RGBA colorspace and no profile.
* @param srcProfileName name of the RGB profile to interpret the img as. "" is interpreted as sRGB
* @param offsetX the offset in X coordinates
* @param offsetY the offset in Y coordinates
*/
virtual void convertFromQImage(const QImage& img, Q_INT32 offsetX = 0, Q_INT32 offsetY = 0) = 0;
virtual void convertFromQImage(const QImage& img, const QString &srcProfileName, Q_INT32 offsetX = 0, Q_INT32 offsetY = 0) = 0;
/**
* Return the number of bytes a pixel takes.
......
......@@ -19,9 +19,16 @@
#include <qclipboard.h>
#include <qobject.h>
#include <qimage.h>
#include <qmessagebox.h>
#include <qbuffer.h>
#include <kmultipledrag.h>
#include <klocale.h>
#include "kdebug.h"
#include "KoStore.h"
#include "KoStoreDrag.h"
#include "kis_types.h"
#include "kis_paint_device_impl.h"
#include "kis_config.h"
......@@ -38,12 +45,15 @@ KisClipboard::KisClipboard()
KisClipboard::m_singleton = this;
m_pushedClipboard = false;
m_hasClip = false;
m_clip = 0;
// Check that we don't already have a clip ready
clipboardDataChanged();
// Make sure we are notified when clipboard changes
connect( QApplication::clipboard(), SIGNAL( dataChanged() ),
this, SLOT( clipboardDataChanged() ) );
}
KisClipboard::~KisClipboard()
......@@ -64,47 +74,153 @@ void KisClipboard::setClip(KisPaintDeviceImplSP selection)
{
m_clip = selection;
if (selection) {
KisConfig cfg;
QImage qimg;
if (cfg.applyMonitorProfileOnCopy()) {
// XXX: Is this a performance problem?
KisConfig cfg;
QString monitorProfileName = cfg.monitorProfile();
KisProfile * monitorProfile = KisMetaRegistry::instance()->csRegistry() -> getProfileByName(monitorProfileName);
qimg = selection -> convertToQImage(monitorProfile);
}
else {
qimg = selection -> convertToQImage(0);
if (!selection)
return;
m_hasClip = true;
// We'll create a store (ZIP format) in memory
QBuffer buffer;
QCString mimeType("application/x-krita-selection");
KoStore* store = KoStore::createStore( &buffer, KoStore::Write, mimeType );
Q_ASSERT( store );
Q_ASSERT( !store->bad() );
// Layer data
if (store -> open("layerdata")) {
if (!selection -> write(store)) {
selection -> disconnect();
store -> close();
return;
}
QClipboard *cb = QApplication::clipboard();
store -> close();
}
cb -> setImage(qimg);
m_pushedClipboard = true;
// ColorSpace id of layer data
if (store -> open("colorspace")) {
QString csName = selection -> colorSpace()->id().id();
store->write(csName.ascii(), strlen(csName.ascii()));
store -> close();
}
if (selection -> colorSpace() -> getProfile()) {
KisAnnotationSP annotation = selection -> colorSpace() -> getProfile() -> annotation();
if (annotation) {
// save layer profile
if (store -> open("profile.icc")) {
store -> write(annotation -> annotation());
store -> close();
}
}
}
delete store;
// We also create a QImage so we can interchange with other applications
QImage qimg;
KisConfig cfg;
QString monitorProfileName = cfg.monitorProfile();
KisProfile * monitorProfile = KisMetaRegistry::instance()->csRegistry() -> getProfileByName(monitorProfileName);
qimg = selection -> convertToQImage(monitorProfile);
QImageDrag *qimgDrag = new QImageDrag(qimg);
KMultipleDrag *multiDrag = new KMultipleDrag();
if ( !qimg.isNull() )
multiDrag->addDragObject( qimgDrag );
KoStoreDrag* storeDrag = new KoStoreDrag( mimeType, 0 );
storeDrag->setEncodedData( buffer.buffer() );
multiDrag->addDragObject( storeDrag );
QClipboard *cb = QApplication::clipboard();
cb -> setData(multiDrag);
m_pushedClipboard = true;
}
KisPaintDeviceImplSP KisClipboard::clip()
{
QClipboard *cb = QApplication::clipboard();
QCString mimeType("application/x-krita-selection");
QMimeSource *cbData = cb->data();
if(cbData && cbData->provides(mimeType))
{
QBuffer buffer(cbData->encodedData(mimeType));
KoStore* store = KoStore::createStore( &buffer, KoStore::Read, mimeType );
KisProfile *profile=0;
if (store -> hasFile("profile.icc")) {
QByteArray data;
store -> open("profile.icc");
data = store -> read(store -> size());
store -> close();
profile = new KisProfile(data);
}
QString csName;
// ColorSpace id of layer data
if (store -> hasFile("colorspace")) {
store -> open("colorspace");
csName = QString(store->read(store -> size()));
store -> close();
}
KisColorSpace *cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName, ""), profile);
m_clip = new KisPaintDeviceImpl(cs, "KisClipboard created clipboard selection");
if (store -> hasFile("layerdata")) {
store -> open("layerdata");
m_clip->read(store);
store -> close();
}
delete store;
}
else
{
QImage qimg = cb -> image();
if (qimg.isNull())
return 0;
KisConfig cfg;
Q_UINT32 behaviour = cfg.pasteBehaviour();
if(behaviour==2)
{
// Ask user each time
behaviour = QMessageBox::question(0,i18n("Pasting data from simple source"),i18n("The image data you are trying to paste has no color profile information.\n\nOn the web and in simple applications data is supposed to be sRGB.\nImporting as web will show it as it is supposed to look.\nMost monitors are not perfect though so if you made the image yourself\nyou might want to import it as it looked on you monitor.\n\nHow do you want to interpret the data?"),"As &Web","As on &monitor");
}
KisColorSpace * cs;
QString profileName("");
if(behaviour==1)
profileName = cfg.monitorProfile();
cs = KisMetaRegistry::instance()->csRegistry() ->getColorSpace(KisID("RGBA",""), profileName);
m_clip = new KisPaintDeviceImpl(cs, "KisClipboard created clipboard selection");
Q_CHECK_PTR(m_clip);
m_clip -> convertFromQImage(qimg, profileName);
}
return m_clip;
}
void KisClipboard::clipboardDataChanged()
{
m_hasClip = false;
if (!m_pushedClipboard) {
QClipboard *cb = QApplication::clipboard();
QImage qimg = cb -> image();
QMimeSource *cbData = cb->data();
QCString mimeType("application/x-krita-selection");
if (!qimg.isNull()) {
KisColorSpace * cs = KisMetaRegistry::instance()->csRegistry() ->getColorSpace(KisID("RGBA",""),"");
if(cbData && cbData->provides(mimeType))
m_hasClip = true;
m_clip =
new KisPaintDeviceImpl(cs,
"KisClipboard created clipboard selection");
Q_CHECK_PTR(m_clip);
m_clip -> convertFromQImage(qimg);
}
if (!qimg.isNull())
m_hasClip = true;
}
m_pushedClipboard = false;
......@@ -113,10 +229,7 @@ void KisClipboard::clipboardDataChanged()
bool KisClipboard::hasClip()
{
if (m_clip != 0) {
return true;
}
return false;
return m_hasClip;
}
#include "kis_clipboard.moc"
......@@ -65,6 +65,7 @@ private:
static KisClipboard * m_singleton;
KisPaintDeviceImplSP m_clip;
bool m_hasClip;
bool m_pushedClipboard;
......
......@@ -126,17 +126,6 @@ void KisConfig::setWorkingColorSpace(QString workingColorSpace)
}
QString KisConfig::importProfile() const
{
return m_cfg -> readEntry("importProfile", "None");
}
void KisConfig::setImportProfile(QString importProfile)
{
m_cfg -> writeEntry("importProfile", importProfile);
}
QString KisConfig::printerColorSpace() const
{
return m_cfg -> readEntry("printerColorSpace", "CMYK");
......@@ -170,16 +159,6 @@ void KisConfig::setUseBlackPointCompensation(bool useBlackPointCompensation)
}
bool KisConfig::dither8Bit() const
{
return m_cfg -> readBoolEntry("dither8Bit", false);
}
void KisConfig::setDither8Bit(bool dither8Bit)
{
m_cfg -> writeEntry("dither8Bit", dither8Bit);
}
bool KisConfig::showRulers() const
{
return m_cfg->readBoolEntry("showrulers", false);
......@@ -190,40 +169,19 @@ void KisConfig::setShowRulers(bool rulers)
m_cfg->writeEntry("showrulers", rulers);
}
bool KisConfig::askProfileOnOpen() const
{
return m_cfg -> readBoolEntry("askProfileOnOpen", true);
}
void KisConfig::setAskProfileOnOpen(bool askProfileOnOpen)
{
m_cfg -> writeEntry("askProfileOnOpen", askProfileOnOpen);
}
bool KisConfig::askProfileOnPaste() const
{
return m_cfg -> readBoolEntry("askProfileOnPaste", true);
}
void KisConfig::setAskProfileOnPaste(bool askProfileOnPaste)
{
m_cfg -> writeEntry("askProfileOnPaste", askProfileOnPaste);
}
bool KisConfig::applyMonitorProfileOnCopy() const
Q_INT32 KisConfig::pasteBehaviour() const
{
return m_cfg -> readBoolEntry("applyMonitorProfileOnCopy", false);
return m_cfg -> readNumEntry("pasteBehaviour", 2);
}
void KisConfig::setApplyMonitorProfileOnCopy(bool applyMonitorProfileOnCopy)
void KisConfig::setPasteBehaviour(Q_INT32 renderIntent)
{
m_cfg -> writeEntry("applyMonitorProfileOnCopy", applyMonitorProfileOnCopy);
m_cfg -> writeEntry("pasteBehaviour", renderIntent);
}
Q_INT32 KisConfig::renderIntent()
Q_INT32 KisConfig::renderIntent() const
{
return m_cfg -> readNumEntry("renderIntent", INTENT_PERCEPTUAL);
}
......
......@@ -57,22 +57,13 @@ public:
bool useBlackPointCompensation() const;
void setUseBlackPointCompensation(bool useBlackPointCompensation);
bool dither8Bit() const;
void setDither8Bit(bool dither8Bit);
bool showRulers() const;
void setShowRulers(bool rulers);
bool askProfileOnOpen() const;
void setAskProfileOnOpen(bool askProfileOnOpen);
bool askProfileOnPaste() const;
void setAskProfileOnPaste(bool askProfileOnPaste);
bool applyMonitorProfileOnCopy() const;
void setApplyMonitorProfileOnCopy(bool applyMonitorProfileOnCopy);
Q_INT32 pasteBehaviour() const;
void setPasteBehaviour(Q_INT32 behaviour);
Q_INT32 renderIntent();
Q_INT32 renderIntent() const;
void setRenderIntent(Q_INT32 renderIntent);
bool useOpenGL() const;
......
......@@ -47,11 +47,12 @@ KisCustomImageWidget::KisCustomImageWidget(QWidget *parent, KisDoc *doc, Q_INT32
cmbColorSpaces -> setIDList(KisMetaRegistry::instance()->csRegistry() -> listKeys());
cmbColorSpaces -> setCurrentText(defColorSpaceName);
// Temporary KisID; this will be matched to the translated ID in the current KisIDList.
fillCmbProfiles(KisID(cmbColorSpaces->currentText(), ""));
connect(cmbColorSpaces, SIGNAL(activated(const KisID &)),
this, SLOT(fillCmbProfiles(const KisID &)));
// Temporary KisID; this will be matched to the translated ID in the current KisIDList.
fillCmbProfiles(KisID(cmbColorSpaces->currentText(), ""));
connect (m_createButton, SIGNAL( clicked() ), this, SLOT (buttonClicked()) );
}
......
......@@ -60,13 +60,7 @@ KisProfile * KisDlgApplyProfile::profile() const
{
QString profileName;
if (m_page -> cmbProfile -> currentItem() == 0) {
// Use import profile
KisConfig cfg;
profileName = cfg.importProfile();
} else {
profileName = m_page -> cmbProfile -> currentText();
}
profileName = m_page -> cmbProfile -> currentText();
return KisMetaRegistry::instance()->csRegistry()->getProfileByName(profileName);
}
......@@ -77,20 +71,24 @@ int KisDlgApplyProfile::renderIntent() const
}
// XXX: Copy & paste from kis_dlg_create_img -- refactor to separate class
// XXX: Copy & paste from kis_custom_image_widget -- refactor to separate class
void KisDlgApplyProfile::fillCmbProfiles(const KisID & s)
{
m_page -> cmbProfile -> clear();
if (!KisMetaRegistry::instance()->csRegistry()->exists(s)) {
return;
}
KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry() -> get(s);
m_page -> cmbProfile -> clear();
m_page -> cmbProfile -> insertItem(i18n("None"));
if (csf == 0) return;
QValueVector<KisProfile *> profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf );
QValueVector<KisProfile *> ::iterator it;
for ( it = profileList.begin(); it != profileList.end(); ++it ) {
m_page -> cmbProfile -> insertItem((*it) -> productName());
m_page -> cmbProfile -> insertItem((*it) -> productName());
}
m_page -> cmbProfile -> setCurrentText(csf->defaultProfile());
}
#include "kis_dlg_apply_profile.moc"
......
......@@ -28,7 +28,6 @@
#include <qlineedit.h>
#include <qcheckbox.h>
#include <qpushbutton.h>
#include <qcombobox.h>
#include <qcursor.h>
#include <qpixmap.h>
#include <qbitmap.h>
......@@ -44,6 +43,7 @@
#include <kurlrequester.h>
#include <klineedit.h>
#include <kiconloader.h>
#include <kcombobox.h>
#include <kis_meta_registry.h>
#include "kis_factory.h"
......@@ -118,48 +118,31 @@ ColorSettingsTab::ColorSettingsTab(QWidget *parent, const char *name )
m_page -> cmbPrintingColorSpace -> setIDList(KisMetaRegistry::instance()->csRegistry() -> listKeys());
m_page -> cmbPrintingColorSpace -> setCurrentText(cfg.printerColorSpace());
refillMonitorProfiles(KisID(cfg.workingColorSpace(), ""));
refillMonitorProfiles(KisID("RGBA", ""));
refillPrintProfiles(KisID(cfg.printerColorSpace(), ""));
refillImportProfiles(KisID(cfg.workingColorSpace(), ""));
m_page -> cmbMonitorProfile -> setCurrentText(cfg.monitorProfile());
m_page -> cmbImportProfile -> setCurrentText(cfg.importProfile());
m_page -> cmbPrintProfile -> setCurrentText(cfg.printerProfile());
if(m_page -> cmbMonitorProfile -> contains(cfg.monitorProfile()))
m_page -> cmbMonitorProfile -> setCurrentText(cfg.monitorProfile());
if(m_page -> cmbPrintProfile -> contains(cfg.printerProfile()))
m_page -> cmbPrintProfile -> setCurrentText(cfg.printerProfile());
m_page -> chkBlackpoint -> setChecked(cfg.useBlackPointCompensation());
m_page -> chkDither8Bit -> setChecked(cfg.dither8Bit());
m_page -> chkAskOpen -> setChecked(cfg.askProfileOnOpen());
m_page -> chkAskPaste -> setChecked(cfg.askProfileOnPaste());
m_page -> chkApplyMonitorOnCopy -> setChecked(cfg.applyMonitorProfileOnCopy());
m_page -> grpIntent -> setButton(cfg.renderIntent());
connect(m_page -> cmbWorkingColorSpace, SIGNAL(activated(const KisID &)),
this, SLOT(refillMonitorProfiles(const KisID &)));
connect(m_page -> cmbWorkingColorSpace, SIGNAL(activated(const KisID &)),
this, SLOT(refillImportProfiles(const KisID &)));
m_page -> grpPasteBehaviour -> setButton(cfg.pasteBehaviour());
m_page -> cmbMonitorIntent -> setCurrentItem(cfg.renderIntent());
connect(m_page -> cmbPrintingColorSpace, SIGNAL(activated(const KisID &)),
this, SLOT(refillPrintProfiles(const KisID &)));
}
void ColorSettingsTab::setDefault()
{
//TODO
m_page -> cmbWorkingColorSpace -> setCurrentText("RGBA");
m_page -> cmbPrintingColorSpace -> setCurrentText("CMYK");
refillPrintProfiles(KisID("CMYK", ""));
m_page -> cmbMonitorProfile -> setCurrentText("None");
m_page -> cmbImportProfile -> setCurrentText("None");
m_page -> cmbPrintProfile -> setCurrentText("None");
m_page -> chkBlackpoint -> setChecked(false);
m_page -> chkDither8Bit -> setChecked(false);
m_page -> chkAskOpen -> setChecked(true);
m_page -> chkAskPaste -> setChecked(true);
m_page -> chkApplyMonitorOnCopy -> setChecked(false);
m_page -> grpIntent -> setButton(INTENT_PERCEPTUAL);
m_page -> cmbMonitorIntent -> setCurrentItem(INTENT_PERCEPTUAL);
m_page -> grpPasteBehaviour -> setButton(2);
}
......@@ -168,7 +151,6 @@ void ColorSettingsTab::refillMonitorProfiles(const KisID & s)
KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry() -> get(s);
m_page -> cmbMonitorProfile -> clear();
m_page -> cmbMonitorProfile -> insertItem(i18n("None"));
if ( !csf )
return;
......@@ -176,41 +158,30 @@ void ColorSettingsTab::refillMonitorProfiles(const KisID & s)
QValueVector<KisProfile *> profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf );
QValueVector<KisProfile *> ::iterator it;
for ( it = profileList.begin(); it != profileList.end(); ++it ) {
if ((*it) -> deviceClass() == icSigDisplayClass)
m_page -> cmbMonitorProfile -> insertItem((*it) -> productName());
if ((*it) -> deviceClass() == icSigDisplayClass)
m_page -> cmbMonitorProfile -> insertItem((*it) -> productName());
}
m_page -> cmbMonitorProfile -> setCurrentText(csf->defaultProfile());
}
void ColorSettingsTab::refillPrintProfiles(const KisID & s)
{
KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry() -> get(s);
m_page -> cmbPrintProfile -> clear();
m_page -> cmbPrintProfile -> insertItem(i18n("None"));
if ( !csf )
return;
QValueVector<KisProfile *> profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf );
QValueVector<KisProfile *> ::iterator it;
for ( it = profileList.begin(); it != profileList.end(); ++it ) {
if ((*it) -> deviceClass() == icSigOutputClass)
m_page -> cmbPrintProfile -> insertItem((*it) -> productName());
}
}
m_page -> cmbPrintProfile -> clear();
void ColorSettingsTab::refillImportProfiles(const KisID & s)
{
KisColorSpaceFactory * csf = KisMetaRegistry::instance()->csRegistry() -> get(s);
m_page -> cmbImportProfile -> clear();
m_page -> cmbImportProfile -> insertItem(i18n("None"));
if ( !csf )
return;
QValueVector<KisProfile *> profileList = KisMetaRegistry::instance()->csRegistry()->profilesFor( csf );
QValueVector<KisProfile *> ::iterator it;
for ( it = profileList.begin(); it != profileList.end(); ++it ) {
if ((*it) -> deviceClass() == icSigInputClass)
m_page -> cmbImportProfile -> insertItem((*it) -> productName());
if ((*it) -> deviceClass() == icSigOutputClass)