Commit 59a2e1f3 authored by Boudewijn Rempt's avatar Boudewijn Rempt

Replace our own ppm filter with the qimageio filter

BUG:409714

This means we no longer load 16 bit ppm files, but that should
be fixed in a next commit, since QImage supports 16 bit these
days.
parent 4f769aa4
......@@ -349,7 +349,6 @@ set(kritaui_LIB_SRCS
KisCloneDocumentStroke.cpp
kis_node_view_color_scheme.cpp
KisImportExportFilter.cpp
KisFilterEntry.cpp
KisImportExportManager.cpp
KisImportExportUtils.cpp
kis_async_action_feedback.cpp
......
/* This file is part of the KDE project
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
Copyright 2007 David Faure <faure@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "KisFilterEntry.h"
#include "KisDocument.h"
#include "KisImportExportFilter.h"
#include <kis_debug.h>
#include <KoJsonTrader.h>
#include <kpluginfactory.h>
#include <QFile>
#include <limits.h> // UINT_MAX
KisFilterEntry::KisFilterEntry(QPluginLoader *loader)
: KisShared()
, m_loader(loader)
{
import = loader->metaData().value("MetaData").toObject().value("X-KDE-Import").toString().split(',');
export_ = loader->metaData().value("MetaData").toObject().value("X-KDE-Export").toString().split(',');
int w = loader->metaData().value("MetaData").toObject().value("X-KDE-Weight").toString().toInt();
weight = w < 0 ? UINT_MAX : static_cast<unsigned int>(w);
available = loader->metaData().value("MetaData").toObject().value("X-KDE-Available").toString();
}
KisFilterEntry::~KisFilterEntry()
{
delete m_loader;
}
QList<KisFilterEntrySP> KisFilterEntry::query()
{
QList<KisFilterEntrySP> lst;
QList<QPluginLoader *> offers = KoJsonTrader::instance()->query("Krita/FileFilter", QString());
unsigned int max = offers.count();
dbgFile <<"Query returned" << max <<" offers";
Q_FOREACH(QPluginLoader *pluginLoader, offers) {
//dbgFile <<" desktopEntryPath=" << (*it)->entryPath()
// << " library=" << (*it)->library() << endl;
// Append converted offer
lst.append(KisFilterEntrySP(new KisFilterEntry(pluginLoader)));
}
return lst;
}
KisImportExportFilter* KisFilterEntry::createFilter()
{
KLibFactory *factory = qobject_cast<KLibFactory *>(m_loader->instance());
if (!factory) {
warnUI << m_loader->errorString();
return 0;
}
QObject *obj = factory->create<KisImportExportFilter>(0);
if (!obj || !obj->inherits("KisImportExportFilter")) {
delete obj;
return 0;
}
KisImportExportFilter* filter = static_cast<KisImportExportFilter*>(obj);
return filter;
}
/* This file is part of the KDE project
Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
Copyright 2007 David Faure <faure@kde.org>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KIS_FILTER_ENTRY_H
#define KIS_FILTER_ENTRY_H
#include <QList>
#include <QStringList>
#include "kis_types.h"
#include "kis_shared.h"
#include "kis_shared_ptr.h"
#include "kritaui_export.h"
class QObject;
class QPluginLoader;
class KisImportExportFilter;
class KisFilterEntry;
typedef KisSharedPtr<KisFilterEntry> KisFilterEntrySP;
/**
* Represents an available filter.
*/
class KRITAUI_EXPORT KisFilterEntry : public KisShared
{
public:
//KisFilterEntry() : weight( 0 ) { m_service = 0; } // for QList
explicit KisFilterEntry(QPluginLoader *loader);
~KisFilterEntry();
KisImportExportFilter *createFilter();
/**
* The imported mimetype(s).
*/
QStringList import;
/**
* The exported mimetype(s).
*/
QStringList export_;
/**
* The "weight" of this filter path. Has to be > 0 to be valid.
*/
unsigned int weight;
/**
* Do we have to check during runtime?
*/
QString available;
/**
* @return TRUE if the filter can import the requested mimetype.
*/
bool imports(const QString& _mimetype) const {
return (import.contains(_mimetype));
}
/**
* @return TRUE if the filter can export the requested mimetype.
*/
bool exports(const QString& _m) const {
return (export_.contains(_m));
}
/**
* This function will query KDED to find all available filters.
*/
static QList<KisFilterEntrySP> query();
QPluginLoader *loader() const {
return m_loader;
}
private:
QPluginLoader *m_loader;
};
#endif
......@@ -34,7 +34,6 @@ endif()
add_subdirectory(svg)
add_subdirectory(qimageio)
add_subdirectory(ora)
add_subdirectory(ppm)
add_subdirectory(xcf)
add_subdirectory(psd)
add_subdirectory(qml)
......
add_subdirectory(tests)
include_directories( ${CMAKE_CURRENT_SOURCE_DIR} )
set(kritappmimport_SOURCES
kis_ppm_import.cpp
)
add_library(kritappmimport MODULE ${kritappmimport_SOURCES})
target_link_libraries(kritappmimport kritaui )
install(TARGETS kritappmimport DESTINATION ${KRITA_PLUGIN_INSTALL_DIR})
set(kritappmexport_SOURCES
kis_ppm_export.cpp
)
ki18n_wrap_ui(kritappmexport_SOURCES kis_wdg_options_ppm.ui )
add_library(kritappmexport MODULE ${kritappmexport_SOURCES})
target_link_libraries(kritappmexport kritaui kritaimpex)
install(TARGETS kritappmexport DESTINATION ${KRITA_PLUGIN_INSTALL_DIR})
install( PROGRAMS krita_ppm.desktop DESTINATION ${XDG_APPS_INSTALL_DIR})
This diff is collapsed.
/*
* Copyright (c) 2009 Cyrille Berger <cberger@cberger.net>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 2 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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.
*/
#ifndef _KIS_PPM_EXPORT_H_
#define _KIS_PPM_EXPORT_H_
#include <QVariant>
#include <KisImportExportFilter.h>
#include <kis_config_widget.h>
#include "ui_kis_wdg_options_ppm.h"
class KisWdgOptionsPPM : public KisConfigWidget, public Ui::WdgOptionsPPM
{
Q_OBJECT
public:
KisWdgOptionsPPM(QWidget *parent)
: KisConfigWidget(parent)
{
setupUi(this);
}
void setConfiguration(const KisPropertiesConfigurationSP cfg) override;
KisPropertiesConfigurationSP configuration() const override;
};
class KisPPMExport : public KisImportExportFilter
{
Q_OBJECT
public:
KisPPMExport(QObject *parent, const QVariantList &);
~KisPPMExport() override;
public:
KisImportExportErrorCode convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration = 0) override;
KisPropertiesConfigurationSP defaultConfiguration(const QByteArray& from = "", const QByteArray& to = "") const override;
KisConfigWidget *createConfigurationWidget(QWidget *parent, const QByteArray& from = "", const QByteArray& to = "") const override;
void initializeCapabilities() override;
};
#endif
/*
* Copyright (c) 2009 Cyrille Berger <cberger@cberger.net>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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 "kis_ppm_import.h"
#include <ctype.h>
#include <QApplication>
#include <QFile>
#include <kpluginfactory.h>
#include <QFileInfo>
#include <KoColorSpaceRegistry.h>
#include <kis_debug.h>
#include <KisDocument.h>
#include <kis_group_layer.h>
#include <kis_image.h>
#include <kis_paint_layer.h>
#include <KoColorSpaceTraits.h>
#include <kis_paint_device.h>
#include <kis_transaction.h>
#include <KoColorSpace.h>
#include <qendian.h>
#include <KoColorModelStandardIds.h>
#include "kis_iterator_ng.h"
K_PLUGIN_FACTORY_WITH_JSON(PPMImportFactory, "krita_ppm_import.json", registerPlugin<KisPPMImport>();)
KisPPMImport::KisPPMImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent)
{
}
KisPPMImport::~KisPPMImport()
{
}
int readNumber(QIODevice* device)
{
char c;
int val = 0;
while (true) {
if (!device->getChar(&c)) break; // End of the file
if (isdigit(c)) {
val = 10 * val + c - '0';
} else if (c == '#') {
device->readLine();
break;
} else if (isspace((uchar) c)) {
break;
}
}
return val;
}
class KisPpmFlow
{
public:
KisPpmFlow() {
}
virtual ~KisPpmFlow() {
}
virtual void nextRow() = 0;
virtual bool valid() = 0;
virtual bool nextUint1() = 0;
virtual quint8 nextUint8() = 0;
virtual quint16 nextUint16() = 0;
};
class KisAsciiPpmFlow : public KisPpmFlow
{
public:
KisAsciiPpmFlow(QIODevice* device) : m_device(device) {
}
~KisAsciiPpmFlow() override {
}
void nextRow() override {
}
bool valid() override {
return !m_device->atEnd();
}
bool nextUint1() override {
return readNumber(m_device) == 1;
}
quint8 nextUint8() override {
return readNumber(m_device);
}
quint16 nextUint16() override {
return readNumber(m_device);
}
private:
QIODevice* m_device;
};
class KisBinaryPpmFlow : public KisPpmFlow
{
public:
KisBinaryPpmFlow(QIODevice* device, int lineWidth) : m_pos(0), m_device(device), m_lineWidth(lineWidth) {
}
~KisBinaryPpmFlow() override {
}
void nextRow() override {
m_array = m_device->read(m_lineWidth);
m_ptr = m_array.data();
}
bool valid() override {
return m_array.size() == m_lineWidth;
}
bool nextUint1() override {
if (m_pos == 0) {
m_current = nextUint8();
m_pos = 8;
}
bool v = (m_current & 1) == 1;
--m_pos;
m_current = m_current >> 1;
return v;
}
quint8 nextUint8() override {
quint8 v = *reinterpret_cast<quint8*>(m_ptr);
m_ptr += 1;
return v;
}
quint16 nextUint16() override {
quint16 v = *reinterpret_cast<quint16*>(m_ptr);
m_ptr += 2;
return qFromBigEndian(v);
}
private:
int m_pos;
quint8 m_current;
char* m_ptr;
QIODevice* m_device;
QByteArray m_array;
int m_lineWidth;
};
KisImportExportErrorCode KisPPMImport::convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP /*configuration*/)
{
QByteArray array = io->read(2);
if (array.size() < 2) {
return ImportExportCodes::FileFormatIncorrect;
}
// Read the type of the ppm file
enum { Puk, P1, P2, P3, P4, P5, P6 } fileType = Puk; // Puk => unknown
int channels = -1;
bool isAscii = false;
if (array == "P1") {
fileType = P1;
isAscii = true;
channels = 0;
} else if (array == "P2") {
fileType = P2;
channels = 1;
isAscii = true;
} else if (array == "P3") {
fileType = P3;
channels = 3;
isAscii = true;
} else if (array == "P4") {
fileType = P4;
channels = 0;
} else if (array == "P5") { // PGM
fileType = P5;
channels = 1;
} else if (array == "P6") { // PPM
fileType = P6;
channels = 3;
}
Q_ASSERT(channels != -1);
char c; io->getChar(&c);
if (!isspace(c)) {
return ImportExportCodes::FileFormatIncorrect;; // Invalid file, it should have a separator now
}
while (io->peek(1) == "#") {
io->readLine();
}
// Read width
int width = readNumber(io);
int height = readNumber(io);
int maxval = 1;
if (fileType != P1 && fileType != P4) {
maxval = readNumber(io);
}
dbgFile << "Width = " << width << " height = " << height << "maxval = " << maxval;
// Select the colorspace depending on the maximum value
int pixelsize = -1;
const KoColorSpace* colorSpace = 0;
const KoColorProfile *profile = 0;
QString colorSpaceId;
QString bitDepthId;
if (maxval <= 255) {
bitDepthId = Integer8BitsColorDepthID.id();
if (channels == 1 || channels == 0) {
pixelsize = 1;
colorSpaceId = GrayAColorModelID.id();
} else {
pixelsize = 3;
colorSpaceId = RGBAColorModelID.id();
}
} else if (maxval <= 65535) {
bitDepthId = Integer16BitsColorDepthID.id();
if (channels == 1 || channels == 0) {
pixelsize = 2;
colorSpaceId = GrayAColorModelID.id();
} else {
pixelsize = 6;
colorSpaceId = RGBAColorModelID.id();
}
} else {
dbgFile << "Unknown colorspace";
return ImportExportCodes::FormatColorSpaceUnsupported;
}
if (colorSpaceId == RGBAColorModelID.id()) {
profile = KoColorSpaceRegistry::instance()->profileByName("sRGB-elle-V2-srgbtrc.icc");
} else if (colorSpaceId == GrayAColorModelID.id()) {
profile = KoColorSpaceRegistry::instance()->profileByName("Gray-D50-elle-V2-srgbtrc.icc");
}
colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorSpaceId, bitDepthId, profile);
KisImageSP image = new KisImage(document->createUndoStore(), width, height, colorSpace, "built image");
KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255);
QScopedPointer<KisPpmFlow> ppmFlow;
if (isAscii) {
ppmFlow.reset(new KisAsciiPpmFlow(io));
} else {
ppmFlow.reset(new KisBinaryPpmFlow(io, pixelsize * width));
}
for (int v = 0; v < height; ++v) {
KisHLineIteratorSP it = layer->paintDevice()->createHLineIteratorNG(0, v, width);
ppmFlow->nextRow();
if (!ppmFlow->valid()) {
return ImportExportCodes::FileFormatIncorrect;
}
if (maxval <= 255) {
if (channels == 3) {
do {
KoBgrTraits<quint8>::setRed(it->rawData(), ppmFlow->nextUint8());
KoBgrTraits<quint8>::setGreen(it->rawData(), ppmFlow->nextUint8());
KoBgrTraits<quint8>::setBlue(it->rawData(), ppmFlow->nextUint8());
colorSpace->setOpacity(it->rawData(), OPACITY_OPAQUE_U8, 1);
} while (it->nextPixel());
} else if (channels == 1) {
do {
*reinterpret_cast<quint8*>(it->rawData()) = ppmFlow->nextUint8();
colorSpace->setOpacity(it->rawData(), OPACITY_OPAQUE_U8, 1);
} while (it->nextPixel());
} else if (channels == 0) {
do {
if (ppmFlow->nextUint1()) {
*reinterpret_cast<quint8*>(it->rawData()) = 255;
} else {
*reinterpret_cast<quint8*>(it->rawData()) = 0;
}
colorSpace->setOpacity(it->rawData(), OPACITY_OPAQUE_U8, 1);
} while (it->nextPixel());
}
} else {
if (channels == 3) {
do {
KoBgrU16Traits::setRed(it->rawData(), ppmFlow->nextUint16());
KoBgrU16Traits::setGreen(it->rawData(), ppmFlow->nextUint16());
KoBgrU16Traits::setBlue(it->rawData(), ppmFlow->nextUint16());
colorSpace->setOpacity(it->rawData(), OPACITY_OPAQUE_U8, 1);
} while (it->nextPixel());
} else if (channels == 1) {
do {
*reinterpret_cast<quint16*>(it->rawData()) = ppmFlow->nextUint16();
colorSpace->setOpacity(it->rawData(), OPACITY_OPAQUE_U8, 1);
} while (it->nextPixel());
}
}
}
image->addNode(layer.data(), image->rootLayer().data());
document->setCurrentImage(image);
return ImportExportCodes::OK;
}
#include "kis_ppm_import.moc"
/*
* Copyright (c) 2009 Cyrille Berger <cberger@cberger.net>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser 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.
*/
#ifndef _KIS_PPM_IMPORT_H_
#define _KIS_PPM_IMPORT_H_
#include <QVariant>
#include <QIODevice>
#include <KisImportExportFilter.h>
class KisDocument;
class KisPPMImport : public KisImportExportFilter
{
Q_OBJECT
public:
KisPPMImport(QObject *parent, const QVariantList &);
~KisPPMImport() override;
public:
KisImportExportErrorCode convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration = 0) override;
};
#endif
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WdgOptionsPPM</class>
<widget class="QWidget" name="WdgOptionsPPM">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>243</width>
<height>94</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Type:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cmbType">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Binary</string>
</property>
</item>
<item>
<property name="text">
<string>Ascii</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>46</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
[Desktop Entry]
Categories=Qt;KDE;Office;Graphics;
Exec=krita %F