1 /*
2  *  Copyright (c) 2014 Boudewijn Rempt <boud@valdyas.org>
3  *  Copyright (c) 2017 Victor Wåhlström <victor.wahlstrom@initiali.se>
4  *
5  *  This library is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU Lesser General Public License as published by
7  *  the Free Software Foundation; either version 2.1 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include "kis_heightmap_import.h"
22 
23 #include <ctype.h>
24 
25 #include <QApplication>
26 #include <qendian.h>
27 
28 #include <kpluginfactory.h>
29 #include <KoDialog.h>
30 
31 #include <KisImportExportManager.h>
32 #include <KoColorSpaceRegistry.h>
33 #include <KoColorModelStandardIds.h>
34 #include <KoColorSpace.h>
35 #include <KoColorSpaceTraits.h>
36 
37 #include <kis_debug.h>
38 #include <KisDocument.h>
39 #include <kis_group_layer.h>
40 #include <kis_image.h>
41 #include <kis_paint_layer.h>
42 #include <kis_paint_device.h>
43 #include <kis_transaction.h>
44 #include <kis_iterator_ng.h>
45 #include <kis_random_accessor_ng.h>
46 #include <kis_config.h>
47 
48 #include "kis_wdg_options_heightmap.h"
49 #include "kis_heightmap_utils.h"
50 
51 K_PLUGIN_FACTORY_WITH_JSON(HeightMapImportFactory, "krita_heightmap_import.json", registerPlugin<KisHeightMapImport>();)
52 
53 template<typename T>
fillData(KisPaintDeviceSP pd,int w,int h,QDataStream & stream)54 void fillData(KisPaintDeviceSP pd, int w, int h, QDataStream &stream) {
55     KIS_ASSERT_RECOVER_RETURN(pd);
56 
57     T pixel;
58 
59     for (int i = 0; i < h; ++i) {
60         KisHLineIteratorSP it = pd->createHLineIteratorNG(0, i, w);
61         do {
62             stream >> pixel;
63             KoGrayTraits<T>::setGray(it->rawData(), pixel);
64             KoGrayTraits<T>::setOpacity(it->rawData(), OPACITY_OPAQUE_F, 1);
65         } while(it->nextPixel());
66     }
67 }
68 
KisHeightMapImport(QObject * parent,const QVariantList &)69 KisHeightMapImport::KisHeightMapImport(QObject *parent, const QVariantList &) : KisImportExportFilter(parent)
70 {
71 }
72 
~KisHeightMapImport()73 KisHeightMapImport::~KisHeightMapImport()
74 {
75 }
76 
convert(KisDocument * document,QIODevice * io,KisPropertiesConfigurationSP configuration)77 KisImportExportErrorCode KisHeightMapImport::convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration)
78 {
79     Q_UNUSED(configuration);
80     KoID depthId = KisHeightmapUtils::mimeTypeToKoID(mimeType());
81     if (depthId.id().isNull()) {
82         document->setErrorMessage(i18n("Unknown file type"));
83         return ImportExportCodes::FileFormatIncorrect;
84     }
85 
86     int w = 0;
87     int h = 0;
88 
89     KIS_ASSERT(io->isOpen());
90     const quint64 size = io->size();
91     if (size == 0) {
92         return ImportExportCodes::FileFormatIncorrect;
93     }
94 
95     QDataStream::ByteOrder bo = QDataStream::LittleEndian;
96 
97     if (!batchMode()) {
98         QApplication::restoreOverrideCursor();
99 
100         KoDialog* kdb = new KoDialog(qApp->activeWindow());
101         kdb->setWindowTitle(i18n("Heightmap Import Options"));
102         kdb->setButtons(KoDialog::Ok | KoDialog::Cancel);
103 
104         KisWdgOptionsHeightmap* wdg = new KisWdgOptionsHeightmap(kdb);
105 
106         kdb->setMainWidget(wdg);
107 
108         connect(wdg, SIGNAL(statusUpdated(bool)), kdb, SLOT(enableButtonOk(bool)));
109 
110         KisConfig config(true);
111 
112         QString filterConfig = config.importConfiguration(mimeType());
113         KisPropertiesConfigurationSP cfg(new KisPropertiesConfiguration);
114         cfg->fromXML(filterConfig);
115 
116 
117         int endianness = cfg->getInt("endianness", 1);
118         if (endianness == 0) {
119             wdg->radioBig->setChecked(true);
120         }
121         else {
122             wdg->radioLittle->setChecked(true);
123         }
124 
125         wdg->fileSizeLabel->setText(QString::number(size));
126 
127         if(depthId == Integer8BitsColorDepthID) {
128             wdg->bppLabel->setText(QString::number(8));
129             wdg->typeLabel->setText("Integer");
130         }
131         else if(depthId == Integer16BitsColorDepthID) {
132             wdg->bppLabel->setText(QString::number(16));
133             wdg->typeLabel->setText("Integer");
134         }
135         else if(depthId == Float32BitsColorDepthID) {
136             wdg->bppLabel->setText(QString::number(32));
137             wdg->typeLabel->setText("Float");
138         }
139         else {
140             KIS_ASSERT_RECOVER_RETURN_VALUE(true, ImportExportCodes::InternalError);
141             return ImportExportCodes::InternalError;
142         }
143 
144         if (kdb->exec() == QDialog::Rejected) {
145             return ImportExportCodes::Cancelled;
146         }
147 
148         cfg->setProperty("endianness", wdg->radioBig->isChecked() ? 0 : 1);
149 
150         config.setImportConfiguration(mimeType(), cfg);
151 
152         w = wdg->widthInput->value();
153         h = wdg->heightInput->value();
154 
155         bo = QDataStream::LittleEndian;
156         cfg->setProperty("endianness", 1);
157         if (wdg->radioBig->isChecked()) {
158             bo = QDataStream::BigEndian;
159             cfg->setProperty("endianness", 0);
160         }
161         KisConfig(true).setExportConfiguration(mimeType(), cfg);
162 
163     } else {
164         const int pixelSize =
165             depthId == Float32BitsColorDepthID ? 4 :
166             depthId == Integer16BitsColorDepthID ? 2 : 1;
167 
168         const int numPixels = size / pixelSize;
169 
170         w = std::sqrt(numPixels);
171         h = numPixels / w;
172         bo = QDataStream::LittleEndian;
173     }
174 
175 
176     QDataStream s(io);
177     s.setByteOrder(bo);
178     // needed for 32bit float data
179     s.setFloatingPointPrecision(QDataStream::SinglePrecision);
180 
181     const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(GrayAColorModelID.id(), depthId.id(), "Gray-D50-elle-V2-srgbtrc.icc");
182     KisImageSP image = new KisImage(document->createUndoStore(), w, h, colorSpace, "imported heightmap");
183     KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), 255);
184 
185     if (depthId == Float32BitsColorDepthID) {
186         fillData<float>(layer->paintDevice(), w, h, s);
187     }
188     else if (depthId == Integer16BitsColorDepthID) {
189         fillData<quint16>(layer->paintDevice(), w, h, s);
190     }
191     else if (depthId == Integer8BitsColorDepthID) {
192         fillData<quint8>(layer->paintDevice(), w, h, s);
193     }
194     else {
195         KIS_ASSERT_RECOVER_RETURN_VALUE(true, ImportExportCodes::InternalError);
196         return ImportExportCodes::InternalError;
197     }
198 
199     image->addNode(layer.data(), image->rootLayer().data());
200     document->setCurrentImage(image);
201     return ImportExportCodes::OK;
202 }
203 
204 #include "kis_heightmap_import.moc"
205