2
* Copyright (C) 2011-2014 Canonical Ltd
4
* This program is free software: you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License version 3 as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17
* Jim Nelson <jim@yorba.org>
18
* Lucas Beeler <lucas@yorba.org>
19
* Charles Lindsay <chaz@yorba.org>
20
* Eric Gregory <eric@yorba.org>
21
* Clint Rogers <clinton@yorba.org>
22
* Ugo Riboni <ugo.riboni@canonical.com>
25
#include "photo-data.h"
26
#include "photo-edit-command.h"
27
#include "photo-edit-thread.h"
30
#include "photo-metadata.h"
35
#include <QApplication>
40
#include <QImageReader>
41
#include <QImageWriter>
43
#include <QStandardPaths>
46
* \brief Photo::isValid
50
bool PhotoData::isValid(const QFileInfo& file)
52
QImageReader reader(file.filePath());
53
QByteArray format = reader.format();
55
if (QString(format).toLower() == "tiff") {
56
// QImageReader.canRead() will detect some raw files as readable TIFFs,
57
// though QImage will fail to load them.
58
QString extension = file.suffix().toLower();
59
if (extension != "tiff" && extension != "tif")
63
PhotoMetadata* tmp = PhotoMetadata::fromFile(file);
68
return reader.canRead() &&
69
QImageWriter::supportedImageFormats().contains(reader.format());
76
PhotoData::PhotoData()
80
m_orientation(TOP_LEFT_ORIGIN)
84
void PhotoData::setPath(QString path)
86
if (QFileInfo(path).absoluteFilePath() != m_file.absoluteFilePath()) {
87
QFileInfo newFile(path);
88
if (newFile.exists() && newFile.isFile()) {
89
QByteArray format = QImageReader(newFile.absoluteFilePath()).format();
90
m_fileFormat = QString(format).toLower();
91
if (m_fileFormat == "jpg") // Why does Qt expose two different names here?
92
m_fileFormat = "jpeg";
97
if (fileFormatHasMetadata()) {
98
PhotoMetadata* metadata = PhotoMetadata::fromFile(newFile.absoluteFilePath());
99
m_orientation = metadata->orientation();
101
Q_EMIT orientationChanged();
107
QString PhotoData::path() const
109
return m_file.absoluteFilePath();
112
QFileInfo PhotoData::file() const
118
* \brief Photo::~Photo
120
PhotoData::~PhotoData()
123
m_editThread->wait();
129
* \brief Photo::orientation
132
Orientation PhotoData::orientation() const
134
return m_orientation;
137
void PhotoData::refreshFromDisk()
139
if (fileFormatHasMetadata()) {
140
PhotoMetadata* metadata = PhotoMetadata::fromFile(m_file.absoluteFilePath());
141
qDebug() << "Refreshing orient." << m_orientation << "to" << metadata->orientation();
142
m_orientation = metadata->orientation();
144
Q_EMIT orientationChanged();
147
Q_EMIT dataChanged();
151
* \brief Photo::rotateRight
153
void PhotoData::rotateRight()
155
Orientation current = fileFormatHasOrientation() ? orientation() :
157
Orientation rotated = OrientationCorrection::rotateOrientation(current,
159
qDebug() << " Rotate from orientation " << current << "to" << rotated;
161
PhotoEditCommand command;
162
command.type = EDIT_ROTATE;
163
command.orientation = rotated;
168
* \brief Photo::autoEnhance
170
void PhotoData::autoEnhance()
172
PhotoEditCommand command;
173
command.type = EDIT_ENHANCE;
178
* \brief Photo::exposureCompensation Changes the brightnes of the image
179
* \param value Value for the compensation. -1.0 moves the image into total black.
180
* +1.0 to total white. 0.0 leaves it as it is.
182
void PhotoData::exposureCompensation(qreal value)
184
PhotoEditCommand command;
185
command.type = EDIT_COMPENSATE_EXPOSURE;
186
command.exposureCompensation = value;
192
* Specify all coords in [0.0, 1.0], where 1.0 is the full size of the image.
193
* They will be clamped to this range if you don't.
194
* \param vrect the rectangle specifying the region to be cropped
196
void PhotoData::crop(QVariant vrect)
198
PhotoEditCommand command;
199
command.type = EDIT_CROP;
200
command.crop_rectangle = vrect.toRectF();
205
* \brief Photo::asyncEdit does edit the photo according to the given command
206
* in a background thread.
207
* \param The command defining the edit operation to perform.
209
void PhotoData::asyncEdit(const PhotoEditCommand& command)
212
qWarning() << "Can't start edit operation while another one is running.";
216
Q_EMIT busyChanged();
217
m_editThread = new PhotoEditThread(this, command);
218
connect(m_editThread, SIGNAL(finished()), this, SLOT(finishEditing()));
219
m_editThread->start();
223
* \brief Photo::finishEditing do all the updates once the editing is done
225
void PhotoData::finishEditing()
227
if (!m_editThread || m_editThread->isRunning())
230
m_editThread->deleteLater();
236
Q_EMIT busyChanged();
237
Q_EMIT editFinished();
241
* \brief Photo::fileFormat returns the file format as QString
244
const QString &PhotoData::fileFormat() const
250
* \brief Photo::fileFormatHasMetadata
253
bool PhotoData::fileFormatHasMetadata() const
255
return (m_fileFormat == "jpeg" || m_fileFormat == "tiff" ||
256
m_fileFormat == "png");
260
* \brief Photo::fileFormatHasOrientation
263
bool PhotoData::fileFormatHasOrientation() const
265
return (m_fileFormat == "jpeg");
269
* \brief Photo::busy return true if there is an editing operation in progress
272
bool PhotoData::busy() const