/* * This file is part of Chalk * * Copyright (c) 2005 Michael Thaler * * ported from Gimp, Copyright (C) 1997 Eiichi Takamori * original pixelize.c for GIMP 0.54 by Tracy Scott * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_meta_registry.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_channel_separator.h" KisChannelSeparator::KisChannelSeparator(KisView * view) : m_view(view) { } void KisChannelSeparator::separate(KisProgressDisplayInterface * progress, enumSepAlphaOptions alphaOps, enumSepSource sourceOps, enumSepOutput outputOps, bool downscale, bool toColor) { KisImageSP image = m_view->canvasSubject()->currentImg(); if (!image) return; KisLayerSP layer = image->activeLayer(); if (!layer) return; KisPaintDeviceSP src = image->activeDevice(); if (!src) return; m_cancelRequested = false; if ( progress ) progress->setSubject(this, true, true); emit notifyProgressStage(i18n("Separating image..."), 0); KisColorSpace * dstCs = 0; TQ_UINT32 numberOfChannels = src->nChannels(); KisColorSpace * srcCs = src->colorSpace(); TQValueVector channels = srcCs->channels(); // Use the flattened image, if required switch(sourceOps) { case(ALL_LAYERS): src = image->mergedImage(); break; default: break; } vKisPaintDeviceSP layers; TQValueVector::const_iterator begin = channels.begin(); TQValueVector::const_iterator end = channels.end(); TQRect rect = src->exactBounds(); int i = 0; TQ_UINT32 channelIndex = 0; for (TQValueVector::const_iterator it = begin; it != end; ++it, ++channelIndex) { KisChannelInfo * ch = (*it); if (ch->channelType() == KisChannelInfo::ALPHA && alphaOps != CREATE_ALPHA_SEPARATION) { continue; } TQ_INT32 channelSize = ch->size(); TQ_INT32 channelPos = ch->pos(); TQ_INT32 destSize = 1; KisPaintDeviceSP dev; if (toColor) { // We don't downscale if we separate to color channels dev = new KisPaintDevice(srcCs, "color separations"); } else { if (channelSize == 1 || downscale) { dev = new KisPaintDevice( KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("GRAYA",""),"" ), "8 bit grayscale sep"); } else { dev = new KisPaintDevice( KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("GRAYA16",""),"" ), "16 bit grayscale sep"); destSize = 2; } } dstCs = dev->colorSpace(); layers.push_back(dev); for (TQ_INT32 row = 0; row < rect.height(); ++row) { KisHLineIteratorPixel srcIt = src->createHLineIterator(rect.x(), rect.y() + row, rect.width(), false); KisHLineIteratorPixel dstIt = dev->createHLineIterator(rect.x(), rect.y() + row, rect.width(), true); while( ! srcIt.isDone() ) { if (srcIt.isSelected()) { if (toColor) { dstCs->getSingleChannelPixel(dstIt.rawData(), srcIt.rawData(), channelIndex); if (alphaOps == COPY_ALPHA_TO_SEPARATIONS) { //dstCs->setAlpha(dstIt.rawData(), srcIt.rawData()[srcAlphaPos], 1); dstCs->setAlpha(dstIt.rawData(), srcCs->getAlpha(srcIt.rawData()), 1); } else { dstCs->setAlpha(dstIt.rawData(), OPACITY_OPAQUE, 1); } } else { // To grayscale // Decide wether we need downscaling if (channelSize == 1 && destSize == 1) { // Both 8-bit channels dstIt.rawData()[0] = srcIt.rawData()[channelPos]; if (alphaOps == COPY_ALPHA_TO_SEPARATIONS) { dstCs->setAlpha(dstIt.rawData(), srcCs->getAlpha(srcIt.rawData()), 1); } else { dstCs->setAlpha(dstIt.rawData(), OPACITY_OPAQUE, 1); } } else if (channelSize == 2 && destSize == 2) { // Both 16-bit dstIt.rawData()[0] = srcIt.rawData()[channelPos]; dstIt.rawData()[1] = srcIt.rawData()[channelPos + 1]; if (alphaOps == COPY_ALPHA_TO_SEPARATIONS) { dstCs->setAlpha(dstIt.rawData(), srcCs->getAlpha(srcIt.rawData()), 1); } else { dstCs->setAlpha(dstIt.rawData(), OPACITY_OPAQUE, 1); } } else if (channelSize != 1 && destSize == 1) { // Downscale memset(dstIt.rawData(), srcCs->scaleToU8(srcIt.rawData(), channelPos), 1); // XXX: Do alpha dstCs->setAlpha(dstIt.rawData(), OPACITY_OPAQUE, 1); } else if (channelSize != 2 && destSize == 2) { // Upscale dstIt.rawData()[0] = srcCs->scaleToU8(srcIt.rawData(), channelPos); // XXX: Do alpha dstCs->setAlpha(dstIt.rawData(), OPACITY_OPAQUE, 1); } } } ++dstIt; ++srcIt; } } ++i; emit notifyProgress((i * 100) / numberOfChannels); if (m_cancelRequested) { break; } } vKisPaintDeviceSP_it deviceIt = layers.begin(); emit notifyProgressDone(); if (!m_cancelRequested) { KisUndoAdapter * undo = 0; if ((undo = image->undoAdapter()) && undo->undo()) { undo->beginMacro(i18n("Separate Image")); } // Flatten the image if required switch(sourceOps) { case(ALL_LAYERS): image->flatten(); break; default: break; } for (TQValueVector::const_iterator it = begin; it != end; ++it) { KisChannelInfo * ch = (*it); if (ch->channelType() == KisChannelInfo::ALPHA && alphaOps != CREATE_ALPHA_SEPARATION) { // Don't make an separate separation of the alpha channel if the user didn't ask for it. continue; } if (outputOps == TO_LAYERS) { KisPaintLayerSP l = new KisPaintLayer( image, ch->name(), OPACITY_OPAQUE, *deviceIt); image->addLayer( dynamic_cast(l.data()), image->rootLayer(), 0); } else { TQStringList listMimeFilter = KoFilterManager::mimeFilter("application/x-chalk", KoFilterManager::Export); TQString mimelist = listMimeFilter.join(" "); KFileDialog fd (TQString(), mimelist, m_view, "Export Layer", true); fd.setCaption(i18n("Export Layer") + "(" + ch->name() + ")"); fd.setMimeFilter(listMimeFilter); fd.setOperationMode(KFileDialog::Saving); fd.setURL(KURL(ch->name())); if (!fd.exec()) return; KURL url = fd.selectedURL(); TQString mimefilter = fd.currentMimeFilter(); if (url.isEmpty()) return; KisPaintLayerSP l = new KisPaintLayer( image, ch->name(), OPACITY_OPAQUE, *deviceIt); TQRect r = l->exactBounds(); KisDoc d; d.prepareForImport(); KisImageSP dst = new KisImage(d.undoAdapter(), r.width(), r.height(), (*deviceIt)->colorSpace(), l->name()); d.setCurrentImage( dst ); dst->addLayer(l->clone(), dst->rootLayer(), 0); d.setOutputMimeType(mimefilter.latin1()); d.exp0rt(url); } ++deviceIt; } if (undo && undo->undo()) { undo->endMacro(); } m_view->canvasSubject()->document()->setModified(true); } } #include "kis_channel_separator.moc"