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