Krazy/EBN: fix i18n warnings
[kphotoalbum.git] / ImageManager / ImageLoader.cpp
blob4e959154fcb2848dbcc3bb3f7fc5cb01f643c7ed
1 /* Copyright (C) 2003-2006 Jesper K. Pedersen <blackie@kde.org>
3 This program is free software; you can redistribute it and/or
4 modify it under the terms of the GNU General Public
5 License as published by the Free Software Foundation; either
6 version 2 of the License, or (at your option) any later version.
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 GNU
11 General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; see the file COPYING. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
19 #include "ImageLoader.h"
21 #include "ImageDecoder.h"
22 #include "Manager.h"
23 #include "RawImageDecoder.h"
24 #include "Utilities/Util.h"
25 #include "ThumbnailStorage.h"
27 #include <qapplication.h>
28 #include <qfileinfo.h>
30 extern "C" {
31 #include <limits.h>
32 #include <setjmp.h>
33 #include <stdio.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <unistd.h>
41 #include <kcodecs.h>
42 #include <kurl.h>
43 #include <qmatrix.h>
45 namespace ImageManager
47 // Create a global instance. Its constructor will itself register it.
48 RAWImageDecoder rawdecoder;
53 ImageManager::ImageLoader::ImageLoader(ThumbnailStorage* storage)
54 : _storage(storage) {
55 /* nop */
58 void ImageManager::ImageLoader::run()
60 while ( true ) {
61 ImageRequest* request = Manager::instance()->next();
62 Q_ASSERT( request );
63 bool ok;
65 QImage img = tryLoadThumbnail( request, ok );
66 if ( ! ok ) {
67 img = loadImage( request, ok );
68 if ( ok ) {
69 writeThumbnail( request, img );
73 if ( ok ) {
74 img = scaleAndRotate( request, img );
77 request->setLoadedOK( ok );
78 ImageEvent* iew = new ImageEvent( request, img );
79 QApplication::postEvent( Manager::instance(), iew );
83 QImage ImageManager::ImageLoader::rotateAndScale( QImage img, int width, int height, int angle )
85 if ( angle != 0 ) {
86 QMatrix matrix;
87 matrix.rotate( angle );
88 img = img.transformed( matrix );
90 img = Utilities::scaleImage(img, width, height, Qt::KeepAspectRatio );
91 return img;
94 QImage ImageManager::ImageLoader::tryLoadThumbnail( ImageRequest* request, bool& ok )
96 ok = false;
97 QString key = thumbnailKey( request );
99 QImage result;
100 ok = _storage->retrieve(key, &result);
101 if (!ok)
102 return result;
104 // TODO(hzeller): ppm do not store meta tags - we always accept them,
105 // because we cannot check 'outdatedness'.
106 // Find workaround (mtime(thumbnail) ? )
107 time_t thumbTime = result.text( "Thumb::MTime" ).toUInt();
109 if ( thumbTime != 0 && QFileInfo(request->fileName()).exists() ) {
110 time_t fileTime = QFileInfo(request->fileName()).lastModified().toTime_t();
111 ok = (thumbTime == fileTime);
114 return result;
117 QImage ImageManager::ImageLoader::loadImage( ImageRequest* request, bool& ok )
119 int dim = calcLoadSize( request );
120 QSize fullSize;
122 ok = false;
123 if ( !QFile( request->fileName() ).exists() )
124 return QImage();
126 QImage img;
127 if (Utilities::isJPEG(request->fileName())) {
128 ok = Utilities::loadJPEG(&img, request->fileName(), &fullSize, dim);
129 if (ok == true)
130 request->setFullSize( fullSize );
133 else {
134 // At first, we have to give our RAW decoders a try. If we allowed
135 // QImage's load() method, it'd for example load a tiny thumbnail from
136 // NEF files, which is not what we want.
137 ok = ImageDecoder::decode( &img, request->fileName(), &fullSize, dim);
138 if (ok)
139 request->setFullSize( img.size() );
142 if (!ok) {
143 // Now we can try QImage's stuff as a fallback...
144 ok = img.load( request->fileName() );
145 if (ok)
146 request->setFullSize( img.size() );
150 return img;
153 void ImageManager::ImageLoader::writeThumbnail( ImageRequest* request, QImage img )
155 int dim = calcLoadSize( request );
156 QList<int> list;
157 list << 128;
158 if ( dim == 256 )
159 list << 256;
161 for( QList<int>::Iterator it = list.begin(); it != list.end(); ++it ) {
162 QString path = thumbnailKey( requestURL( request ), *it );
163 if ( path.isNull() )
164 continue;
166 QFileInfo fi( request->fileName() );
167 QImage scaledImg = Utilities::scaleImage(img, *it, *it, Qt::KeepAspectRatio );
168 scaledImg.setText( "Software","",QString::fromLatin1( "KPhotoAlbum" ) );
169 scaledImg.setText( "Thumb::URI", "", requestURL( request ) );
170 scaledImg.setText( "Thumb::MTime", "", QString::number( fi.lastModified().toTime_t() ) );
171 scaledImg.setText( "Thumb::Size", "", QString::number( fi.size() ) );
172 scaledImg.setText( "Thumb::Image::Width", "", QString::number( request->fullSize().width() ) );
173 scaledImg.setText( "Thumb::Image::Height", "", QString::number( request->fullSize().height() ) );
174 _storage->store(path, scaledImg);
178 int ImageManager::ImageLoader::calcLoadSize( ImageRequest* request )
180 if ( request->width() == -1 )
181 return -1;
183 int max = qMax( request->width(), request->height() );
184 if ( max > 256 )
185 return max;
186 else if ( max > 128 )
187 return 256;
188 else
189 return 128;
192 QImage ImageManager::ImageLoader::scaleAndRotate( ImageRequest* request, QImage img )
194 if ( request->angle() != 0 ) {
195 QMatrix matrix;
196 matrix.rotate( request->angle() );
197 img = img.transformed( matrix );
198 int angle = (request->angle() + 360)%360;
199 Q_ASSERT( angle >= 0 && angle <= 360 );
200 if ( angle == 90 || angle == 270 )
201 request->setFullSize( QSize( request->fullSize().height(), request->fullSize().width() ) );
204 // If we are looking for a scaled version, then scale
205 if ( shouldImageBeScale( img, request ) )
206 img = Utilities::scaleImage(img, request->width(), request->height(), Qt::KeepAspectRatio );
208 return img;
211 QString ImageManager::ImageLoader::thumbnailKey( ImageRequest* request )
213 return thumbnailKey( requestURL( request ), calcLoadSize( request ) );
216 QString ImageManager::ImageLoader::thumbnailKey( QString uri, int dim )
218 QString dir;
219 if ( dim == 256 )
220 dir = QString::fromLatin1( "large" );
221 else if ( dim == 128 )
222 dir = QString::fromLatin1( "normal" );
223 else
224 return QString::null;
226 KMD5 md5( uri.toUtf8() );
227 return QString::fromLatin1( "%1/%2" ).arg(dir).arg(QString::fromUtf8(md5.hexDigest()));
230 QString ImageManager::ImageLoader::requestURL( ImageRequest* request )
232 KUrl url;
233 url.setPath( request->fileName() );
234 return url.url();
237 bool ImageManager::ImageLoader::shouldImageBeScale( const QImage& img, ImageRequest* request )
239 // No size specified, meaning we want it full size.
240 if ( request->width() == -1 )
241 return false;
243 if ( img.width() < request->width() && img.height() < request->height() ) {
244 // The image is smaller than the requets.
245 return request->doUpScale();
248 return true;