You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/filters/chalk/gmagick/kis_image_magick_converter.cc

1145 lines
38 KiB

/*
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
* Copyright (c) 2006 Cyrille Berger <cberger@cberger.net>
*
* 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,
* Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <magick/api.h>
#include <tqfile.h>
#include <tqfileinfo.h>
#include <tqstring.h>
#include <tdeversion.h>
#include <kdebug.h>
#include <tdeapplication.h>
#include <tdelocale.h>
#include <kurl.h>
#include <tdeio/netaccess.h>
#include <tqcolor.h>
#include "kis_types.h"
#include "kis_global.h"
#include "kis_doc.h"
#include "kis_image.h"
#include "kis_layer.h"
#include "kis_undo_adapter.h"
#include "kis_image_magick_converter.h"
#include "kis_meta_registry.h"
#include "kis_colorspace_factory_registry.h"
#include "kis_iterators_pixel.h"
#include "kis_colorspace.h"
#include "kis_profile.h"
#include "kis_annotation.h"
#include "kis_paint_layer.h"
#include "kis_group_layer.h"
#include "kis_paint_device.h"
#include "../../../config.h"
namespace {
const TQ_UINT8 PIXEL_BLUE = 0;
const TQ_UINT8 PIXEL_GREEN = 1;
const TQ_UINT8 PIXEL_RED = 2;
const TQ_UINT8 PIXEL_ALPHA = 3;
static const TQ_UINT8 PIXEL_CYAN = 0;
static const TQ_UINT8 PIXEL_MAGENTA = 1;
static const TQ_UINT8 PIXEL_YELLOW = 2;
static const TQ_UINT8 PIXEL_BLACK = 3;
static const TQ_UINT8 PIXEL_CMYK_ALPHA = 4;
static const TQ_UINT8 PIXEL_GRAY = 0;
static const TQ_UINT8 PIXEL_GRAY_ALPHA = 1;
/**
* Make this more flexible -- although... ImageMagick
* isn't that flexible either.
*/
TQString getColorSpaceName(ColorspaceType type, unsigned long imageDepth = 8)
{
if (type == GRAYColorspace) {
if (imageDepth == 8)
return "GRAYA";
else if ( imageDepth == 16 )
return "GRAYA16" ;
}
else if (type == CMYKColorspace) {
if (imageDepth == 8)
return "CMYK";
else if ( imageDepth == 16 ) {
return "CMYK16";
}
}
else if (type == LABColorspace) {
kdDebug(41008) << "Lab!\n";
return "LABA";
}
else if (type == RGBColorspace || type == sRGBColorspace || type == TransparentColorspace) {
if (imageDepth == 8)
return "RGBA";
else if (imageDepth == 16)
return "RGBA16";
}
return "";
}
ColorspaceType getColorTypeforColorSpace( KisColorSpace * cs )
{
if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") ) return GRAYColorspace;
if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") ) return RGBColorspace;
if ( cs->id() == KisID("CMYK") || cs->id() == KisID("CMYK16") ) return CMYKColorspace;
if ( cs->id() == KisID("LABA") ) return LABColorspace;
kdDebug(41008) << "Cannot export images in " + cs->id().name() + " yet.\n";
return RGBColorspace;
}
KisProfile * getProfileForProfileInfo(const Image * image)
{
size_t length;
const unsigned char * profiledata = GetImageProfile(image, "ICM", &length);
if( profiledata == NULL )
return 0;
TQByteArray rawdata;
rawdata.resize(length);
memcpy(rawdata.data(), profiledata, length);
KisProfile* p = new KisProfile(rawdata);
return p;
#if 0
return 0;
if (image->profiles == NULL)
return 0;
const char *name;
const StringInfo *profile;
KisProfile * p = 0;
ResetImageProfileIterator(image);
for (name = GetNextImageProfile(image); name != (char *) NULL; )
{
profile = GetImageProfile(image, name);
if (profile == (StringInfo *) NULL)
continue;
// XXX: Hardcoded for icc type -- is that correct for us?
if (TQString::compare(name, "icc") == 0) {
TQByteArray rawdata;
rawdata.resize(profile->length);
memcpy(rawdata.data(), profile->datum, profile->length);
p = new KisProfile(rawdata);
if (p == 0)
return 0;
}
name = GetNextImageProfile(image);
}
return p;
#endif
}
void setAnnotationsForImage(const Image * src, KisImageSP image)
{
size_t length;
const unsigned char * profiledata = GetImageProfile(src, "IPTC", &length);
if( profiledata != NULL )
{
TQByteArray rawdata;
rawdata.resize(length);
memcpy(rawdata.data(), profiledata, length);
KisAnnotation* annotation = new KisAnnotation(TQString("IPTC"), "", rawdata);
TQ_CHECK_PTR(annotation);
image -> addAnnotation(annotation);
}
/* This code is no longer needed or supported by graphicsmagick */
#if 0
for(int i = 0; i < src->generic_profiles; i++)
{
TQByteArray rawdata;
rawdata.resize(length);
memcpy(rawdata.data(), src->generic_profile[i].info, src->generic_profile[i].length);
KisAnnotation* annotation = new KisAnnotation(TQString(src->generic_profile[i].name), "", rawdata);
TQ_CHECK_PTR(annotation);
image -> addAnnotation(annotation);
}
#endif
const ImageAttribute* imgAttr = GetImageAttribute(src, NULL);
while(imgAttr)
{
TQByteArray rawdata;
int len = strlen(imgAttr -> value) + 1;
rawdata.resize(len);
memcpy(rawdata.data(), imgAttr -> value, len);
KisAnnotation* annotation = new KisAnnotation( TQString("chalk_attribute:%1").arg(TQString(imgAttr -> key)), "", rawdata );
TQ_CHECK_PTR(annotation);
image -> addAnnotation(annotation);
imgAttr = imgAttr->next;
}
#if 0
return;
if (src->profiles == NULL)
return;
const char *name = 0;
const StringInfo *profile;
KisAnnotation* annotation = 0;
// Profiles and so
ResetImageProfileIterator(src);
while((name = GetNextImageProfile(src))) {
profile = GetImageProfile(src, name);
if (profile == (StringInfo *) NULL)
continue;
// XXX: icc will be written seperately?
if (TQString::compare(name, "icc") == 0)
continue;
TQByteArray rawdata;
rawdata.resize(profile->length);
memcpy(rawdata.data(), profile->datum, profile->length);
annotation = new KisAnnotation(TQString(name), "", rawdata);
TQ_CHECK_PTR(annotation);
image -> addAnnotation(annotation);
}
// Attributes, since we have no hint on if this is an attribute or a profile
// annotation, we prefix it with 'chalk_attribute:'. XXX This needs to be rethought!
// The joys of imagemagick. From at version 6.2.1 (dfaure has 6.2.0 and confirms the
// old way of doing things) they changed the src -> attributes
// to void* and require us to use the iterator functions. So we #if around that, *sigh*
#if MagickLibVersion >= 0x621
const ImageAttribute * attr;
ResetImageAttributeIterator(src);
while ( (attr = GetNextImageAttribute(src)) ) {
#else
ImageAttribute * attr = src -> attributes;
while (attr) {
#endif
TQByteArray rawdata;
int len = strlen(attr -> value) + 1;
rawdata.resize(len);
memcpy(rawdata.data(), attr -> value, len);
annotation = new KisAnnotation(
TQString("chalk_attribute:%1").arg(TQString(attr -> key)), "", rawdata);
TQ_CHECK_PTR(annotation);
image -> addAnnotation(annotation);
#if MagickLibVersion < 0x620
attr = attr -> next;
#endif
}
#endif
}
}
void exportAnnotationsForImage(Image * dst, vKisAnnotationSP_it& it, vKisAnnotationSP_it& annotationsEnd)
{
while(it != annotationsEnd) {
if (!(*it) || (*it) -> type() == TQString()) {
kdDebug(41008) << "Warning: empty annotation" << endl;
++it;
continue;
}
kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl;
if ((*it) -> type().startsWith("chalk_attribute:")) { // Attribute
if (!SetImageAttribute(dst,
(*it) -> type().mid(strlen("chalk_attribute:")).ascii(),
(*it) -> annotation() . data()) ) {
kdDebug(41008) << "Storing of attribute " << (*it) -> type() << "failed!\n";
}
} else { // Profile
unsigned char * profiledata = new unsigned char[(*it) -> annotation() . size()];
memcpy( profiledata, (*it) -> annotation() . data(), (*it) -> annotation() . size());
if (!ProfileImage(dst, (*it) -> type().ascii(),
profiledata, (*it) -> annotation() . size(), MagickFalse)) {
kdDebug(41008) << "Storing failed!" << endl;
}
}
++it;
}
}
void InitGlobalMagick()
{
static bool init = false;
if (!init) {
TDEApplication *app = TDEApplication::kApplication();
InitializeMagick(*app -> argv());
atexit(DestroyMagick);
init = true;
}
}
/*
* ImageMagick progress monitor callback. Unfortunately it doesn't support passing in some user
* data which complicates things quite a bit. The plan was to allow the user start multiple
* import/scans if he/she so wished. However, without passing user data it's not possible to tell
* on which task we have made progress on.
*
* Additionally, ImageMagick is thread-safe, not re-entrant... i.e. IM does not relinquish held
* locks when calling user defined callbacks, this means that the same thread going back into IM
* would deadlock since it would try to acquire locks it already holds.
*/
#if 0
MagickBooleanType monitor(const char *text, const ExtendedSignedIntegralType, const ExtendedUnsignedIntegralType, ExceptionInfo *)
{
TDEApplication *app = TDEApplication::kApplication();
Q_ASSERT(app);
if (app -> hasPendingEvents())
app -> processEvents();
printf("%s\n", text);
return MagickTrue;
}
#else
unsigned int monitor(const char *text, const ExtendedSignedIntegralType, const ExtendedUnsignedIntegralType, ExceptionInfo *)
{
TDEApplication *app = TDEApplication::kApplication();
Q_ASSERT(app);
if (app -> hasPendingEvents())
app -> processEvents();
printf("%s\n", text);
return true;
}
#endif
KisImageMagickConverter::KisImageMagickConverter(KisDoc *doc, KisUndoAdapter *adapter)
{
InitGlobalMagick();
init(doc, adapter);
SetMonitorHandler(monitor);
m_stop = false;
}
KisImageMagickConverter::~KisImageMagickConverter()
{
}
KisImageBuilder_Result KisImageMagickConverter::decode(const KURL& uri, bool isBlob)
{
Image *image;
Image *images;
ExceptionInfo ei;
ImageInfo *ii;
if (m_stop) {
m_img = 0;
return KisImageBuilder_RESULT_INTR;
}
GetExceptionInfo(&ei);
ii = CloneImageInfo(0);
if (isBlob) {
// TODO : Test. Does BlobToImage even work?
Q_ASSERT(uri.isEmpty());
images = BlobToImage(ii, &m_data[0], m_data.size(), &ei);
} else {
tqstrncpy(ii -> filename, TQFile::encodeName(uri.path()), MaxTextExtent - 1);
if (ii -> filename[MaxTextExtent - 1]) {
emit notifyProgressError();
return KisImageBuilder_RESULT_PATH;
}
images = ReadImage(ii, &ei);
}
if (ei.severity != UndefinedException)
{
CatchException(&ei);
kdDebug(41008) << "Exceptions happen when loading" << endl;
return KisImageBuilder_RESULT_FAILURE;
}
if (images == 0) {
DestroyImageInfo(ii);
DestroyExceptionInfo(&ei);
emit notifyProgressError();
return KisImageBuilder_RESULT_FAILURE;
}
emit notifyProgressStage(i18n("Importing..."), 0);
m_img = 0;
while ((image = RemoveFirstImageFromList(&images))) {
if(image->rows == 0 or image->columns == 0) return KisImageBuilder_RESULT_FAILURE;
ViewInfo *vi = OpenCacheView(image);
// Determine image depth -- for now, all channels of an imported image are of the same depth
unsigned long imageDepth = image->depth;
kdDebug(41008) << "Image depth: " << imageDepth << "\n";
TQString csName;
KisColorSpace * cs = 0;
ColorspaceType colorspaceType;
// Determine image type -- rgb, grayscale or cmyk
if (GetImageType(image, &ei) == GrayscaleType || GetImageType(image, &ei) == GrayscaleMatteType) {
if (imageDepth == 8)
csName = "GRAYA";
else if ( imageDepth == 16 )
csName = "GRAYA16" ;
colorspaceType = GRAYColorspace;
}
else {
colorspaceType = image->colorspace;
csName = getColorSpaceName(image -> colorspace, imageDepth);
}
kdDebug(41008) << "image has " << csName << " colorspace\n";
KisProfile * profile = getProfileForProfileInfo(image);
if (profile)
{
kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n";
cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
}
else
cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),"");
if (!cs) {
kdDebug(41008) << "Chalk does not support colorspace " << image -> colorspace << "\n";
CloseCacheView(vi);
DestroyImage(image);
DestroyExceptionInfo(&ei);
DestroyImageList(images);
DestroyImageInfo(ii);
emit notifyProgressError();
return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
}
if( ! m_img) {
m_img = new KisImage(m_doc->undoAdapter(), image -> columns, image -> rows, cs, "built image");
TQ_CHECK_PTR(m_img);
m_img->blockSignals(true); // Don't send out signals while we're building the image
// XXX I'm assuming seperate layers won't have other profile things like EXIF
setAnnotationsForImage(image, m_img);
}
if (image -> columns && image -> rows) {
// Opacity (set by the photoshop import filter)
TQ_UINT8 opacity = OPACITY_OPAQUE;
const ImageAttribute * attr = GetImageAttribute(image, "[layer-opacity]");
if (attr != 0) {
opacity = TQ_UINT8_MAX - ScaleQuantumToChar(TQString(attr->value).toInt());
}
KisPaintLayerSP layer = 0;
attr = GetImageAttribute(image, "[layer-name]");
if (attr != 0) {
layer = new KisPaintLayer(m_img, attr->value, opacity);
}
else {
layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), opacity);
}
Q_ASSERT(layer);
// Layerlocation (set by the photoshop import filter)
TQ_INT32 x_offset = 0;
TQ_INT32 y_offset = 0;
attr = GetImageAttribute(image, "[layer-xpos]");
if (attr != 0) {
x_offset = TQString(attr->value).toInt();
}
attr = GetImageAttribute(image, "[layer-ypos]");
if (attr != 0) {
y_offset = TQString(attr->value).toInt();
}
for (TQ_UINT32 y = 0; y < image->rows; y ++)
{
const PixelPacket *pp = AcquireCacheView(vi, 0, y, image->columns, 1, &ei);
if(!pp)
{
CloseCacheView(vi);
DestroyImageList(images);
DestroyImageInfo(ii);
DestroyExceptionInfo(&ei);
emit notifyProgressError();
return KisImageBuilder_RESULT_FAILURE;
}
IndexPacket * indexes = GetCacheViewIndexes(vi);
KisHLineIteratorPixel hiter = layer->paintDevice()->createHLineIterator(0, y, image->columns, true);
if (colorspaceType== CMYKColorspace) {
if (imageDepth == 8) {
int x = 0;
while (!hiter.isDone())
{
TQ_UINT8 *ptr= hiter.rawData();
*(ptr++) = ScaleQuantumToChar(pp->red); // cyan
*(ptr++) = ScaleQuantumToChar(pp->green); // magenta
*(ptr++) = ScaleQuantumToChar(pp->blue); // yellow
*(ptr++) = ScaleQuantumToChar(indexes[x]); // Black
// XXX: Warning! This ifdef messes up the paren matching big-time!
#ifdef HAVE_MAGICK6
if (image->matte != MagickFalse) {
#else
if (image->matte == true) {
#endif
*(ptr++) = OPACITY_OPAQUE - ScaleQuantumToChar(pp->opacity);
}
else {
*(ptr++) = OPACITY_OPAQUE;
}
++x;
pp++;
++hiter;
}
}
}
else if (colorspaceType == LABColorspace) {
while(! hiter.isDone())
{
TQ_UINT16 *ptr = reinterpret_cast<TQ_UINT16 *>(hiter.rawData());
*(ptr++) = ScaleQuantumToShort(pp->red);
*(ptr++) = ScaleQuantumToShort(pp->green);
*(ptr++) = ScaleQuantumToShort(pp->blue);
*(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity);
pp++;
++hiter;
}
}
else if (colorspaceType == RGBColorspace ||
colorspaceType == sRGBColorspace ||
colorspaceType == TransparentColorspace)
{
if (imageDepth == 8) {
while(! hiter.isDone())
{
TQ_UINT8 *ptr= hiter.rawData();
// XXX: not colorstrategy and bitdepth independent
*(ptr++) = ScaleQuantumToChar(pp->blue);
*(ptr++) = ScaleQuantumToChar(pp->green);
*(ptr++) = ScaleQuantumToChar(pp->red);
*(ptr++) = OPACITY_OPAQUE - ScaleQuantumToChar(pp->opacity);
pp++;
++hiter;
}
}
else if (imageDepth == 16) {
while(! hiter.isDone())
{
TQ_UINT16 *ptr = reinterpret_cast<TQ_UINT16 *>(hiter.rawData());
// XXX: not colorstrategy independent
*(ptr++) = ScaleQuantumToShort(pp->blue);
*(ptr++) = ScaleQuantumToShort(pp->green);
*(ptr++) = ScaleQuantumToShort(pp->red);
*(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity);
pp++;
++hiter;
}
}
}
else if ( colorspaceType == GRAYColorspace) {
if (imageDepth == 8) {
while(! hiter.isDone())
{
TQ_UINT8 *ptr= hiter.rawData();
// XXX: not colorstrategy and bitdepth independent
*(ptr++) = ScaleQuantumToChar(pp->blue);
*(ptr++) = OPACITY_OPAQUE - ScaleQuantumToChar(pp->opacity);
pp++;
++hiter;
}
}
else if (imageDepth == 16) {
while(! hiter.isDone())
{
TQ_UINT16 *ptr = reinterpret_cast<TQ_UINT16 *>(hiter.rawData());
// XXX: not colorstrategy independent
*(ptr++) = ScaleQuantumToShort(pp->blue);
*(ptr++) = 65535/*OPACITY_OPAQUE*/ - ScaleQuantumToShort(pp->opacity);
pp++;
++hiter;
}
}
}
emit notifyProgress(y * 100 / image->rows);
if (m_stop) {
CloseCacheView(vi);
DestroyImage(image);
DestroyImageList(images);
DestroyImageInfo(ii);
DestroyExceptionInfo(&ei);
m_img = 0;
return KisImageBuilder_RESULT_INTR;
}
}
m_img->addLayer(layer.data(), m_img->rootLayer());
layer->paintDevice()->move(x_offset, y_offset);
}
emit notifyProgressDone();
CloseCacheView(vi);
DestroyImage(image);
}
emit notifyProgressDone();
DestroyImageList(images);
DestroyImageInfo(ii);
DestroyExceptionInfo(&ei);
return KisImageBuilder_RESULT_OK;
}
KisImageBuilder_Result KisImageMagickConverter::buildImage(const KURL& uri)
{
if (uri.isEmpty())
return KisImageBuilder_RESULT_NO_URI;
if (!TDEIO::NetAccess::exists(uri, false, tqApp -> mainWidget())) {
return KisImageBuilder_RESULT_NOT_EXIST;
}
KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
TQString tmpFile;
if (TDEIO::NetAccess::download(uri, tmpFile, tqApp -> mainWidget())) {
KURL uriTF;
uriTF.setPath( tmpFile );
result = decode(uriTF, false);
TDEIO::NetAccess::removeTempFile(tmpFile);
}
return result;
}
KisImageSP KisImageMagickConverter::image()
{
return m_img;
}
void KisImageMagickConverter::init(KisDoc *doc, KisUndoAdapter *adapter)
{
m_doc = doc;
m_adapter = adapter;
m_job = 0;
}
KisImageBuilder_Result KisImageMagickConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd)
{
Image *image;
ExceptionInfo ei;
ImageInfo *ii;
if (!layer)
return KisImageBuilder_RESULT_INVALID_ARG;
KisImageSP img = layer->image();
if (!img)
return KisImageBuilder_RESULT_EMPTY;
if (uri.isEmpty())
return KisImageBuilder_RESULT_NO_URI;
if (!uri.isLocalFile())
return KisImageBuilder_RESULT_NOT_LOCAL;
TQ_UINT32 layerBytesPerChannel = layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
GetExceptionInfo(&ei);
ii = CloneImageInfo(0);
tqstrncpy(ii -> filename, TQFile::encodeName(uri.path()), MaxTextExtent - 1);
if (ii -> filename[MaxTextExtent - 1]) {
emit notifyProgressError();
return KisImageBuilder_RESULT_PATH;
}
if (!img -> width() || !img -> height())
return KisImageBuilder_RESULT_EMPTY;
if (layerBytesPerChannel < 2) {
ii->depth = 8;
}
else {
ii->depth = 16;
}
ii->colorspace = getColorTypeforColorSpace(layer->paintDevice()->colorSpace());
image = AllocateImage(ii);
// SetImageColorspace(image, ii->colorspace);
image -> columns = img -> width();
image -> rows = img -> height();
kdDebug(41008) << "Saving with colorspace " << image->colorspace << ", (" << layer->paintDevice()->colorSpace()->id().name() << ")\n";
kdDebug(41008) << "IM Image thinks it has depth: " << image->depth << "\n";
#ifdef HAVE_MAGICK6
// if ( layer-> hasAlpha() )
image -> matte = MagickTrue;
// else
// image -> matte = MagickFalse;
#else
// image -> matte = layer -> hasAlpha();
image -> matte = true;
#endif
TQ_INT32 y, height, width;
height = img -> height();
width = img -> width();
bool alpha = true;
TQString ext = TQFileInfo(TQFile::encodeName(uri.path())).extension(false).upper();
if (ext == "BMP") {
alpha = false;
tqstrncpy(ii->magick, "BMP2", MaxTextExtent - 1);
}
else if (ext == "RGB") {
tqstrncpy(ii->magick, "SGI", MaxTextExtent - 1);
}
for (y = 0; y < height; y++) {
// Allocate pixels for this scanline
PixelPacket * pp = SetImagePixels(image, 0, y, width, 1);
if (!pp) {
DestroyExceptionInfo(&ei);
DestroyImage(image);
emit notifyProgressError();
return KisImageBuilder_RESULT_FAILURE;
}
KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false);
if (alpha)
SetImageType(image, TrueColorMatteType);
else
SetImageType(image, TrueColorType);
if (image->colorspace== CMYKColorspace) {
IndexPacket * indexes = GetIndexes(image);
int x = 0;
if (layerBytesPerChannel == 2) {
while (!it.isDone()) {
const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
pp -> red = ScaleShortToQuantum(d[PIXEL_CYAN]);
pp -> green = ScaleShortToQuantum(d[PIXEL_MAGENTA]);
pp -> blue = ScaleShortToQuantum(d[PIXEL_YELLOW]);
if (alpha)
pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_CMYK_ALPHA]);
indexes[x] = ScaleShortToQuantum(d[PIXEL_BLACK]);
x++;
pp++;
++it;
}
}
else {
while (!it.isDone()) {
TQ_UINT8 * d = it.rawData();
pp -> red = ScaleCharToQuantum(d[PIXEL_CYAN]);
pp -> green = ScaleCharToQuantum(d[PIXEL_MAGENTA]);
pp -> blue = ScaleCharToQuantum(d[PIXEL_YELLOW]);
if (alpha)
pp -> opacity = ScaleCharToQuantum(OPACITY_OPAQUE - d[PIXEL_CMYK_ALPHA]);
indexes[x]= ScaleCharToQuantum(d[PIXEL_BLACK]);
x++;
pp++;
++it;
}
}
}
else if (image->colorspace== RGBColorspace ||
image->colorspace == sRGBColorspace ||
image->colorspace == TransparentColorspace)
{
if (layerBytesPerChannel == 2) {
while (!it.isDone()) {
const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
pp -> red = ScaleShortToQuantum(d[PIXEL_RED]);
pp -> green = ScaleShortToQuantum(d[PIXEL_GREEN]);
pp -> blue = ScaleShortToQuantum(d[PIXEL_BLUE]);
if (alpha)
pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_ALPHA]);
pp++;
++it;
}
}
else {
while (!it.isDone()) {
TQ_UINT8 * d = it.rawData();
pp -> red = ScaleCharToQuantum(d[PIXEL_RED]);
pp -> green = ScaleCharToQuantum(d[PIXEL_GREEN]);
pp -> blue = ScaleCharToQuantum(d[PIXEL_BLUE]);
if (alpha)
pp -> opacity = ScaleCharToQuantum(OPACITY_OPAQUE - d[PIXEL_ALPHA]);
pp++;
++it;
}
}
}
else if (image->colorspace == GRAYColorspace)
{
SetImageType(image, GrayscaleMatteType);
if (layerBytesPerChannel == 2) {
while (!it.isDone()) {
const TQ_UINT16 *d = reinterpret_cast<const TQ_UINT16 *>(it.rawData());
pp -> red = ScaleShortToQuantum(d[PIXEL_GRAY]);
pp -> green = ScaleShortToQuantum(d[PIXEL_GRAY]);
pp -> blue = ScaleShortToQuantum(d[PIXEL_GRAY]);
if (alpha)
pp -> opacity = ScaleShortToQuantum(65535/*OPACITY_OPAQUE*/ - d[PIXEL_GRAY_ALPHA]);
pp++;
++it;
}
}
else {
while (!it.isDone()) {
TQ_UINT8 * d = it.rawData();
pp -> red = ScaleCharToQuantum(d[PIXEL_GRAY]);
pp -> green = ScaleCharToQuantum(d[PIXEL_GRAY]);
pp -> blue = ScaleCharToQuantum(d[PIXEL_GRAY]);
if (alpha)
pp -> opacity = ScaleCharToQuantum(OPACITY_OPAQUE - d[PIXEL_GRAY_ALPHA]);
pp++;
++it;
}
}
}
else {
kdDebug(41008) << "Unsupported image format\n";
return KisImageBuilder_RESULT_INVALID_ARG;
}
emit notifyProgressStage(i18n("Saving..."), y * 100 / height);
#ifdef HAVE_MAGICK6
if (SyncImagePixels(image) == MagickFalse)
kdDebug(41008) << "Syncing pixels failed\n";
#else
if (!SyncImagePixels(image))
kdDebug(41008) << "Syncing pixels failed\n";
#endif
}
// set the annotations
exportAnnotationsForImage(image, annotationsStart, annotationsEnd);
// XXX: Write to a temp file, then have Chalk use TDEIO to copy temp
// image to remote location.
WriteImage(ii, image);
DestroyExceptionInfo(&ei);
DestroyImage(image);
emit notifyProgressDone();
return KisImageBuilder_RESULT_OK;
}
void KisImageMagickConverter::ioData(TDEIO::Job *job, const TQByteArray& data)
{
if (data.isNull() || data.isEmpty()) {
emit notifyProgressStage(i18n("Loading..."), 0);
return;
}
if (m_data.empty()) {
Image *image;
ImageInfo *ii;
ExceptionInfo ei;
ii = CloneImageInfo(0);
GetExceptionInfo(&ei);
image = PingBlob(ii, data.data(), data.size(), &ei);
if (image == 0 || ei.severity == BlobError) {
DestroyExceptionInfo(&ei);
DestroyImageInfo(ii);
job -> kill();
emit notifyProgressError();
return;
}
DestroyImage(image);
DestroyExceptionInfo(&ei);
DestroyImageInfo(ii);
emit notifyProgressStage(i18n("Loading..."), 0);
}
Q_ASSERT(data.size() + m_data.size() <= m_size);
memcpy(&m_data[m_data.size()], data.data(), data.count());
m_data.resize(m_data.size() + data.count());
emit notifyProgressStage(i18n("Loading..."), m_data.size() * 100 / m_size);
if (m_stop)
job -> kill();
}
void KisImageMagickConverter::ioResult(TDEIO::Job *job)
{
m_job = 0;
if (job -> error())
emit notifyProgressError();
decode(KURL(), true);
}
void KisImageMagickConverter::ioTotalSize(TDEIO::Job * /*job*/, TDEIO::filesize_t size)
{
m_size = size;
m_data.reserve(size);
emit notifyProgressStage(i18n("Loading..."), 0);
}
void KisImageMagickConverter::cancel()
{
m_stop = true;
}
/**
* @name readFilters
* @return Provide a list of file formats the application can read.
*/
TQString KisImageMagickConverter::readFilters()
{
TQString s;
TQString all;
TQString name;
TQString description;
unsigned long matches;
/*#ifdef HAVE_MAGICK6
#ifdef HAVE_OLD_GETMAGICKINFOLIST
const MagickInfo **mi;
mi = GetMagickInfoList("*", &matches);
#else // HAVE_OLD_GETMAGICKINFOLIST
ExceptionInfo ei;
GetExceptionInfo(&ei);
const MagickInfo **mi;
mi = GetMagickInfoList("*", &matches, &ei);
DestroyExceptionInfo(&ei);
#endif // HAVE_OLD_GETMAGICKINFOLIST
#else // HAVE_MAGICK6*/
const MagickInfo *mi;
ExceptionInfo ei;
GetExceptionInfo(&ei);
mi = GetMagickInfo("*", &ei);
DestroyExceptionInfo(&ei);
// #endif // HAVE_MAGICK6
if (!mi)
return s;
/*#ifdef HAVE_MAGICK6
for (unsigned long i = 0; i < matches; i++) {
const MagickInfo *info = mi[i];
if (info -> stealth)
continue;
if (info -> decoder) {
name = info -> name;
description = info -> description;
kdDebug(41008) << "Found import filter for: " << name << "\n";
if (!description.isEmpty() && !description.contains('/')) {
all += "*." + name.lower() + " *." + name + " ";
s += "*." + name.lower() + " *." + name + "|";
s += i18n(description.utf8());
s += "\n";
}
}
}
#else*/
for (; mi; mi = reinterpret_cast<const MagickInfo*>(mi -> next)) {
if (mi -> stealth)
continue;
if (mi -> decoder) {
name = mi -> name;
description = mi -> description;
kdDebug(41008) << "Found import filter for: " << name << "\n";
if (!description.isEmpty() && !description.contains('/')) {
all += "*." + name.lower() + " *." + name + " ";
s += "*." + name.lower() + " *." + name + "|";
s += i18n(description.utf8());
s += "\n";
}
}
}
// #endif
all += "|" + i18n("All Images");
all += "\n";
return all + s;
}
TQString KisImageMagickConverter::writeFilters()
{
TQString s;
TQString all;
TQString name;
TQString description;
unsigned long matches;
/*#ifdef HAVE_MAGICK6
#ifdef HAVE_OLD_GETMAGICKINFOLIST
const MagickInfo **mi;
mi = GetMagickInfoList("*", &matches);
#else // HAVE_OLD_GETMAGICKINFOLIST
ExceptionInfo ei;
GetExceptionInfo(&ei);
const MagickInfo **mi;
mi = GetMagickInfoList("*", &matches, &ei);
DestroyExceptionInfo(&ei);
#endif // HAVE_OLD_GETMAGICKINFOLIST
#else // HAVE_MAGICK6*/
const MagickInfo *mi;
ExceptionInfo ei;
GetExceptionInfo(&ei);
mi = GetMagickInfo("*", &ei);
DestroyExceptionInfo(&ei);
// #endif // HAVE_MAGICK6
if (!mi) {
kdDebug(41008) << "Eek, no magick info!\n";
return s;
}
/*#ifdef HAVE_MAGICK6
for (unsigned long i = 0; i < matches; i++) {
const MagickInfo *info = mi[i];
kdDebug(41008) << "Found export filter for: " << info -> name << "\n";
if (info -> stealth)
continue;
if (info -> encoder) {
name = info -> name;
description = info -> description;
if (!description.isEmpty() && !description.contains('/')) {
all += "*." + name.lower() + " *." + name + " ";
s += "*." + name.lower() + " *." + name + "|";
s += i18n(description.utf8());
s += "\n";
}
}
}
#else*/
for (; mi; mi = reinterpret_cast<const MagickInfo*>(mi -> next)) {
kdDebug(41008) << "Found export filter for: " << mi -> name << "\n";
if (mi -> stealth)
continue;
if (mi -> encoder) {
name = mi -> name;
description = mi -> description;
if (!description.isEmpty() && !description.contains('/')) {
all += "*." + name.lower() + " *." + name + " ";
s += "*." + name.lower() + " *." + name + "|";
s += i18n(description.utf8());
s += "\n";
}
}
}
// #endif
all += "|" + i18n("All Images");
all += "\n";
return all + s;
}
#include "kis_image_magick_converter.moc"