00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <string.h>
00022 #include <unistd.h>
00023
00024 #include <magick/api.h>
00025
00026 #include <qfile.h>
00027 #include <qfileinfo.h>
00028 #include <qstring.h>
00029
00030 #include <kdeversion.h>
00031 #include <kdebug.h>
00032 #include <kapplication.h>
00033 #include <klocale.h>
00034 #include <kurl.h>
00035 #include <kio/netaccess.h>
00036
00037 #include <qcolor.h>
00038
00039 #include "kis_types.h"
00040 #include "kis_global.h"
00041 #include "kis_doc.h"
00042 #include "kis_image.h"
00043 #include "kis_layer.h"
00044 #include "kis_undo_adapter.h"
00045 #include "kis_image_magick_converter.h"
00046 #include "kis_meta_registry.h"
00047 #include "kis_colorspace_factory_registry.h"
00048 #include "kis_iterators_pixel.h"
00049 #include "kis_colorspace.h"
00050 #include "kis_profile.h"
00051 #include "kis_annotation.h"
00052 #include "kis_paint_layer.h"
00053 #include "kis_group_layer.h"
00054 #include "kis_paint_device.h"
00055
00056 #include "../../../config.h"
00057
00058 namespace {
00059
00060 const Q_UINT8 PIXEL_BLUE = 0;
00061 const Q_UINT8 PIXEL_GREEN = 1;
00062 const Q_UINT8 PIXEL_RED = 2;
00063 const Q_UINT8 PIXEL_ALPHA = 3;
00064
00065 static const Q_UINT8 PIXEL_CYAN = 0;
00066 static const Q_UINT8 PIXEL_MAGENTA = 1;
00067 static const Q_UINT8 PIXEL_YELLOW = 2;
00068 static const Q_UINT8 PIXEL_BLACK = 3;
00069 static const Q_UINT8 PIXEL_CMYK_ALPHA = 4;
00070
00071 static const Q_UINT8 PIXEL_GRAY = 0;
00072 static const Q_UINT8 PIXEL_GRAY_ALPHA = 1;
00073
00078 QString getColorSpaceName(ColorspaceType type, unsigned long imageDepth = 8)
00079 {
00080
00081 if (type == GRAYColorspace) {
00082 if (imageDepth == 8)
00083 return "GRAYA";
00084 else if ( imageDepth == 16 )
00085 return "GRAYA16" ;
00086 }
00087 else if (type == CMYKColorspace) {
00088 if (imageDepth == 8)
00089 return "CMYK";
00090 else if ( imageDepth == 16 ) {
00091 return "CMYK16";
00092 }
00093 }
00094 #ifdef HAVE_MAGICK6
00095 else if (type == LABColorspace) {
00096 kdDebug(41008) << "Lab!\n";
00097 return "LABA";
00098 }
00099 #endif
00100 else if (type == RGBColorspace || type == sRGBColorspace || type == TransparentColorspace) {
00101 if (imageDepth == 8)
00102 return "RGBA";
00103 else if (imageDepth == 16)
00104 return "RGBA16";
00105 }
00106 return "";
00107
00108 }
00109
00110 ColorspaceType getColorTypeforColorSpace( KisColorSpace * cs )
00111 {
00112 if ( cs->id() == KisID("GRAYA") || cs->id() == KisID("GRAYA16") ) return GRAYColorspace;
00113 if ( cs->id() == KisID("RGBA") || cs->id() == KisID("RGBA16") ) return RGBColorspace;
00114 if ( cs->id() == KisID("CMYK") || cs->id() == KisID("CMYK16") ) return CMYKColorspace;
00115 #ifdef HAVE_MAGICK6
00116 if ( cs->id() == KisID("LABA") ) return LABColorspace;
00117 #endif
00118
00119 kdDebug(41008) << "Cannot export images in " + cs->id().name() + " yet.\n";
00120 return RGBColorspace;
00121
00122 }
00123
00124 KisProfile * getProfileForProfileInfo(const Image * image)
00125 {
00126 #ifndef HAVE_MAGICK6
00127 return 0;
00128 #else
00129
00130 if (image->profiles == NULL)
00131 return 0;
00132
00133 const char *name;
00134 const StringInfo *profile;
00135
00136 KisProfile * p = 0;
00137
00138 ResetImageProfileIterator(image);
00139 for (name = GetNextImageProfile(image); name != (char *) NULL; )
00140 {
00141 profile = GetImageProfile(image, name);
00142 if (profile == (StringInfo *) NULL)
00143 continue;
00144
00145
00146 if (QString::compare(name, "icc") == 0) {
00147 QByteArray rawdata;
00148 rawdata.resize(profile->length);
00149 memcpy(rawdata.data(), profile->datum, profile->length);
00150
00151 p = new KisProfile(rawdata);
00152 if (p == 0)
00153 return 0;
00154 }
00155 name = GetNextImageProfile(image);
00156 }
00157 return p;
00158 #endif
00159 }
00160
00161 void setAnnotationsForImage(const Image * src, KisImageSP image)
00162 {
00163 #ifndef HAVE_MAGICK6
00164 return;
00165 #else
00166 if (src->profiles == NULL)
00167 return;
00168
00169 const char *name = 0;
00170 const StringInfo *profile;
00171 KisAnnotation* annotation = 0;
00172
00173
00174 ResetImageProfileIterator(src);
00175 while((name = GetNextImageProfile(src))) {
00176 profile = GetImageProfile(src, name);
00177 if (profile == (StringInfo *) NULL)
00178 continue;
00179
00180
00181 if (QString::compare(name, "icc") == 0)
00182 continue;
00183
00184 QByteArray rawdata;
00185 rawdata.resize(profile->length);
00186 memcpy(rawdata.data(), profile->datum, profile->length);
00187
00188 annotation = new KisAnnotation(QString(name), "", rawdata);
00189 Q_CHECK_PTR(annotation);
00190
00191 image -> addAnnotation(annotation);
00192 }
00193
00194
00195
00196
00197
00198
00199 #if MagickLibVersion >= 0x621
00200 const ImageAttribute * attr;
00201 ResetImageAttributeIterator(src);
00202 while ( (attr = GetNextImageAttribute(src)) ) {
00203 #else
00204 ImageAttribute * attr = src -> attributes;
00205 while (attr) {
00206 #endif
00207 QByteArray rawdata;
00208 int len = strlen(attr -> value) + 1;
00209 rawdata.resize(len);
00210 memcpy(rawdata.data(), attr -> value, len);
00211
00212 annotation = new KisAnnotation(
00213 QString("krita_attribute:%1").arg(QString(attr -> key)), "", rawdata);
00214 Q_CHECK_PTR(annotation);
00215
00216 image -> addAnnotation(annotation);
00217 #if MagickLibVersion < 0x620
00218 attr = attr -> next;
00219 #endif
00220 }
00221
00222 #endif
00223 }
00224 }
00225
00226 void exportAnnotationsForImage(Image * dst, vKisAnnotationSP_it& it, vKisAnnotationSP_it& annotationsEnd)
00227 {
00228 #ifndef HAVE_MAGICK6
00229 return;
00230 #else
00231 while(it != annotationsEnd) {
00232 if (!(*it) || (*it) -> type() == QString()) {
00233 kdDebug(41008) << "Warning: empty annotation" << endl;
00234 ++it;
00235 continue;
00236 }
00237
00238 kdDebug(41008) << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size() << endl;
00239
00240 if ((*it) -> type().startsWith("krita_attribute:")) {
00241 if (!SetImageAttribute(dst,
00242 (*it) -> type().mid(strlen("krita_attribute:")).ascii(),
00243 (*it) -> annotation() . data()) ) {
00244 kdDebug(41008) << "Storing of attribute " << (*it) -> type() << "failed!\n";
00245 }
00246 } else {
00247 if (!ProfileImage(dst, (*it) -> type().ascii(),
00248 (unsigned char*)(*it) -> annotation() . data(),
00249 (*it) -> annotation() . size(), MagickFalse)) {
00250 kdDebug(41008) << "Storing failed!" << endl;
00251 }
00252 }
00253 ++it;
00254 }
00255 #endif
00256 }
00257
00258
00259 void InitGlobalMagick()
00260 {
00261 static bool init = false;
00262
00263 if (!init) {
00264 KApplication *app = KApplication::kApplication();
00265
00266 InitializeMagick(*app -> argv());
00267 atexit(DestroyMagick);
00268 init = true;
00269 }
00270 }
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 #ifdef HAVE_MAGICK6
00283 MagickBooleanType monitor(const char *text, const ExtendedSignedIntegralType, const ExtendedUnsignedIntegralType, ExceptionInfo *)
00284 {
00285 KApplication *app = KApplication::kApplication();
00286
00287 Q_ASSERT(app);
00288
00289 if (app -> hasPendingEvents())
00290 app -> processEvents();
00291
00292 printf("%s\n", text);
00293 return MagickTrue;
00294 }
00295 #else
00296 unsigned int monitor(const char *text, const ExtendedSignedIntegralType, const ExtendedUnsignedIntegralType, ExceptionInfo *)
00297 {
00298 KApplication *app = KApplication::kApplication();
00299
00300 Q_ASSERT(app);
00301
00302 if (app -> hasPendingEvents())
00303 app -> processEvents();
00304
00305 printf("%s\n", text);
00306 return true;
00307 }
00308 #endif
00309
00310
00311
00312 KisImageMagickConverter::KisImageMagickConverter(KisDoc *doc, KisUndoAdapter *adapter)
00313 {
00314 InitGlobalMagick();
00315 init(doc, adapter);
00316 SetMonitorHandler(monitor);
00317 m_stop = false;
00318 }
00319
00320 KisImageMagickConverter::~KisImageMagickConverter()
00321 {
00322 }
00323
00324 KisImageBuilder_Result KisImageMagickConverter::decode(const KURL& uri, bool isBlob)
00325 {
00326 Image *image;
00327 Image *images;
00328 ExceptionInfo ei;
00329 ImageInfo *ii;
00330
00331 if (m_stop) {
00332 m_img = 0;
00333 return KisImageBuilder_RESULT_INTR;
00334 }
00335
00336 GetExceptionInfo(&ei);
00337 ii = CloneImageInfo(0);
00338
00339 if (isBlob) {
00340
00341
00342 Q_ASSERT(uri.isEmpty());
00343 images = BlobToImage(ii, &m_data[0], m_data.size(), &ei);
00344 } else {
00345
00346 qstrncpy(ii -> filename, QFile::encodeName(uri.path()), MaxTextExtent - 1);
00347
00348 if (ii -> filename[MaxTextExtent - 1]) {
00349 emit notifyProgressError();
00350 return KisImageBuilder_RESULT_PATH;
00351 }
00352
00353 images = ReadImage(ii, &ei);
00354
00355 }
00356
00357 if (ei.severity != UndefinedException)
00358 CatchException(&ei);
00359
00360 if (images == 0) {
00361 DestroyImageInfo(ii);
00362 DestroyExceptionInfo(&ei);
00363 emit notifyProgressError();
00364 return KisImageBuilder_RESULT_FAILURE;
00365 }
00366
00367 emit notifyProgressStage(i18n("Importing..."), 0);
00368
00369 m_img = 0;
00370
00371 while ((image = RemoveFirstImageFromList(&images))) {
00372 ViewInfo *vi = OpenCacheView(image);
00373
00374
00375 unsigned long imageDepth = image->depth;
00376 kdDebug(41008) << "Image depth: " << imageDepth << "\n";
00377
00378 QString csName;
00379 KisColorSpace * cs = 0;
00380 ColorspaceType colorspaceType;
00381
00382
00383 if (GetImageType(image, &ei) == GrayscaleType || GetImageType(image, &ei) == GrayscaleMatteType) {
00384 if (imageDepth == 8)
00385 csName = "GRAYA";
00386 else if ( imageDepth == 16 )
00387 csName = "GRAYA16" ;
00388 colorspaceType = GRAYColorspace;
00389 }
00390 else {
00391 colorspaceType = image->colorspace;
00392 csName = getColorSpaceName(image -> colorspace, imageDepth);
00393 }
00394
00395 kdDebug(41008) << "image has " << csName << " colorspace\n";
00396
00397 KisProfile * profile = getProfileForProfileInfo(image);
00398 if (profile)
00399 {
00400 kdDebug(41008) << "image has embedded profile: " << profile -> productName() << "\n";
00401 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(csName, profile);
00402 }
00403 else
00404 cs = KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID(csName,""),"");
00405
00406 if (!cs) {
00407 kdDebug(41008) << "Krita does not support colorspace " << image -> colorspace << "\n";
00408 CloseCacheView(vi);
00409 DestroyImage(image);
00410 DestroyExceptionInfo(&ei);
00411 DestroyImageList(images);
00412 DestroyImageInfo(ii);
00413 emit notifyProgressError();
00414 return KisImageBuilder_RESULT_UNSUPPORTED_COLORSPACE;
00415 }
00416
00417 if( ! m_img) {
00418 m_img = new KisImage(m_doc->undoAdapter(), image -> columns, image -> rows, cs, "built image");
00419 Q_CHECK_PTR(m_img);
00420 m_img->blockSignals(true);
00421
00422
00423 setAnnotationsForImage(image, m_img);
00424 }
00425
00426 if (image -> columns && image -> rows) {
00427
00428
00429 Q_UINT8 opacity = OPACITY_OPAQUE;
00430 const ImageAttribute * attr = GetImageAttribute(image, "[layer-opacity]");
00431 if (attr != 0) {
00432 opacity = Q_UINT8_MAX - Downscale(QString(attr->value).toInt());
00433 }
00434
00435 KisPaintLayerSP layer = 0;
00436
00437 attr = GetImageAttribute(image, "[layer-name]");
00438 if (attr != 0) {
00439 layer = new KisPaintLayer(m_img, attr->value, opacity);
00440 }
00441 else {
00442 layer = new KisPaintLayer(m_img, m_img -> nextLayerName(), opacity);
00443 }
00444
00445 Q_ASSERT(layer);
00446
00447
00448 Q_INT32 x_offset = 0;
00449 Q_INT32 y_offset = 0;
00450
00451 attr = GetImageAttribute(image, "[layer-xpos]");
00452 if (attr != 0) {
00453 x_offset = QString(attr->value).toInt();
00454 }
00455
00456 attr = GetImageAttribute(image, "[layer-ypos]");
00457 if (attr != 0) {
00458 y_offset = QString(attr->value).toInt();
00459 }
00460
00461
00462 for (Q_UINT32 y = 0; y < image->rows; y ++)
00463 {
00464 const PixelPacket *pp = AcquireCacheView(vi, 0, y, image->columns, 1, &ei);
00465
00466 if(!pp)
00467 {
00468 CloseCacheView(vi);
00469 DestroyImageList(images);
00470 DestroyImageInfo(ii);
00471 DestroyExceptionInfo(&ei);
00472 emit notifyProgressError();
00473 return KisImageBuilder_RESULT_FAILURE;
00474 }
00475
00476 IndexPacket * indexes = GetCacheViewIndexes(vi);
00477
00478 KisHLineIteratorPixel hiter = layer->paintDevice()->createHLineIterator(0, y, image->columns, true);
00479
00480 if (colorspaceType== CMYKColorspace) {
00481 if (imageDepth == 8) {
00482 int x = 0;
00483 while (!hiter.isDone())
00484 {
00485 Q_UINT8 *ptr= hiter.rawData();
00486 *(ptr++) = Downscale(pp->red);
00487 *(ptr++) = Downscale(pp->green);
00488 *(ptr++) = Downscale(pp->blue);
00489 *(ptr++) = Downscale(indexes[x]);
00490
00491 #ifdef HAVE_MAGICK6
00492 if (image->matte != MagickFalse) {
00493 #else
00494 if (image->matte == true) {
00495 #endif
00496 *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity);
00497 }
00498 else {
00499 *(ptr++) = OPACITY_OPAQUE;
00500 }
00501 ++x;
00502 pp++;
00503 ++hiter;
00504 }
00505 }
00506 }
00507 #ifdef HAVE_MAGICK6
00508 else if (colorspaceType == LABColorspace) {
00509 while(! hiter.isDone())
00510 {
00511 Q_UINT16 *ptr = reinterpret_cast<Q_UINT16 *>(hiter.rawData());
00512
00513 *(ptr++) = ScaleQuantumToShort(pp->red);
00514 *(ptr++) = ScaleQuantumToShort(pp->green);
00515 *(ptr++) = ScaleQuantumToShort(pp->blue);
00516 *(ptr++) = 65535 - ScaleQuantumToShort(pp->opacity);
00517
00518 pp++;
00519 ++hiter;
00520 }
00521 }
00522 #endif
00523 else if (colorspaceType == RGBColorspace ||
00524 colorspaceType == sRGBColorspace ||
00525 colorspaceType == TransparentColorspace)
00526 {
00527 if (imageDepth == 8) {
00528 while(! hiter.isDone())
00529 {
00530 Q_UINT8 *ptr= hiter.rawData();
00531
00532 *(ptr++) = Downscale(pp->blue);
00533 *(ptr++) = Downscale(pp->green);
00534 *(ptr++) = Downscale(pp->red);
00535 *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity);
00536
00537 pp++;
00538 ++hiter;
00539 }
00540 }
00541 else if (imageDepth == 16) {
00542 while(! hiter.isDone())
00543 {
00544 Q_UINT16 *ptr = reinterpret_cast<Q_UINT16 *>(hiter.rawData());
00545
00546 *(ptr++) = ScaleQuantumToShort(pp->blue);
00547 *(ptr++) = ScaleQuantumToShort(pp->green);
00548 *(ptr++) = ScaleQuantumToShort(pp->red);
00549 *(ptr++) = 65535 - ScaleQuantumToShort(pp->opacity);
00550
00551 pp++;
00552 ++hiter;
00553 }
00554 }
00555 }
00556 else if ( colorspaceType == GRAYColorspace) {
00557 if (imageDepth == 8) {
00558 while(! hiter.isDone())
00559 {
00560 Q_UINT8 *ptr= hiter.rawData();
00561
00562 *(ptr++) = Downscale(pp->blue);
00563 *(ptr++) = OPACITY_OPAQUE - Downscale(pp->opacity);
00564
00565 pp++;
00566 ++hiter;
00567 }
00568 }
00569 else if (imageDepth == 16) {
00570 while(! hiter.isDone())
00571 {
00572 Q_UINT16 *ptr = reinterpret_cast<Q_UINT16 *>(hiter.rawData());
00573
00574 *(ptr++) = ScaleQuantumToShort(pp->blue);
00575 *(ptr++) = 65535 - ScaleQuantumToShort(pp->opacity);
00576
00577 pp++;
00578 ++hiter;
00579 }
00580 }
00581 }
00582
00583 emit notifyProgress(y * 100 / image->rows);
00584
00585 if (m_stop) {
00586 CloseCacheView(vi);
00587 DestroyImage(image);
00588 DestroyImageList(images);
00589 DestroyImageInfo(ii);
00590 DestroyExceptionInfo(&ei);
00591 m_img = 0;
00592 return KisImageBuilder_RESULT_INTR;
00593 }
00594 }
00595 m_img->addLayer(layer.data(), m_img->rootLayer());
00596 layer->paintDevice()->move(x_offset, y_offset);
00597 }
00598
00599 emit notifyProgressDone();
00600 CloseCacheView(vi);
00601 DestroyImage(image);
00602 }
00603
00604 emit notifyProgressDone();
00605 DestroyImageList(images);
00606 DestroyImageInfo(ii);
00607 DestroyExceptionInfo(&ei);
00608 return KisImageBuilder_RESULT_OK;
00609 }
00610
00611 KisImageBuilder_Result KisImageMagickConverter::buildImage(const KURL& uri)
00612 {
00613 if (uri.isEmpty())
00614 return KisImageBuilder_RESULT_NO_URI;
00615
00616 if (!KIO::NetAccess::exists(uri, false, qApp -> mainWidget())) {
00617 return KisImageBuilder_RESULT_NOT_EXIST;
00618 }
00619
00620 KisImageBuilder_Result result = KisImageBuilder_RESULT_FAILURE;
00621 QString tmpFile;
00622
00623 if (KIO::NetAccess::download(uri, tmpFile, qApp -> mainWidget())) {
00624 KURL uriTF;
00625 uriTF.setPath( tmpFile );
00626 result = decode(uriTF, false);
00627 KIO::NetAccess::removeTempFile(tmpFile);
00628 }
00629
00630 return result;
00631 }
00632
00633
00634 KisImageSP KisImageMagickConverter::image()
00635 {
00636 return m_img;
00637 }
00638
00639 void KisImageMagickConverter::init(KisDoc *doc, KisUndoAdapter *adapter)
00640 {
00641 m_doc = doc;
00642 m_adapter = adapter;
00643 m_job = 0;
00644 }
00645
00646 KisImageBuilder_Result KisImageMagickConverter::buildFile(const KURL& uri, KisPaintLayerSP layer, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd)
00647 {
00648 Image *image;
00649 ExceptionInfo ei;
00650 ImageInfo *ii;
00651
00652 if (!layer)
00653 return KisImageBuilder_RESULT_INVALID_ARG;
00654
00655 KisImageSP img = layer->image();
00656 if (!img)
00657 return KisImageBuilder_RESULT_EMPTY;
00658
00659 if (uri.isEmpty())
00660 return KisImageBuilder_RESULT_NO_URI;
00661
00662 if (!uri.isLocalFile())
00663 return KisImageBuilder_RESULT_NOT_LOCAL;
00664
00665
00666 Q_UINT32 layerBytesPerChannel = layer->paintDevice()->pixelSize() / layer->paintDevice()->nChannels();
00667
00668 GetExceptionInfo(&ei);
00669
00670 ii = CloneImageInfo(0);
00671
00672 qstrncpy(ii -> filename, QFile::encodeName(uri.path()), MaxTextExtent - 1);
00673
00674 if (ii -> filename[MaxTextExtent - 1]) {
00675 emit notifyProgressError();
00676 return KisImageBuilder_RESULT_PATH;
00677 }
00678
00679 if (!img -> width() || !img -> height())
00680 return KisImageBuilder_RESULT_EMPTY;
00681
00682 if (layerBytesPerChannel < 2) {
00683 ii->depth = 8;
00684 }
00685 else {
00686 ii->depth = 16;
00687 }
00688
00689 ii->colorspace = getColorTypeforColorSpace(layer->paintDevice()->colorSpace());
00690
00691 image = AllocateImage(ii);
00692 SetImageColorspace(image, ii->colorspace);
00693 image -> columns = img -> width();
00694 image -> rows = img -> height();
00695
00696 kdDebug(41008) << "Saving with colorspace " << image->colorspace << ", (" << layer->paintDevice()->colorSpace()->id().name() << ")\n";
00697 kdDebug(41008) << "IM Image thinks it has depth: " << image->depth << "\n";
00698
00699 #ifdef HAVE_MAGICK6
00700
00701 image -> matte = MagickTrue;
00702
00703
00704 #else
00705
00706 image -> matte = true;
00707 #endif
00708
00709 Q_INT32 y, height, width;
00710
00711 height = img -> height();
00712 width = img -> width();
00713
00714 bool alpha = true;
00715 QString ext = QFileInfo(QFile::encodeName(uri.path())).extension(false).upper();
00716 if (ext == "BMP") {
00717 alpha = false;
00718 qstrncpy(ii->magick, "BMP2", MaxTextExtent - 1);
00719 }
00720 else if (ext == "RGB") {
00721 qstrncpy(ii->magick, "SGI", MaxTextExtent - 1);
00722 }
00723
00724 for (y = 0; y < height; y++) {
00725
00726
00727 PixelPacket * pp = SetImagePixels(image, 0, y, width, 1);
00728
00729 if (!pp) {
00730 DestroyExceptionInfo(&ei);
00731 DestroyImage(image);
00732 emit notifyProgressError();
00733 return KisImageBuilder_RESULT_FAILURE;
00734
00735 }
00736
00737 KisHLineIterator it = layer->paintDevice()->createHLineIterator(0, y, width, false);
00738 if (alpha)
00739 SetImageType(image, TrueColorMatteType);
00740 else
00741 SetImageType(image, TrueColorType);
00742
00743 if (image->colorspace== CMYKColorspace) {
00744
00745 IndexPacket * indexes = GetIndexes(image);
00746 int x = 0;
00747 if (layerBytesPerChannel == 2) {
00748 while (!it.isDone()) {
00749
00750 const Q_UINT16 *d = reinterpret_cast<const Q_UINT16 *>(it.rawData());
00751 pp -> red = ScaleShortToQuantum(d[PIXEL_CYAN]);
00752 pp -> green = ScaleShortToQuantum(d[PIXEL_MAGENTA]);
00753 pp -> blue = ScaleShortToQuantum(d[PIXEL_YELLOW]);
00754 if (alpha)
00755 pp -> opacity = ScaleShortToQuantum(65535 - d[PIXEL_CMYK_ALPHA]);
00756 indexes[x] = ScaleShortToQuantum(d[PIXEL_BLACK]);
00757 x++;
00758 pp++;
00759 ++it;
00760 }
00761 }
00762 else {
00763 while (!it.isDone()) {
00764
00765 Q_UINT8 * d = it.rawData();
00766 pp -> red = Upscale(d[PIXEL_CYAN]);
00767 pp -> green = Upscale(d[PIXEL_MAGENTA]);
00768 pp -> blue = Upscale(d[PIXEL_YELLOW]);
00769 if (alpha)
00770 pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_CMYK_ALPHA]);
00771
00772 indexes[x]= Upscale(d[PIXEL_BLACK]);
00773
00774 x++;
00775 pp++;
00776 ++it;
00777 }
00778 }
00779 }
00780 else if (image->colorspace== RGBColorspace ||
00781 image->colorspace == sRGBColorspace ||
00782 image->colorspace == TransparentColorspace)
00783 {
00784 if (layerBytesPerChannel == 2) {
00785 while (!it.isDone()) {
00786
00787 const Q_UINT16 *d = reinterpret_cast<const Q_UINT16 *>(it.rawData());
00788 pp -> red = ScaleShortToQuantum(d[PIXEL_RED]);
00789 pp -> green = ScaleShortToQuantum(d[PIXEL_GREEN]);
00790 pp -> blue = ScaleShortToQuantum(d[PIXEL_BLUE]);
00791 if (alpha)
00792 pp -> opacity = ScaleShortToQuantum(65535 - d[PIXEL_ALPHA]);
00793
00794 pp++;
00795 ++it;
00796 }
00797 }
00798 else {
00799 while (!it.isDone()) {
00800
00801 Q_UINT8 * d = it.rawData();
00802 pp -> red = Upscale(d[PIXEL_RED]);
00803 pp -> green = Upscale(d[PIXEL_GREEN]);
00804 pp -> blue = Upscale(d[PIXEL_BLUE]);
00805 if (alpha)
00806 pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_ALPHA]);
00807
00808 pp++;
00809 ++it;
00810 }
00811 }
00812 }
00813 else if (image->colorspace == GRAYColorspace)
00814 {
00815 SetImageType(image, GrayscaleMatteType);
00816 if (layerBytesPerChannel == 2) {
00817 while (!it.isDone()) {
00818
00819 const Q_UINT16 *d = reinterpret_cast<const Q_UINT16 *>(it.rawData());
00820 pp -> red = ScaleShortToQuantum(d[PIXEL_GRAY]);
00821 pp -> green = ScaleShortToQuantum(d[PIXEL_GRAY]);
00822 pp -> blue = ScaleShortToQuantum(d[PIXEL_GRAY]);
00823 if (alpha)
00824 pp -> opacity = ScaleShortToQuantum(65535 - d[PIXEL_GRAY_ALPHA]);
00825
00826 pp++;
00827 ++it;
00828 }
00829 }
00830 else {
00831 while (!it.isDone()) {
00832 Q_UINT8 * d = it.rawData();
00833 pp -> red = Upscale(d[PIXEL_GRAY]);
00834 pp -> green = Upscale(d[PIXEL_GRAY]);
00835 pp -> blue = Upscale(d[PIXEL_GRAY]);
00836 if (alpha)
00837 pp -> opacity = Upscale(OPACITY_OPAQUE - d[PIXEL_GRAY_ALPHA]);
00838
00839 pp++;
00840 ++it;
00841 }
00842 }
00843 }
00844 else {
00845 kdDebug(41008) << "Unsupported image format\n";
00846 return KisImageBuilder_RESULT_INVALID_ARG;
00847 }
00848
00849 emit notifyProgressStage(i18n("Saving..."), y * 100 / height);
00850
00851 #ifdef HAVE_MAGICK6
00852 if (SyncImagePixels(image) == MagickFalse)
00853 kdDebug(41008) << "Syncing pixels failed\n";
00854 #else
00855 if (!SyncImagePixels(image))
00856 kdDebug(41008) << "Syncing pixels failed\n";
00857 #endif
00858 }
00859
00860
00861 exportAnnotationsForImage(image, annotationsStart, annotationsEnd);
00862
00863
00864
00865
00866 WriteImage(ii, image);
00867 DestroyExceptionInfo(&ei);
00868 DestroyImage(image);
00869 emit notifyProgressDone();
00870 return KisImageBuilder_RESULT_OK;
00871 }
00872
00873 void KisImageMagickConverter::ioData(KIO::Job *job, const QByteArray& data)
00874 {
00875 if (data.isNull() || data.isEmpty()) {
00876 emit notifyProgressStage(i18n("Loading..."), 0);
00877 return;
00878 }
00879
00880 if (m_data.empty()) {
00881 Image *image;
00882 ImageInfo *ii;
00883 ExceptionInfo ei;
00884
00885 ii = CloneImageInfo(0);
00886 GetExceptionInfo(&ei);
00887 image = PingBlob(ii, data.data(), data.size(), &ei);
00888
00889 if (image == 0 || ei.severity == BlobError) {
00890 DestroyExceptionInfo(&ei);
00891 DestroyImageInfo(ii);
00892 job -> kill();
00893 emit notifyProgressError();
00894 return;
00895 }
00896
00897 DestroyImage(image);
00898 DestroyExceptionInfo(&ei);
00899 DestroyImageInfo(ii);
00900 emit notifyProgressStage(i18n("Loading..."), 0);
00901 }
00902
00903 Q_ASSERT(data.size() + m_data.size() <= m_size);
00904 memcpy(&m_data[m_data.size()], data.data(), data.count());
00905 m_data.resize(m_data.size() + data.count());
00906 emit notifyProgressStage(i18n("Loading..."), m_data.size() * 100 / m_size);
00907
00908 if (m_stop)
00909 job -> kill();
00910 }
00911
00912 void KisImageMagickConverter::ioResult(KIO::Job *job)
00913 {
00914 m_job = 0;
00915
00916 if (job -> error())
00917 emit notifyProgressError();
00918
00919 decode(KURL(), true);
00920 }
00921
00922 void KisImageMagickConverter::ioTotalSize(KIO::Job * , KIO::filesize_t size)
00923 {
00924 m_size = size;
00925 m_data.reserve(size);
00926 emit notifyProgressStage(i18n("Loading..."), 0);
00927 }
00928
00929 void KisImageMagickConverter::cancel()
00930 {
00931 m_stop = true;
00932 }
00933
00938 QString KisImageMagickConverter::readFilters()
00939 {
00940 QString s;
00941 QString all;
00942 QString name;
00943 QString description;
00944 unsigned long matches;
00945
00946 #ifdef HAVE_MAGICK6
00947 #ifdef HAVE_OLD_GETMAGICKINFOLIST
00948 const MagickInfo **mi;
00949 mi = GetMagickInfoList("*", &matches);
00950 #else // HAVE_OLD_GETMAGICKINFOLIST
00951 ExceptionInfo ei;
00952 GetExceptionInfo(&ei);
00953 const MagickInfo **mi;
00954 mi = GetMagickInfoList("*", &matches, &ei);
00955 DestroyExceptionInfo(&ei);
00956 #endif // HAVE_OLD_GETMAGICKINFOLIST
00957 #else // HAVE_MAGICK6
00958 const MagickInfo *mi;
00959 ExceptionInfo ei;
00960 GetExceptionInfo(&ei);
00961 mi = GetMagickInfo("*", &ei);
00962 DestroyExceptionInfo(&ei);
00963 #endif // HAVE_MAGICK6
00964
00965 if (!mi)
00966 return s;
00967
00968 #ifdef HAVE_MAGICK6
00969 for (unsigned long i = 0; i < matches; i++) {
00970 const MagickInfo *info = mi[i];
00971 if (info -> stealth)
00972 continue;
00973
00974 if (info -> decoder) {
00975 name = info -> name;
00976 description = info -> description;
00977 kdDebug(41008) << "Found import filter for: " << name << "\n";
00978
00979 if (!description.isEmpty() && !description.contains('/')) {
00980 all += "*." + name.lower() + " *." + name + " ";
00981 s += "*." + name.lower() + " *." + name + "|";
00982 s += i18n(description.utf8());
00983 s += "\n";
00984 }
00985 }
00986 }
00987 #else
00988 for (; mi; mi = reinterpret_cast<const MagickInfo*>(mi -> next)) {
00989 if (mi -> stealth)
00990 continue;
00991 if (mi -> decoder) {
00992 name = mi -> name;
00993 description = mi -> description;
00994 kdDebug(41008) << "Found import filter for: " << name << "\n";
00995
00996 if (!description.isEmpty() && !description.contains('/')) {
00997 all += "*." + name.lower() + " *." + name + " ";
00998 s += "*." + name.lower() + " *." + name + "|";
00999 s += i18n(description.utf8());
01000 s += "\n";
01001 }
01002 }
01003 }
01004 #endif
01005
01006 all += "|" + i18n("All Images");
01007 all += "\n";
01008
01009 return all + s;
01010 }
01011
01012 QString KisImageMagickConverter::writeFilters()
01013 {
01014 QString s;
01015 QString all;
01016 QString name;
01017 QString description;
01018 unsigned long matches;
01019
01020 #ifdef HAVE_MAGICK6
01021 #ifdef HAVE_OLD_GETMAGICKINFOLIST
01022 const MagickInfo **mi;
01023 mi = GetMagickInfoList("*", &matches);
01024 #else // HAVE_OLD_GETMAGICKINFOLIST
01025 ExceptionInfo ei;
01026 GetExceptionInfo(&ei);
01027 const MagickInfo **mi;
01028 mi = GetMagickInfoList("*", &matches, &ei);
01029 DestroyExceptionInfo(&ei);
01030 #endif // HAVE_OLD_GETMAGICKINFOLIST
01031 #else // HAVE_MAGICK6
01032 const MagickInfo *mi;
01033 ExceptionInfo ei;
01034 GetExceptionInfo(&ei);
01035 mi = GetMagickInfo("*", &ei);
01036 DestroyExceptionInfo(&ei);
01037 #endif // HAVE_MAGICK6
01038
01039 if (!mi) {
01040 kdDebug(41008) << "Eek, no magick info!\n";
01041 return s;
01042 }
01043
01044 #ifdef HAVE_MAGICK6
01045 for (unsigned long i = 0; i < matches; i++) {
01046 const MagickInfo *info = mi[i];
01047 kdDebug(41008) << "Found export filter for: " << info -> name << "\n";
01048 if (info -> stealth)
01049 continue;
01050
01051 if (info -> encoder) {
01052 name = info -> name;
01053
01054 description = info -> description;
01055
01056 if (!description.isEmpty() && !description.contains('/')) {
01057 all += "*." + name.lower() + " *." + name + " ";
01058 s += "*." + name.lower() + " *." + name + "|";
01059 s += i18n(description.utf8());
01060 s += "\n";
01061 }
01062 }
01063 }
01064 #else
01065 for (; mi; mi = reinterpret_cast<const MagickInfo*>(mi -> next)) {
01066 kdDebug(41008) << "Found export filter for: " << mi -> name << "\n";
01067 if (mi -> stealth)
01068 continue;
01069
01070 if (mi -> encoder) {
01071 name = mi -> name;
01072
01073 description = mi -> description;
01074
01075 if (!description.isEmpty() && !description.contains('/')) {
01076 all += "*." + name.lower() + " *." + name + " ";
01077 s += "*." + name.lower() + " *." + name + "|";
01078 s += i18n(description.utf8());
01079 s += "\n";
01080 }
01081 }
01082 }
01083 #endif
01084
01085
01086 all += "|" + i18n("All Images");
01087 all += "\n";
01088
01089 return all + s;
01090 }
01091
01092 #include "kis_image_magick_converter.moc"
01093