1
1
/* ============================================================
2
* Author: Renchi Raju <renchi@pooh.tam.uiuc.edu>
3
* Gilles Caulier <caulier dot gilles at free.fr>
7
* Copyright 2004-2005 by Renchi Raju
8
* Copyright 2005-2006 by Gilles Caulier
3
* This file is a part of digiKam project
4
* http://www.digikam.org
7
* Description : USB Mass Storage camera interface
9
* Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
10
* Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
10
12
* This program is free software; you can redistribute it
11
13
* and/or modify it under the terms of the GNU General
12
14
* Public License as published by the Free Software Foundation;
13
15
* either version 2, or (at your option)
14
16
* any later version.
16
18
* This program is distributed in the hope that it will be useful,
17
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
21
* GNU General Public License for more details.
21
23
* ============================================================ */
23
25
// C Ansi includes.
38
40
#include <qstringlist.h>
39
41
#include <qdeepcopy.h>
43
#include <ktempfile.h>
48
#include <libkexif/kexifdata.h>
47
#include <kfilemetainfo.h>
49
// LibKDcraw includes.
51
#include <libkdcraw/kdcraw.h>
52
#include "dcraw_parse.h"
53
#include "albumsettings.h"
57
#include "dmetadata.h"
54
58
#include "umscamera.h"
56
UMSCamera::UMSCamera(const QString& model,
59
: DKCamera(model, port, path)
63
AlbumSettings* settings = AlbumSettings::instance();
64
m_imageFilter = QDeepCopy<QString>(settings->getImageFileFilter());
65
m_movieFilter = QDeepCopy<QString>(settings->getMovieFileFilter());
66
m_audioFilter = QDeepCopy<QString>(settings->getAudioFileFilter());
67
m_rawFilter = QDeepCopy<QString>(settings->getRawFileFilter());
69
m_imageFilter = m_imageFilter.lower();
70
m_movieFilter = m_movieFilter.lower();
71
m_audioFilter = m_audioFilter.lower();
72
m_rawFilter = m_rawFilter.lower();
63
UMSCamera::UMSCamera(const QString& title, const QString& model, const QString& port, const QString& path)
64
: DKCamera(title, model, port, path)
75
69
UMSCamera::~UMSCamera()
79
bool UMSCamera::connect()
73
bool UMSCamera::doConnect()
84
78
void UMSCamera::cancel()
119
111
QString mime = mimeType(fi->extension(false).lower());
120
113
if (!mime.isEmpty())
118
if (getImageDimensions)
120
if (mime == QString("image/x-raw"))
122
DMetadata metaData(fi->filePath());
123
dims = metaData.getImageDimensions();
127
KFileMetaInfo meta(fi->filePath());
130
if (meta.containsGroup("Jpeg EXIF Data"))
131
dims = meta.group("Jpeg EXIF Data").item("Dimensions").value().toSize();
132
else if (meta.containsGroup("General"))
133
dims = meta.group("General").item("Dimensions").value().toSize();
134
else if (meta.containsGroup("Technical"))
135
dims = meta.group("Technical").item("Dimensions").value().toSize();
123
140
info.name = fi->fileName();
124
info.folder = folder;
141
info.folder = !folder.endsWith("/") ? folder + QString("/") : folder;
125
142
info.mime = mime;
126
143
info.mtime = fi->lastModified().toTime_t();
127
144
info.size = fi->size();
128
info.width = -1; // todo
129
info.height = -1; // todo
130
info.downloaded = -1;
145
info.width = dims.width();
146
info.height = dims.height();
147
info.downloaded = GPItemInfo::DownloadUnknow;
131
148
info.readPermissions = fi->isReadable();
132
149
info.writePermissions = fi->isWritable();
134
151
infoList.append(info);
143
160
m_cancel = false;
145
// In 1st, we trying to get thumbnail from Exif data if we are JPEG file.
149
if (exifData.readFromFile(folder + "/" + itemName))
151
thumbnail = exifData.getThumbnail();
152
if (!thumbnail.isNull())
156
// In 2th, we trying to get thumbnail from '.thm' files if we didn't manage to get
162
// JPEG files: try to get thumbnail from Exif data.
164
DMetadata metadata(QFile::encodeName(folder + QString("/") + itemName));
165
thumbnail = metadata.getExifThumbnail(true);
166
if (!thumbnail.isNull())
169
// RAW files : try to extract embedded thumbnail using dcraw
171
KDcrawIface::KDcraw::loadDcrawPreview(thumbnail, QString(folder + QString("/") + itemName));
172
if (!thumbnail.isNull())
175
// THM files: try to get thumbnail from '.thm' files if we didn't manage to get
157
176
// thumbnail from Exif. Any cameras provides *.thm files like JPEG files with RAW files.
158
// Using this way is always more speed than using dcraw parse utility.
177
// Using this way is always speed up than ultimate loading using DImg.
178
// Nota: the thumbnail extracted with this method can be in poor quality.
159
179
// 2006/27/01 - Gilles - Tested with my Minolta Dynax 5D USM camera.
161
QFileInfo fi(folder + "/" + itemName);
163
if (thumbnail.load(folder + "/" + fi.baseName() + ".thm")) // Lowercase
165
if (!thumbnail.isNull())
168
else if (thumbnail.load(folder + "/" + fi.baseName() + ".THM")) // Uppercase
170
if (!thumbnail.isNull())
174
// In 3rd, if file image type is TIFF, load thumb using KDELib API before to use dcraw::parse method
175
// to prevent broken 16 bits TIFF thumb.
177
if (fi.extension().upper() == QString("TIFF") ||
178
fi.extension().upper() == QString("TIF"))
180
thumbnail.load(folder + "/" + itemName);
182
if (!thumbnail.isNull())
186
// In 4th we trying to get thumbnail from RAW files using dcraw parse utility.
188
KTempFile thumbFile(QString::null, "camerarawthumb");
189
thumbFile.setAutoDelete(true);
190
Digikam::DcrawParse rawFileParser;
192
if (thumbFile.status() == 0)
194
if (rawFileParser.getThumbnail(QFile::encodeName(folder + "/" + itemName),
195
QFile::encodeName(thumbFile.name())) == 0)
197
thumbnail.load(thumbFile.name());
198
if (!thumbnail.isNull())
203
// Finaly, we trying to get thumbnail using KDELib API. This way can take a while.
205
thumbnail.load(folder + "/" + itemName);
207
if (!thumbnail.isNull())
181
QFileInfo fi(folder + QString("/") + itemName);
183
if (thumbnail.load(folder + QString("/") + fi.baseName() + ".thm")) // Lowercase
185
if (!thumbnail.isNull())
188
else if (thumbnail.load(folder + QString("/") + fi.baseName() + ".THM")) // Uppercase
190
if (!thumbnail.isNull())
195
// Finaly, we trying to get thumbnail using DImg API (slow).
197
DImg dimgThumb(QFile::encodeName(folder + QString("/") + itemName));
199
if (!dimgThumb.isNull())
201
thumbnail = dimgThumb.copyQImage();
213
bool UMSCamera::getExif(const QString& ,
208
bool UMSCamera::getExif(const QString&, const QString&, char **, int&)
217
210
// not necessary to implement this. read it directly from the file
218
211
// (done in camera controller)
219
kdWarning() << "exif implemented yet" << endl;
212
DWarning() << "exif implemented yet in camera controller" << endl;
223
bool UMSCamera::downloadItem(const QString& folder,
224
const QString& itemName,
225
const QString& saveFile)
216
bool UMSCamera::downloadItem(const QString& folder, const QString& itemName, const QString& saveFile)
227
218
m_cancel = false;
229
QString src = folder + "/" + itemName;
220
QString src = folder + QString("/") + itemName;
230
221
QString dest = saveFile;
232
223
QFile sFile(src);
233
224
QFile dFile(dest);
235
226
if ( !sFile.open(IO_ReadOnly) )
237
kdWarning() << "Failed to open source file for reading: "
228
DWarning() << "Failed to open source file for reading: "
242
233
if ( !dFile.open(IO_WriteOnly) )
245
kdWarning() << "Failed to open dest file for writing: "
236
DWarning() << "Failed to open dest file for writing: "
281
bool UMSCamera::deleteItem(const QString& folder,
282
const QString& itemName)
272
bool UMSCamera::setLockItem(const QString& folder, const QString& itemName, bool lock)
274
QString src = folder + QString("/") + itemName;
278
// Lock the file to set read only flag
279
if (::chmod(QFile::encodeName(src), S_IREAD) == -1)
284
// Unlock the file to set read/write flag
285
if (::chmod(QFile::encodeName(src), S_IREAD | S_IWRITE) == -1)
292
bool UMSCamera::deleteItem(const QString& folder, const QString& itemName)
284
294
m_cancel = false;
286
296
// Any camera provide THM (thumbnail) file with real image. We need to remove it also.
288
QFileInfo fi(folder + "/" + itemName);
290
QFileInfo thmLo(folder + "/" + fi.baseName() + ".thm"); // Lowercase
298
QFileInfo fi(folder + QString("/") + itemName);
300
QFileInfo thmLo(folder + QString("/") + fi.baseName() + ".thm"); // Lowercase
293
303
::unlink(QFile::encodeName(thmLo.filePath()));
295
QFileInfo thmUp(folder + "/" + fi.baseName() + ".THM"); // Uppercase
305
QFileInfo thmUp(folder + QString("/") + fi.baseName() + ".THM"); // Uppercase
298
308
::unlink(QFile::encodeName(thmUp.filePath()));
300
310
// Remove the real image.
301
return (::unlink(QFile::encodeName(folder + "/" + itemName)) == 0);
311
return (::unlink(QFile::encodeName(folder + QString("/") + itemName)) == 0);
304
bool UMSCamera::uploadItem(const QString& ,
314
bool UMSCamera::uploadItem(const QString& folder, const QString& itemName, const QString& localFile,
315
GPItemInfo& itemInfo, bool getImageDimensions)
308
kdWarning() << "Upload not implemented yet" << endl;
319
QString dest = folder + QString("/") + itemName;
320
QString src = localFile;
325
if ( !sFile.open(IO_ReadOnly) )
327
DWarning() << "Failed to open source file for reading: "
332
if ( !dFile.open(IO_WriteOnly) )
335
DWarning() << "Failed to open dest file for writing: "
340
const int MAX_IPC_SIZE = (1024*32);
341
char buffer[MAX_IPC_SIZE];
344
while ((len = sFile.readBlock(buffer, MAX_IPC_SIZE)) != 0 && !m_cancel)
346
if (len == -1 || dFile.writeBlock(buffer, (Q_ULONG)len) == -1)
357
// set the file modification time of the uploaded file to that
358
// of the original file
360
::stat(QFile::encodeName(src), &st);
363
ut.modtime = st.st_mtime;
364
ut.actime = st.st_atime;
366
::utime(QFile::encodeName(dest), &ut);
368
// Get new camera item information.
371
QString mime = mimeType(fi.extension(false).lower());
377
if (getImageDimensions)
379
if (mime == QString("image/x-raw"))
381
DMetadata metaData(fi.filePath());
382
dims = metaData.getImageDimensions();
386
KFileMetaInfo meta(fi.filePath());
389
if (meta.containsGroup("Jpeg EXIF Data"))
390
dims = meta.group("Jpeg EXIF Data").item("Dimensions").value().toSize();
391
else if (meta.containsGroup("General"))
392
dims = meta.group("General").item("Dimensions").value().toSize();
393
else if (meta.containsGroup("Technical"))
394
dims = meta.group("Technical").item("Dimensions").value().toSize();
399
itemInfo.name = fi.fileName();
400
itemInfo.folder = !folder.endsWith("/") ? folder + QString("/") : folder;
401
itemInfo.mime = mime;
402
itemInfo.mtime = fi.lastModified().toTime_t();
403
itemInfo.size = fi.size();
404
itemInfo.width = dims.width();
405
itemInfo.height = dims.height();
406
itemInfo.downloaded = GPItemInfo::DownloadUnknow;
407
itemInfo.readPermissions = fi.isReadable();
408
itemInfo.writePermissions = fi.isWritable();
312
void UMSCamera::listFolders(const QString& folder,
313
QStringList& subFolderList)
414
void UMSCamera::listFolders(const QString& folder, QStringList& subFolderList)
328
429
while ((fi = it.current()) != 0 && !m_cancel)
332
433
if (fi->fileName() == "." || fi->fileName() == "..")
335
QString subfolder = folder + QString(folder.endsWith("/") ? "" : "/")
436
QString subfolder = folder + QString(folder.endsWith("/") ? "" : "/") + fi->fileName();
337
437
subFolderList.append(subfolder);
338
listFolders(subfolder, subFolderList);
342
QString UMSCamera::mimeType(const QString& fileext) const
344
QString ext = fileext;
346
// massage known variations of known mimetypes into kde specific ones
349
else if (ext == "tif")
352
if (m_imageFilter.contains(ext))
354
return "image/" + ext;
356
else if (m_movieFilter.contains(ext))
358
return "video/" + ext;
360
else if (m_audioFilter.contains(ext))
362
return "audio/" + ext;
364
else if (m_rawFilter.contains(ext))
366
return "image/" + ext;
438
listFolders(subfolder, subFolderList);
442
bool UMSCamera::cameraSummary(QString& summary)
444
summary = QString(i18n("<b>Mounted Camera</b> driver for USB/IEEE1394 mass storage cameras and "
445
"Flash disk card readers.<br><br>"));
447
summary.append(i18n("Title: %1<br>"
458
bool UMSCamera::cameraManual(QString& manual)
460
manual = QString(i18n("For more information about the <b>Mounted Camera</b> driver, "
461
"please read <b>Supported Digital Still "
462
"Cameras</b> section in the digiKam manual."));
466
bool UMSCamera::cameraAbout(QString& about)
468
about = QString(i18n("The <b>Mounted Camera</b> driver is a simple interface to a camera disk "
469
"mounted locally on your system.<br><br>"
470
"It doesn't use libgphoto2 drivers.<br><br>"
471
"To report any problems with this driver, please contact the digiKam team at:<br><br>"
472
"http://www.digikam.org/?q=contact"));
476
} // namespace Digikam