diff --git a/plugins/impex/heif/HeifError.h b/plugins/impex/heif/HeifError.h index 4b6c0ea405..3fd38b018a 100644 --- a/plugins/impex/heif/HeifError.h +++ b/plugins/impex/heif/HeifError.h @@ -1,31 +1,31 @@ /* * Copyright (c) 2018 Dirk Farin * * 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. */ #ifndef HEIF_ERROR_H_ #define HEIF_ERROR_H_ #include -#include "libheif/heif-cxx.h" +#include "libheif/heif_cxx.h" KisImportExportFilter::ConversionStatus setHeifError(KisDocument* document, heif::Error error); #endif diff --git a/plugins/impex/heif/HeifExport.cpp b/plugins/impex/heif/HeifExport.cpp index 2f4629fc95..2faf8660ab 100644 --- a/plugins/impex/heif/HeifExport.cpp +++ b/plugins/impex/heif/HeifExport.cpp @@ -1,269 +1,269 @@ /* * Copyright (c) 2018 Dirk Farin * * 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 "HeifExport.h" #include "HeifError.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_iterator_ng.h" -#include "libheif/heif-cxx.h" +#include "libheif/heif_cxx.h" class KisExternalLayer; K_PLUGIN_FACTORY_WITH_JSON(ExportFactory, "krita_heif_export.json", registerPlugin();) HeifExport::HeifExport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } HeifExport::~HeifExport() { } KisPropertiesConfigurationSP HeifExport::defaultConfiguration(const QByteArray &/*from*/, const QByteArray &/*to*/) const { KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); cfg->setProperty("quality", 50); cfg->setProperty("lossless", true); return cfg; } KisConfigWidget *HeifExport::createConfigurationWidget(QWidget *parent, const QByteArray &/*from*/, const QByteArray &/*to*/) const { return new KisWdgOptionsHeif(parent); } class Writer_QIODevice : public heif::Context::Writer { public: Writer_QIODevice(QIODevice* io) : m_io(io) { } heif_error write(const void* data, size_t size) override { qint64 n = m_io->write((const char*)data,size); if (n != (qint64)size) { QString error = m_io->errorString(); heif_error err = { heif_error_Encoding_error, heif_suberror_Cannot_write_output_data, "Could not write output data" }; return err; } struct heif_error heif_error_ok = { heif_error_Ok, heif_suberror_Unspecified, "Success" }; return heif_error_ok; } private: QIODevice* m_io; }; KisImportExportFilter::ConversionStatus HeifExport::convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration) { KisImageSP image = document->savingImage(); const KoColorSpace *cs = image->colorSpace(); // Convert to 8 bits rgba on saving if (cs->colorModelId() != RGBAColorModelID || cs->colorDepthId() != Integer8BitsColorDepthID) { cs = KoColorSpaceRegistry::instance()->colorSpace(RGBAColorModelID.id(), Integer8BitsColorDepthID.id()); image->convertImageColorSpace(cs, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); } int quality = configuration->getInt("quality", 50); bool lossless = configuration->getBool("lossless", false); bool has_alpha = configuration->getBool(KisImportExportFilter::ImageContainsTransparencyTag, false); KisExifInfoVisitor exivInfoVisitor; exivInfoVisitor.visit(image->rootLayer().data()); QScopedPointer metaDataStore; if (exivInfoVisitor.metaDataCount() == 1) { metaDataStore.reset(new KisMetaData::Store(*exivInfoVisitor.exifInfo())); } else { metaDataStore.reset(new KisMetaData::Store()); } if (!metaDataStore->empty()) { { KisMetaData::IOBackend* exifIO = KisMetaData::IOBackendRegistry::instance()->value("exif"); QBuffer buffer; exifIO->saveTo(metaDataStore.data(), &buffer, KisMetaData::IOBackend::NoHeader); // Or JpegHeader? Or something else? QByteArray data = buffer.data(); // Write the data to the file } { KisMetaData::IOBackend* xmpIO = KisMetaData::IOBackendRegistry::instance()->value("xmp"); QBuffer buffer; xmpIO->saveTo(metaDataStore.data(), &buffer, KisMetaData::IOBackend::NoHeader); // Or JpegHeader? Or something else? QByteArray data = buffer.data(); // Write the data to the file } } // If we want to add information from the document to the metadata, // we should do that here. try { // --- use standard HEVC encoder heif::Encoder encoder(heif_compression_HEVC); encoder.set_lossy_quality(quality); encoder.set_lossless(lossless); // --- convert KisImage to HEIF image --- int width = image->width(); int height = image->height(); heif::Context ctx; heif::Image img; img.create(width,height, heif_colorspace_RGB, heif_chroma_444); img.add_plane(heif_channel_R, width,height, 8); img.add_plane(heif_channel_G, width,height, 8); img.add_plane(heif_channel_B, width,height, 8); uint8_t* ptrR {0}; uint8_t* ptrG {0}; uint8_t* ptrB {0}; uint8_t* ptrA {0}; int strideR,strideG,strideB,strideA; ptrR = img.get_plane(heif_channel_R, &strideR); ptrG = img.get_plane(heif_channel_G, &strideG); ptrB = img.get_plane(heif_channel_B, &strideB); if (has_alpha) { img.add_plane(heif_channel_Alpha, width,height, 8); ptrA = img.get_plane(heif_channel_Alpha, &strideA); } KisPaintDeviceSP pd = image->projection(); for (int y=0; ycreateHLineIteratorNG(0, y, width); for (int x=0; x::red(it->rawData()); ptrG[y*strideG+x] = KoBgrTraits::green(it->rawData()); ptrB[y*strideB+x] = KoBgrTraits::blue(it->rawData()); if (has_alpha) { ptrA[y*strideA+x] = cs->opacityU8(it->rawData()); } it->nextPixel(); } } // --- encode and write image ctx.encode_image(img, encoder); Writer_QIODevice writer(io); ctx.write(writer); } catch (heif::Error err) { return setHeifError(document, err); } return KisImportExportFilter::OK; } void HeifExport::initializeCapabilities() { // This checks before saving for what the file format supports: anything that is supported needs to be mentioned here QList > supportedColorModels; supportedColorModels << QPair() << QPair(RGBAColorModelID, Integer8BitsColorDepthID) /*<< QPair(GrayAColorModelID, Integer8BitsColorDepthID) << QPair(RGBAColorModelID, Integer16BitsColorDepthID) << QPair(GrayAColorModelID, Integer16BitsColorDepthID)*/ ; addSupportedColorModels(supportedColorModels, "HEIF"); } void KisWdgOptionsHeif::setConfiguration(const KisPropertiesConfigurationSP cfg) { chkLossless->setChecked(cfg->getBool("lossless", true)); sliderQuality->setValue(cfg->getInt("quality", 50)); } KisPropertiesConfigurationSP KisWdgOptionsHeif::configuration() const { KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration(); cfg->setProperty("lossless", chkLossless->isChecked()); cfg->setProperty("quality", sliderQuality->value()); return cfg; } void KisWdgOptionsHeif::toggleQualitySlider(bool toggle) { // Disable the quality slider if lossless is true sliderQuality->setEnabled(!toggle); } #include diff --git a/plugins/impex/heif/HeifImport.cpp b/plugins/impex/heif/HeifImport.cpp index d392d645fc..ee77c61683 100644 --- a/plugins/impex/heif/HeifImport.cpp +++ b/plugins/impex/heif/HeifImport.cpp @@ -1,151 +1,151 @@ /* * Copyright (c) 2018 Dirk Farin * * 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 "HeifImport.h" #include "HeifError.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_iterator_ng.h" -#include "libheif/heif-cxx.h" +#include "libheif/heif_cxx.h" K_PLUGIN_FACTORY_WITH_JSON(ImportFactory, "krita_heif_import.json", registerPlugin();) HeifImport::HeifImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent) { } HeifImport::~HeifImport() { } KisImportExportFilter::ConversionStatus HeifImport::convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP /*configuration*/) { // Load the file into memory and decode from there // TODO: There will be a loader-API in libheif that we should use to connect to QIODevice qint64 fileLength = io->bytesAvailable(); char* mem = new char[fileLength]; io->read(mem, fileLength); try { heif::Context ctx; ctx.read_from_memory(mem, fileLength); // decode primary image heif::ImageHandle handle = ctx.get_primary_image_handle(); heif::Image heifimage = handle.decode_image(heif_colorspace_RGB, heif_chroma_444); int width =handle.get_width(); int height=handle.get_height(); bool hasAlpha = handle.has_alpha_channel(); // convert HEIF image to Krita KisDocument int strideR, strideG, strideB, strideA; const uint8_t* imgR = heifimage.get_plane(heif_channel_R, &strideR); const uint8_t* imgG = heifimage.get_plane(heif_channel_G, &strideG); const uint8_t* imgB = heifimage.get_plane(heif_channel_B, &strideB); const uint8_t* imgA = heifimage.get_plane(heif_channel_Alpha, &strideA); const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->rgb8(); KisImageSP image = new KisImage(document->createUndoStore(), width, height, colorSpace, "HEIF image"); KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255); for (int y=0;ypaintDevice()->createHLineIteratorNG(0, y, width); for (int x=0;x::setRed(it->rawData(), imgR[y*strideR+x]); KoBgrTraits::setGreen(it->rawData(), imgG[y*strideG+x]); KoBgrTraits::setBlue(it->rawData(), imgB[y*strideB+x]); if (hasAlpha) { colorSpace->setOpacity(it->rawData(), quint8(imgA[y*strideA+x]), 1); } else { colorSpace->setOpacity(it->rawData(), OPACITY_OPAQUE_U8, 1); } it->nextPixel(); } } image->addNode(layer.data(), image->rootLayer().data()); // Read exif information { KisMetaData::IOBackend* exifIO = KisMetaData::IOBackendRegistry::instance()->value("exif"); // The exif data should be copied into the byte array QByteArray ba; QBuffer buf(&ba); exifIO->loadFrom(layer->metaData(), &buf); } // Read XMP information { KisMetaData::IOBackend* xmpIO = KisMetaData::IOBackendRegistry::instance()->value("xmp"); // The xmp data should be copied into the byte array QByteArray ba; QBuffer buf(&ba); xmpIO->loadFrom(layer->metaData(), &buf); } delete[] mem; document->setCurrentImage(image); return KisImportExportFilter::OK; } catch (heif::Error err) { delete[] mem; return setHeifError(document, err); } } #include