Commit 178ac6df authored by Halla Rempt's avatar Halla Rempt

Pass an IO device to the filters instead of a filename

Not all filters can handle that: some need a filename to start
a directory structure, others (tiff) use a library that thinks
it needs to open the file itself.

Implements T3574
parent e0656601
......@@ -122,6 +122,9 @@ private:
// The parent filter manager may be 0.
friend class CalligraFilter::Graph;
friend class KisImportExportFilter;
friend class KisImportExportManager;
friend class CalligraFilter::ChainLink;
void prependChainLink(KisFilterEntrySP filterEntry, const QByteArray& from, const QByteArray& to);
......@@ -129,8 +132,6 @@ private:
// to a private part of its API. As I don't want to include
// koFilterManager.h in this header the direction is "int" here.
friend class KisImportExportManager;
QString filterManagerImportFile() const;
QString filterManagerExportFile() const;
KisDocument* filterManagerKisDocument() const;
......
......@@ -24,7 +24,7 @@ Boston, MA 02110-1301, USA.
#include "KisImportExportManager.h"
#include "KoProgressUpdater.h"
#include "KoUpdater.h"
#include <QFile>
namespace
{
KoUpdater *createUpdater(KisFilterChainSP chain)
......@@ -78,7 +78,35 @@ namespace CalligraFilter {
m_filter->setUpdater(m_updater);
}
KisImportExportFilter::ConversionStatus status = m_filter->convert(m_from, m_to, m_chain->filterManagerExportConfiguration());
KisImportExportFilter::ConversionStatus status;
if (static_cast<KisImportExportManager::Direction>(m_chain->filterManagerDirection()) == KisImportExportManager::Export) {
m_filter->setMimeType(m_to);
KisDocument *doc = m_chain->inputDocument();
QFile fi(m_chain->outputFile());
if (!fi.open(QIODevice::WriteOnly)) {
status = KisImportExportFilter::CreationError;
}
else {
status = m_filter->convert(doc, &fi, m_chain->filterManagerExportConfiguration());
fi.close();
}
}
else {
KisDocument *doc = m_chain->outputDocument();
m_filter->setMimeType(m_from);
QFile fi(m_chain->inputFile());
if (!fi.exists() || !fi.open(QIODevice::ReadOnly)) {
status = KisImportExportFilter::FileNotFound;
}
else {
status = m_filter->convert(doc, &fi, m_chain->filterManagerExportConfiguration());
fi.close();
}
}
delete m_filter;
m_filter = 0;
if (m_updater) {
......
......@@ -42,6 +42,7 @@ public:
* it's invalid while constructing the object!
*/
KisFilterChainSP chain;
QByteArray mime;
};
......@@ -83,6 +84,16 @@ KisImportExportFilter::~KisImportExportFilter()
delete d;
}
void KisImportExportFilter::setMimeType(QByteArray mime)
{
d->mime = mime;
}
QByteArray KisImportExportFilter::mimeType() const
{
return d->mime;
}
void KisImportExportFilter::setChain(KisFilterChainSP chain)
{
d->chain = chain;
......
......@@ -22,6 +22,7 @@ Boston, MA 02110-1301, USA.
#define KIS_IMPORT_EXPORT_FILTER_H
#include <QObject>
#include <QIODevice>
#include <QMap>
#include <QPointer>
#include <QString>
......@@ -98,6 +99,9 @@ public:
virtual ~KisImportExportFilter();
void setMimeType(QByteArray mime);
QByteArray mimeType() const;
/**
* @brief setChain set the chain information on the filter. The chain information
* lets the filter know what document it's working on. The filter will not delete
......@@ -116,7 +120,7 @@ public:
* @return The error status, see the @ref #ConversionStatus enum.
* KisImportExportFilter::OK means that everything is alright.
*/
virtual ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0) = 0;
virtual ConversionStatus convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration = 0) = 0;
/**
* Set the updater to which the filter will report progress.
......
......@@ -412,10 +412,6 @@ void _flush_fn(png_structp png_ptr)
KisImageBuilder_Result KisPNGConverter::buildImage(QIODevice* iod)
{
dbgFile << "Start decoding PNG File";
if (!iod->open(QIODevice::ReadOnly)) {
dbgFile << "Failed to open PNG File";
return (KisImageBuilder_RESULT_FAILURE);
}
png_byte signature[8];
iod->peek((char*)signature, 8);
......@@ -665,7 +661,7 @@ png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments);
} else if (key == "description") {
info->setAboutInfo("comment", text_ptr[i].text);
} else if (key == "author") {
qDebug()<<"Author:"<<text_ptr[i].text;
qDebug()<<"Author:"<<text_ptr[i].text;
info->setAuthorInfo("creator", text_ptr[i].text);
} else if (key.contains("Raw profile type exif")) {
decode_meta_data(text_ptr + i, layer->metaData(), "exif", 6);
......@@ -821,6 +817,11 @@ KisImageBuilder_Result KisPNGConverter::buildImage(const QString &filename)
QFile fp(filename);
if (fp.exists()) {
if (!fp.open(QIODevice::ReadOnly)) {
dbgFile << "Failed to open PNG File";
return (KisImageBuilder_RESULT_FAILURE);
}
return buildImage(&fp);
}
return (KisImageBuilder_RESULT_NOT_EXIST);
......@@ -877,6 +878,11 @@ KisImageBuilder_Result KisPNGConverter::buildFile(const QString &filename, const
dbgFile << "Start writing PNG File " << filename;
// Open a QIODevice for writing
QFile fp (filename);
if (!fp.open(QIODevice::WriteOnly)) {
dbgFile << "Failed to open PNG File for writing";
return (KisImageBuilder_RESULT_FAILURE);
}
KisImageBuilder_Result result = buildFile(&fp, imageRect, xRes, yRes, device, annotationsStart, annotationsEnd, options, metaData);
return result;
......@@ -884,11 +890,6 @@ KisImageBuilder_Result KisPNGConverter::buildFile(const QString &filename, const
KisImageBuilder_Result KisPNGConverter::buildFile(QIODevice* iodevice, const QRect &imageRect, const qreal xRes, const qreal yRes, KisPaintDeviceSP device, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, KisPNGOptions options, KisMetaData::Store* metaData)
{
if (!iodevice->open(QIODevice::WriteOnly)) {
dbgFile << "Failed to open PNG File for writing";
return (KisImageBuilder_RESULT_FAILURE);
}
if (!device)
return KisImageBuilder_RESULT_INVALID_ARG;
......@@ -1022,9 +1023,9 @@ KisImageBuilder_Result KisPNGConverter::buildFile(QIODevice* iodevice, const QRe
* This automatically writes the correct gamma and chroma chunks along with the sRGB chunk, but firefox's
* color management is bugged, so once you give it any incentive to start color managing an sRGB image it
* will turn, for example, a nice desaturated rusty red into bright poppy red. So this is disabled for now.
*/
*/
/*if (!options.saveSRGBProfile && sRGB) {
png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);
png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);
}*/
// set the palette
if (color_type == PNG_COLOR_TYPE_PALETTE) {
......
......@@ -121,11 +121,19 @@ void AnimaterionRenderer::slotRenderAnimation()
KisFilterChainSP chain(new KisFilterChain(doc->importExportManager()));
chain->setOutputFile(videoConfig->getString("filename"));
encoder->setChain(chain);
KisImportExportFilter::ConversionStatus res = encoder->convert(KisDocument::nativeFormatMimeType(), encoderConfig->getString("mimetype").toLatin1(), encoderConfig);
QFile fi(videoConfig->getString("filename"));
KisImportExportFilter::ConversionStatus res;
if (!fi.open(QIODevice::WriteOnly)) {
qWarning() << "Could not open" << fi.fileName() << "for writing!";
res = KisImportExportFilter::CreationError;
}
else {
res = encoder->convert(doc, &fi, encoderConfig);
fi.close();
}
if (res != KisImportExportFilter::OK) {
QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not render animation:\n%1", doc->errorMessage()));
}
if (videoConfig->getBool("delete_sequence", false)) {
QDir d(sequenceConfig->getString("directory"));
QStringList sequenceFiles = d.entryList(QStringList() << sequenceConfig->getString("basename") + "*." + extension, QDir::Files);
......
......@@ -43,26 +43,11 @@ KisBMPExport::~KisBMPExport()
{
}
KisImportExportFilter::ConversionStatus KisBMPExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration)
KisImportExportFilter::ConversionStatus KisBMPExport::convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP /*configuration*/)
{
dbgFile << "BMP export! From:" << from << ", To:" << to << "";
KisDocument *input = inputDocument();
QString filename = outputFile();
if (!input)
return KisImportExportFilter::NoDocumentCreated;
if (filename.isEmpty()) return KisImportExportFilter::FileNotFound;
if (from != "application/x-krita")
return KisImportExportFilter::NotImplemented;
QRect rc = input->image()->bounds();
// the image must be locked at the higher levels
KIS_SAFE_ASSERT_RECOVER_NOOP(input->image()->locked());
QImage image = input->image()->projection()->convertToQImage(0, 0, 0, rc.width(), rc.height(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags());
image.save(filename);
QRect rc = document->image()->bounds();
QImage image = document->image()->projection()->convertToQImage(0, 0, 0, rc.width(), rc.height(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags());
image.save(io, QFileInfo(outputFile()).suffix().toLatin1());
return KisImportExportFilter::OK;
}
......
......@@ -31,7 +31,7 @@ public:
KisBMPExport(QObject *parent, const QVariantList &);
virtual ~KisBMPExport();
public:
virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0);
virtual KisImportExportFilter::ConversionStatus convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration = 0);
};
#endif
......@@ -50,40 +50,22 @@ KisBMPImport::~KisBMPImport()
{
}
KisImportExportFilter::ConversionStatus KisBMPImport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration)
KisImportExportFilter::ConversionStatus KisBMPImport::convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP /*configuration*/)
{
dbgFile << "BMP import! From:" << from << ", To:" << to << 0;
if (to != "application/x-krita")
return KisImportExportFilter::BadMimeType;
KisDocument * doc = outputDocument();
if (!doc)
return KisImportExportFilter::NoDocumentCreated;
QString filename = inputFile();
if (!filename.isEmpty()) {
QFileInfo fi(filename);
if (!fi.exists()) {
return KisImportExportFilter::FileNotFound;
}
QImage img(filename);
QImage img;
if (!img.loadFromData(io->readAll())) {
return KisImportExportFilter::InvalidFormat;
}
const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8();
KisImageSP image = new KisImage(doc->createUndoStore(), img.width(), img.height(), colorSpace, "imported from bmp");
const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8();
KisImageSP image = new KisImage(document->createUndoStore(), img.width(), img.height(), colorSpace, i18n("Imported Image"));
KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255);
layer->paintDevice()->convertFromQImage(img, 0, 0, 0);
image->addNode(layer.data(), image->rootLayer().data());
KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255);
layer->paintDevice()->convertFromQImage(img, 0, 0, 0);
image->addNode(layer.data(), image->rootLayer().data());
doc->setCurrentImage(image);
return KisImportExportFilter::OK;
}
return KisImportExportFilter::StorageCreationError;
document->setCurrentImage(image);
return KisImportExportFilter::OK;
}
......
......@@ -31,7 +31,7 @@ public:
KisBMPImport(QObject *parent, const QVariantList &);
virtual ~KisBMPImport();
public:
virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0);
virtual KisImportExportFilter::ConversionStatus convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration = 0);
};
#endif
......@@ -62,38 +62,28 @@ KisBrushExport::~KisBrushExport()
{
}
KisImportExportFilter::ConversionStatus KisBrushExport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration)
KisImportExportFilter::ConversionStatus KisBrushExport::convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP /*configuration*/)
{
KisDocument *input = inputDocument();
QString filename = outputFile();
if (!input)
return KisImportExportFilter::NoDocumentCreated;
if (filename.isEmpty()) return KisImportExportFilter::FileNotFound;
if (from != "application/x-krita")
return KisImportExportFilter::NotImplemented;
KisAnnotationSP annotation = input->image()->annotation("ImagePipe Parasite");
KisPipeBrushParasite parasite;
if (annotation) {
QBuffer buf(const_cast<QByteArray*>(&annotation->annotation()));
buf.open(QBuffer::ReadOnly);
//parasite.loadFromDevice(&buf);
buf.close();
}
// XXX: Loading the parasite itself was commented out -- needs investigation
// KisAnnotationSP annotation = document->image()->annotation("ImagePipe Parasite");
// KisPipeBrushParasite parasite;
// if (annotation) {
// QBuffer buf(const_cast<QByteArray*>(&annotation->annotation()));
// buf.open(QBuffer::ReadOnly);
// parasite.loadFromDevice(&buf);
// buf.close();
// }
KisBrushExportOptions exportOptions;
exportOptions.spacing = 1.0;
exportOptions.name = input->image()->objectName();
exportOptions.name = document->image()->objectName();
exportOptions.mask = true;
exportOptions.selectionMode = 0;
exportOptions.brushStyle = 0;
if (input->image()->dynamicPropertyNames().contains("brushspacing")) {
exportOptions.spacing = input->image()->property("brushspacing").toFloat();
if (document->image()->dynamicPropertyNames().contains("brushspacing")) {
exportOptions.spacing = document->image()->property("brushspacing").toFloat();
}
KisGbrBrush *brush = 0;
......@@ -111,12 +101,12 @@ KisImportExportFilter::ConversionStatus KisBrushExport::convert(const QByteArray
dlgBrushExportOptions->setMainWidget(wdg);
if (to == "image/x-gimp-brush") {
brush = new KisGbrBrush(filename);
if (mimeType() == "image/x-gimp-brush") {
brush = new KisGbrBrush(outputFile());
wdgUi.groupBox->setVisible(false);
}
else if (to == "image/x-gimp-brush-animated") {
brush = new KisImagePipeBrush(filename);
else if (mimeType() == "image/x-gimp-brush-animated") {
brush = new KisImagePipeBrush(outputFile());
wdgUi.groupBox->setVisible(true);
}
else {
......@@ -142,16 +132,16 @@ KisImportExportFilter::ConversionStatus KisBrushExport::convert(const QByteArray
}
// the image must be locked at the higher levels
KIS_SAFE_ASSERT_RECOVER_NOOP(input->image()->locked());
KIS_SAFE_ASSERT_RECOVER_NOOP(document->image()->locked());
QRect rc = input->image()->bounds();
QRect rc = document->image()->bounds();
brush->setName(exportOptions.name);
brush->setSpacing(exportOptions.spacing);
brush->setUseColorAsMask(exportOptions.mask);
int w = input->image()->width();
int h = input->image()->height();
int w = document->image()->width();
int h = document->image()->height();
KisImagePipeBrush *pipeBrush = dynamic_cast<KisImagePipeBrush*>(brush);
if (pipeBrush) {
......@@ -161,13 +151,12 @@ KisImportExportFilter::ConversionStatus KisBrushExport::convert(const QByteArray
KoProperties properties;
properties.setProperty("visible", true);
QList<KisNodeSP> layers = input->image()->root()->childNodes(QStringList("KisLayer"), properties);
KisNodeSP node;
QList<KisNodeSP> layers = document->image()->root()->childNodes(QStringList("KisLayer"), properties);
Q_FOREACH (KisNodeSP node, layers) {
devices[0].push_back(node->projection().data());
}
QVector<KisParasite::SelectionMode > modes;
switch (exportOptions.selectionMode) {
case 0: modes.push_back(KisParasite::Constant); break;
......@@ -192,17 +181,14 @@ KisImportExportFilter::ConversionStatus KisBrushExport::convert(const QByteArray
pipeBrush->setDevices(devices, w, h);
}
else {
QImage image = input->image()->projection()->convertToQImage(0, 0, 0, rc.width(), rc.height(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags());
QImage image = document->image()->projection()->convertToQImage(0, 0, 0, rc.width(), rc.height(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags());
brush->setImage(image);
}
brush->setWidth(w);
brush->setHeight(h);
QFile f(filename);
f.open(QIODevice::WriteOnly);
brush->saveToDevice(&f);
f.close();
brush->saveToDevice(io);
return KisImportExportFilter::OK;
}
......
......@@ -31,7 +31,7 @@ public:
KisBrushExport(QObject *parent, const QVariantList &);
virtual ~KisBrushExport();
public:
virtual KisImportExportFilter::ConversionStatus convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration = 0);
virtual KisImportExportFilter::ConversionStatus convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration = 0);
};
#endif
......@@ -56,92 +56,69 @@ KisBrushImport::~KisBrushImport()
}
KisImportExportFilter::ConversionStatus KisBrushImport::convert(const QByteArray& from, const QByteArray& to, KisPropertiesConfigurationSP configuration)
KisImportExportFilter::ConversionStatus KisBrushImport::convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP /*configuration*/)
{
if (to != "application/x-krita")
return KisImportExportFilter::BadMimeType;
QString filename = inputFile();
if (!filename.isEmpty()) {
if (!QFile(filename).exists()) {
return KisImportExportFilter::FileNotFound;
}
KisBrush *brush;
if (mimeType() == "image/x-gimp-brush") {
brush = new KisGbrBrush(inputFile());
}
else if (mimeType() == "image/x-gimp-brush-animated") {
brush = new KisImagePipeBrush(inputFile());
}
else {
return KisImportExportFilter::BadMimeType;
}
KisBrush *brush;
if (from == "image/x-gimp-brush") {
brush = new KisGbrBrush(filename);
}
else if (from == "image/x-gimp-brush-animated") {
brush = new KisImagePipeBrush(filename);
}
else {
return KisImportExportFilter::BadMimeType;
}
if (!brush->load()) {
delete brush;
return KisImportExportFilter::InvalidFormat;
}
if (!brush->valid()) {
delete brush;
return KisImportExportFilter::InvalidFormat;
}
KisDocument * doc = outputDocument();
if (!brush->loadFromDevice(io)) {
delete brush;
return KisImportExportFilter::InvalidFormat;
}
if (!doc) {
delete brush;
return KisImportExportFilter::NoDocumentCreated;
}
if (!brush->valid()) {
delete brush;
return KisImportExportFilter::InvalidFormat;
}
const KoColorSpace *colorSpace = 0;
if (brush->hasColor()) {
colorSpace = KoColorSpaceRegistry::instance()->rgb8();
}
else {
colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), "");
}
const KoColorSpace *colorSpace = 0;
if (brush->hasColor()) {
colorSpace = KoColorSpaceRegistry::instance()->rgb8();
}
else {
colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), "");
}
KisImageWSP image = new KisImage(doc->createUndoStore(), brush->width(), brush->height(), colorSpace, brush->name());
image->setProperty("brushspacing", brush->spacing());
KisImagePipeBrush *pipeBrush = dynamic_cast<KisImagePipeBrush*>(brush);
if (pipeBrush) {
QVector<KisGbrBrush*> brushes = pipeBrush->brushes();
for(int i = brushes.size(); i > 0; i--) {
KisGbrBrush *subbrush = brushes.at(i - 1);
const KoColorSpace *subColorSpace = 0;
if (brush->hasColor()) {
subColorSpace = KoColorSpaceRegistry::instance()->rgb8();
}
else {
subColorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), Integer8BitsColorDepthID.id(), "");
}
KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255, subColorSpace);
layer->paintDevice()->convertFromQImage(subbrush->brushTipImage(), 0, 0, 0);
image->addNode(layer, image->rootLayer());
KisImageWSP image = new KisImage(document->createUndoStore(), brush->width(), brush->height(), colorSpace, brush->name());
image->setProperty("brushspacing", brush->spacing());
KisImagePipeBrush *pipeBrush = dynamic_cast<KisImagePipeBrush*>(brush);
if (pipeBrush) {
QVector<KisGbrBrush*> brushes = pipeBrush->brushes();
for(int i = brushes.size(); i > 0; i--) {
KisGbrBrush *subbrush = brushes.at(i - 1);
const KoColorSpace *subColorSpace = 0;
if (brush->hasColor()) {
subColorSpace = KoColorSpaceRegistry::instance()->rgb8();
}
KisAnnotationSP ann = new KisAnimatedBrushAnnotation(pipeBrush->parasite());
image->addAnnotation(ann);
}
else {
KisPaintLayerSP layer = new KisPaintLayer(image, image->