1 /**************************************************************************
2 ** **
3 ** Copyright (C) 2018 Lukas Spies **
4 ** Contact: http://photoqt.org **
5 ** **
6 ** This file is part of PhotoQt. **
7 ** **
8 ** PhotoQt is free software: you can redistribute it and/or modify **
9 ** it under the terms of the GNU General Public License as published by **
10 ** the Free Software Foundation, either version 2 of the License, or **
11 ** (at your option) any later version. **
12 ** **
13 ** PhotoQt is distributed in the hope that it will be useful, **
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of **
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the **
16 ** GNU General Public License for more details. **
17 ** **
18 ** You should have received a copy of the GNU General Public License **
19 ** along with PhotoQt. If not, see <http://www.gnu.org/licenses/>. **
20 ** **
21 **************************************************************************/
22
23 #include "manipulation.h"
24
GetAndDoStuffManipulation(QObject * parent)25 GetAndDoStuffManipulation::GetAndDoStuffManipulation(QObject *parent) : QObject(parent) { }
~GetAndDoStuffManipulation()26 GetAndDoStuffManipulation::~GetAndDoStuffManipulation() { }
27
canBeScaled(QString filename)28 bool GetAndDoStuffManipulation::canBeScaled(QString filename) {
29
30 // These image formats known by exiv2 are also supported by PhotoQt
31 QStringList formats;
32 formats << "jpeg"
33 << "jpg"
34 << "tif"
35 << "tiff"
36 << "png"
37 << "psd"
38 << "jpeg2000"
39 << "jp2"
40 << "jpc"
41 << "j2k"
42 << "jpf"
43 << "jpx"
44 << "jpm"
45 << "mj2"
46 << "bmp"
47 << "bitmap"
48 << "gif"
49 << "tga";
50
51 return formats.contains(QFileInfo(filename).suffix().toLower());
52
53 }
54
scaleImage(QString filename,int width,int height,int quality,QString newfilename)55 bool GetAndDoStuffManipulation::scaleImage(QString filename, int width, int height, int quality, QString newfilename) {
56
57 if(qgetenv("PHOTOQT_DEBUG") == "yes")
58 LOG << CURDATE << "GetAndDoStuffManipulation::scaleImage() - " << filename.toStdString() << " / " << width << " / " << height << " / " << quality << " / " << newfilename.toStdString() << NL;
59
60 // These image formats known by exiv2 are also supported by PhotoQt
61 QStringList formats;
62 formats << "jpeg"
63 << "jpg"
64 << "tif"
65 << "tiff"
66 << "png"
67 << "psd"
68 << "jpeg2000"
69 << "jp2"
70 << "jpc"
71 << "j2k"
72 << "jpf"
73 << "jpx"
74 << "jpm"
75 << "mj2"
76 << "bmp"
77 << "bitmap"
78 << "gif"
79 << "tga";
80
81 #ifdef EXIV2
82
83 // This will store all the exif data
84 Exiv2::ExifData exifData;
85 bool gotExifData = false;
86
87 if(formats.contains(QFileInfo(filename).suffix().toLower()) && formats.contains(QFileInfo(newfilename).suffix().toLower())) {
88
89 if(qgetenv("PHOTOQT_DEBUG") == "yes") std::clog << "scale: image format supported by exiv2" << NL;
90
91 try {
92
93 // Open image for exif reading
94 Exiv2::Image::AutoPtr image_read = Exiv2::ImageFactory::open(filename.toStdString());
95
96 if(image_read.get() != 0) {
97
98 // YAY, WE FOUND SOME!!!!!
99 gotExifData = true;
100
101 // read exif
102 image_read->readMetadata();
103 exifData = image_read->exifData();
104
105 // Update dimensions
106 exifData["Exif.Photo.PixelXDimension"] = int32_t(width);
107 exifData["Exif.Photo.PixelYDimension"] = int32_t(height);
108
109 }
110
111 }
112
113 catch (Exiv2::Error& e) {
114 std::cerr << "ERROR [scale]: reading exif data (caught exception): " << e.what() << NL;
115 }
116
117 } else {
118 std::cerr << "ERROR [scale]: image format NOT supported by exiv2" << NL;
119 return false;
120 }
121
122
123 #endif
124
125 // We need to do the actual scaling in between reading the exif data above and writing it below,
126 // since we might be scaling the image in place and thus would overwrite old exif data
127 QImageReader reader(filename);
128 reader.setScaledSize(QSize(width,height));
129 QImage img = reader.read();
130 if(!img.save(newfilename,0,quality)) {
131 std::cerr << "ERROR [scale]: Unable to save file";
132 return false;
133 }
134
135 #ifdef EXIV2
136
137 // We don't need to check again, if both files are actually supported formats, since if either one isn't supported, this bool cannot be true
138 if(gotExifData) {
139
140 try {
141
142 // And write exif data to new image file
143 Exiv2::Image::AutoPtr image_write = Exiv2::ImageFactory::open(newfilename.toStdString());
144 image_write->setExifData(exifData);
145 image_write->writeMetadata();
146
147 }
148
149 catch (Exiv2::Error& e) {
150 std::cerr << "ERROR [scale]: writing exif data (caught exception): " << e.what() << NL;
151 }
152
153 }
154
155 #endif
156
157 return true;
158
159 }
160
161
deleteImage(QString filename,bool trash)162 void GetAndDoStuffManipulation::deleteImage(QString filename, bool trash) {
163
164 if(qgetenv("PHOTOQT_DEBUG") == "yes")
165 LOG << CURDATE << "GetAndDoStuffManipulation::deleteImage() - " << filename.toStdString() << " / " << trash << NL;
166
167 filename = QByteArray::fromPercentEncoding(filename.toUtf8());
168
169 #ifdef Q_OS_LINUX
170
171 if(trash) {
172
173 if(qgetenv("PHOTOQT_DEBUG") == "yes") std::clog << "fhd: Move to trash" << NL;
174
175 // The file to delete
176 QFile f(filename);
177
178 // Of course we only proceed if the file actually exists
179 if(f.exists()) {
180
181 // Create the meta .trashinfo file
182 QString info = "[Trash Info]\n";
183 info += "Path=" + QUrl(filename).toEncoded() + "\n";
184 info += "DeletionDate=" + QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm:ss");
185
186 // The base patzh for the Trah (files on external devices use the external device for Trash)
187 QString baseTrash = "";
188
189 // If file lies in the home directory
190 if(QFileInfo(filename).absoluteFilePath().startsWith(QDir::homePath())) {
191
192 // Set the base path and make sure all the dirs exist
193 baseTrash = ConfigFiles::GENERIC_DATA_DIR() + "/Trash/";
194
195 if(!QDir(baseTrash).exists())
196 QDir().mkpath(baseTrash);
197 if(!QDir(baseTrash + "files").exists())
198 QDir().mkdir(baseTrash + "files");
199 if(!QDir(baseTrash + "info").exists())
200 QDir().mkdir(baseTrash + "info");
201 } else {
202 // Set the base path and make sure all the dirs exist
203 baseTrash = "/" + filename.split("/").at(1) + "/" + filename.split("/").at(2) + QString("/.Trash-%1/").arg(getuid());
204 if(!QDir(baseTrash).exists())
205 QDir().mkdir(baseTrash);
206 if(!QDir(baseTrash + "files").exists())
207 QDir().mkdir(baseTrash + "files");
208 if(!QDir(baseTrash + "info").exists())
209 QDir().mkdir(baseTrash + "info");
210
211 }
212
213 // that's the new trash file
214 QString trashFile = baseTrash + "files/" + QUrl::toPercentEncoding(QFileInfo(f).fileName(),""," ");
215 QString backupTrashFile = trashFile;
216
217 // If there exists already a file with that name, we simply append the next higher number (sarting at 1)
218 QFile ensure(trashFile);
219 int j = 1;
220 while(ensure.exists()) {
221 trashFile = backupTrashFile + QString(" (%1)").arg(j++);
222 ensure.setFileName(trashFile);
223 }
224
225 // Copy the file to the Trash
226 if(f.copy(trashFile)) {
227
228 // And remove the old file
229 if(!f.remove())
230 LOG << CURDATE << "GetAndDoStuffManipulation: ERROR: Old file couldn't be removed!" << NL;
231
232 // Write the .trashinfo file
233 QFile i(baseTrash + "info/" + QFileInfo(trashFile).fileName() + ".trashinfo");
234 if(i.open(QIODevice::WriteOnly)) {
235 QTextStream out(&i);
236 out << info;
237 i.close();
238 } else
239 LOG << CURDATE << "GetAndDoStuffManipulation: ERROR: *.trashinfo file couldn't be created!" << NL;
240
241 } else
242 LOG << CURDATE << "GetAndDoStuffManipulation: ERROR: File couldn't be deleted (moving file failed)" << NL;
243
244 } else
245 LOG << CURDATE << "GetAndDoStuffManipulation: ERROR: File '" << filename.toStdString() << "' doesn't exist...?" << NL;
246
247 } else {
248
249 if(qgetenv("PHOTOQT_DEBUG") == "yes") LOG << CURDATE << "GetAndDoStuffManipulation: fhd: Hard delete file" << NL;
250
251 // current file
252 QFile file(filename);
253
254 // Delete it if it exists (if it got here, the file should exist)
255 if(file.exists()) {
256
257 file.remove();
258
259 } else {
260 LOG << CURDATE << "GetAndDoStuffManipulation: ERROR! File '" << filename.toStdString() << "' doesn't exist...?" << NL;
261 }
262
263 }
264
265 #else
266
267 if(qgetenv("PHOTOQT_DEBUG") == "yes") LOG << CURDATE << "GetAndDoStuffManipulation: fhd: Delete file" << NL;
268
269 // current file
270 QFile file(filename);
271
272 // Delete it if it exists (if it got here, the file should exist)
273 if(file.exists()) {
274
275 file.remove();
276
277 } else {
278 LOG << CURDATE << "GetAndDoStuffManipulation: ERROR! File doesn't exist...?" << NL;
279 }
280
281
282 #endif
283
284 }
285
copyImage(QString imagePath,QString destinationPath)286 void GetAndDoStuffManipulation::copyImage(QString imagePath, QString destinationPath) {
287
288 if(qgetenv("PHOTOQT_DEBUG") == "yes")
289 LOG << CURDATE << "GetAndDoStuffManipulation::copyImage() - " << imagePath.toStdString() << " / " << destinationPath.toStdString() << NL;
290
291 if(destinationPath.startsWith("file:/"))
292 destinationPath = destinationPath.remove(0,6);
293 #ifdef Q_OS_WIN
294 while(destinationPath.startsWith("/"))
295 destinationPath = destinationPath.remove(0,1);
296 #endif
297
298 // Don't do anything here
299 if(destinationPath.trimmed() == "") return;
300 if(destinationPath == imagePath) return;
301
302 // And copy file
303 QFile file(imagePath);
304 if(file.copy(destinationPath)) {
305 if(QFileInfo(destinationPath).absolutePath() == QFileInfo(imagePath).absolutePath())
306 emit reloadDirectory(destinationPath);
307 } else
308 LOG << CURDATE << "GetAndDoStuffManipulation: ERROR: Couldn't copy file" << NL;
309
310 }
311
moveImage(QString imagePath,QString destinationPath)312 void GetAndDoStuffManipulation::moveImage(QString imagePath, QString destinationPath) {
313
314 if(qgetenv("PHOTOQT_DEBUG") == "yes")
315 LOG << CURDATE << "GetAndDoStuffManipulation::moveImage() - " << imagePath.toStdString() << " / " << destinationPath.toStdString() << NL;
316
317 if(destinationPath.startsWith("file:/"))
318 destinationPath = destinationPath.remove(0,6);
319 #ifdef Q_OS_WIN
320 while(destinationPath.startsWith("/"))
321 destinationPath = destinationPath.remove(0,1);
322 #endif
323
324 // Don't do anything here
325 if(destinationPath.trimmed() == "") return;
326 if(destinationPath == imagePath) return;
327
328 // Make sure, that the right suffix is there...
329 if(QFileInfo(destinationPath).completeSuffix().toLower() != QFileInfo(imagePath).completeSuffix().toLower())
330 destinationPath += QFileInfo(imagePath).completeSuffix();
331
332 // And move file
333 QFile file(imagePath);
334 if(file.copy(destinationPath)) {
335 if(!file.remove()) {
336 LOG << CURDATE << "GetAndDoStuffManipulation: ERROR: Couldn't remove old file" << NL;
337 if(QFileInfo(destinationPath).absolutePath() == QFileInfo(imagePath).absolutePath())
338 emit reloadDirectory(destinationPath);
339 } else {
340 if(QFileInfo(destinationPath).absolutePath() == QFileInfo(imagePath).absolutePath())
341 emit reloadDirectory(destinationPath);
342 else
343 // A value of true signals, that the file has been moved to a different directory (i.e. "deleted" from current directory)
344 reloadDirectory(imagePath,true);
345 }
346
347 } else
348 LOG << CURDATE << "GetAndDoStuffManipulation: ERROR: Couldn't move file" << NL;
349
350 }
351
getImageBaseName(QString imagePath)352 QString GetAndDoStuffManipulation::getImageBaseName(QString imagePath) {
353
354 return QFileInfo(imagePath).baseName();
355
356 }
357