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