You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
digikam/digikam/utilities/cameragui/umscamera.cpp

520 lines
15 KiB

/* ============================================================
*
* This file is a part of digiKam project
* http://www.digikam.org
*
* Date : 2004-12-21
* Description : USB Mass Storage camera interface
*
* Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
* Copyright (C) 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
* Public License as published by the Free Software Foundation;
* either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* ============================================================ */
// C Ansi includes.
extern "C"
{
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <utime.h>
}
// TQt includes.
#include <tqdir.h>
#include <tqfileinfo.h>
#include <tqfile.h>
#include <tqstringlist.h>
#include <tqdeepcopy.h>
#include <tqwmatrix.h>
// KDE includes.
#include <klocale.h>
#include <tdefilemetainfo.h>
// LibKDcraw includes.
#include <libkdcraw/kdcraw.h>
// Local includes.
#include "ddebug.h"
#include "dimg.h"
#include "dmetadata.h"
#include "umscamera.h"
namespace Digikam
{
UMSCamera::UMSCamera(const TQString& title, const TQString& model, const TQString& port, const TQString& path)
: DKCamera(title, model, port, path)
{
m_cancel = false;
}
UMSCamera::~UMSCamera()
{
}
bool UMSCamera::doConnect()
{
return true;
}
void UMSCamera::cancel()
{
// set the cancel flag
m_cancel = true;
}
void UMSCamera::getAllFolders(const TQString& folder, TQStringList& subFolderList)
{
m_cancel = false;
subFolderList.clear();
subFolderList.append(folder);
listFolders(folder, subFolderList);
}
bool UMSCamera::getItemsInfoList(const TQString& folder, GPItemInfoList& infoList, bool getImageDimensions)
{
m_cancel = false;
infoList.clear();
TQDir dir(folder);
dir.setFilter(TQDir::Files);
const TQFileInfoList *list = dir.entryInfoList();
if (!list)
return false;
TQFileInfoListIterator it(*list);
TQFileInfo *fi;
TQFileInfo thmlo, thmup;
DMetadata meta;
while ((fi = it.current()) != 0 && !m_cancel)
{
++it;
TQString mime = mimeType(fi->extension(false).lower());
if (!mime.isEmpty())
{
TQSize dims;
TQDateTime dt;
GPItemInfo info;
thmlo.setFile(folder + TQString("/") + fi->baseName() + TQString(".thm"));
thmup.setFile(folder + TQString("/") + fi->baseName() + TQString(".THM"));
if (thmlo.exists())
{
// Try thumbnail sidecar files with lowercase extension.
meta.load(thmlo.filePath());
dt = meta.getImageDateTime();
dims = meta.getImageDimensions();
}
else if (thmup.exists())
{
// Try thumbnail sidecar files with uppercase extension.
meta.load(thmup.filePath());
dt = meta.getImageDateTime();
dims = meta.getImageDimensions();
}
else if (mime == TQString("image/x-raw"))
{
// If no thumbnail sidecar file available , try to load image metadata with Raw files.
meta.load(fi->filePath());
dt = meta.getImageDateTime();
dims = meta.getImageDimensions();
}
else
{
meta.load(fi->filePath());
dt = meta.getImageDateTime();
dims = meta.getImageDimensions();
if (dims.isNull())
{
// In all others case, try KFileMetaInfo.
KFileMetaInfo kmeta(fi->filePath());
if (kmeta.isValid())
{
if (kmeta.containsGroup("Jpeg EXIF Data"))
dims = kmeta.group("Jpeg EXIF Data").item("Dimensions").value().toSize();
else if (kmeta.containsGroup("General"))
dims = kmeta.group("General").item("Dimensions").value().toSize();
else if (kmeta.containsGroup("Technical"))
dims = kmeta.group("Technical").item("Dimensions").value().toSize();
}
}
}
if (dt.isNull())
{
// If date is not found in metadata, use file time stamp
dt = fi->created();
}
info.name = fi->fileName();
info.folder = !folder.endsWith("/") ? folder + TQString("/") : folder;
info.mime = mime;
info.mtime = dt.toTime_t();
info.size = fi->size();
info.width = getImageDimensions ? dims.width() : -1;
info.height = getImageDimensions ? dims.height() : -1;
info.downloaded = GPItemInfo::DownloadUnknow;
info.readPermissions = fi->isReadable();
info.writePermissions = fi->isWritable();
infoList.append(info);
}
}
return true;
}
bool UMSCamera::getThumbnail(const TQString& folder, const TQString& itemName, TQImage& thumbnail)
{
m_cancel = false;
// JPEG files: try to get thumbnail from Exif data.
DMetadata metadata(TQFile::encodeName(folder + TQString("/") + itemName));
thumbnail = metadata.getExifThumbnail(true);
if (!thumbnail.isNull())
return true;
// RAW files : try to extract embedded thumbnail using dcraw
KDcrawIface::KDcraw::loadDcrawPreview(thumbnail, TQString(folder + TQString("/") + itemName));
if (!thumbnail.isNull())
return true;
// THM files: try to get thumbnail from '.thm' files if we didn't manage to get
// thumbnail from Exif. Any cameras provides *.thm files like JPEG files with RAW/video files.
// Using this way speed up thumbnailization and limit data transfered between camera and computer.
// NOTE: the thumbnail extracted with this method can provide a poor quality preview.
TQFileInfo fi(folder + TQString("/") + itemName);
if (thumbnail.load(folder + TQString("/") + fi.baseName() + TQString(".thm"))) // Lowercase
{
if (!thumbnail.isNull())
return true;
}
else if (thumbnail.load(folder + TQString("/") + fi.baseName() + TQString(".THM"))) // Uppercase
{
if (!thumbnail.isNull())
return true;
}
// Finaly, we trying to get thumbnail using DImg API (slow).
DImg dimgThumb(TQCString(TQFile::encodeName(folder + TQString("/") + itemName)));
if (!dimgThumb.isNull())
{
thumbnail = dimgThumb.copyTQImage();
return true;
}
return false;
}
bool UMSCamera::getExif(const TQString&, const TQString&, char **, int&)
{
// not necessary to implement this. read it directly from the file
// (done in camera controller)
DWarning() << "exif implemented yet in camera controller" << endl;
return false;
}
bool UMSCamera::downloadItem(const TQString& folder, const TQString& itemName, const TQString& saveFile)
{
m_cancel = false;
TQString src = folder + TQString("/") + itemName;
TQString dest = saveFile;
TQFile sFile(src);
TQFile dFile(dest);
if ( !sFile.open(IO_ReadOnly) )
{
DWarning() << "Failed to open source file for reading: "
<< src << endl;
return false;
}
if ( !dFile.open(IO_WriteOnly) )
{
sFile.close();
DWarning() << "Failed to open dest file for writing: "
<< dest << endl;
return false;
}
const int MAX_IPC_SIZE = (1024*32);
char buffer[MAX_IPC_SIZE];
TQ_LONG len;
while ((len = sFile.readBlock(buffer, MAX_IPC_SIZE)) != 0 && !m_cancel)
{
if (len == -1 || dFile.writeBlock(buffer, (TQ_ULONG)len) != len)
{
sFile.close();
dFile.close();
return false;
}
}
sFile.close();
dFile.close();
// set the file modification time of the downloaded file to that
// of the original file
struct stat st;
::stat(TQFile::encodeName(src), &st);
struct utimbuf ut;
ut.modtime = st.st_mtime;
ut.actime = st.st_atime;
::utime(TQFile::encodeName(dest), &ut);
return true;
}
bool UMSCamera::setLockItem(const TQString& folder, const TQString& itemName, bool lock)
{
TQString src = folder + TQString("/") + itemName;
if (lock)
{
// Lock the file to set read only flag
if (::chmod(TQFile::encodeName(src), S_IREAD) == -1)
return false;
}
else
{
// Unlock the file to set read/write flag
if (::chmod(TQFile::encodeName(src), S_IREAD | S_IWRITE) == -1)
return false;
}
return true;
}
bool UMSCamera::deleteItem(const TQString& folder, const TQString& itemName)
{
m_cancel = false;
// Any camera provide THM (thumbnail) file with real image. We need to remove it also.
TQFileInfo fi(folder + TQString("/") + itemName);
TQFileInfo thmLo(folder + TQString("/") + fi.baseName() + ".thm"); // Lowercase
if (thmLo.exists())
::unlink(TQFile::encodeName(thmLo.filePath()));
TQFileInfo thmUp(folder + TQString("/") + fi.baseName() + ".THM"); // Uppercase
if (thmUp.exists())
::unlink(TQFile::encodeName(thmUp.filePath()));
// Remove the real image.
return (::unlink(TQFile::encodeName(folder + TQString("/") + itemName)) == 0);
}
bool UMSCamera::uploadItem(const TQString& folder, const TQString& itemName, const TQString& localFile,
GPItemInfo& info, bool getImageDimensions)
{
m_cancel = false;
TQString dest = folder + TQString("/") + itemName;
TQString src = localFile;
TQFile sFile(src);
TQFile dFile(dest);
if ( !sFile.open(IO_ReadOnly) )
{
DWarning() << "Failed to open source file for reading: "
<< src << endl;
return false;
}
if ( !dFile.open(IO_WriteOnly) )
{
sFile.close();
DWarning() << "Failed to open dest file for writing: "
<< dest << endl;
return false;
}
const int MAX_IPC_SIZE = (1024*32);
char buffer[MAX_IPC_SIZE];
TQ_LONG len;
while ((len = sFile.readBlock(buffer, MAX_IPC_SIZE)) != 0 && !m_cancel)
{
if (len == -1 || dFile.writeBlock(buffer, (TQ_ULONG)len) == -1)
{
sFile.close();
dFile.close();
return false;
}
}
sFile.close();
dFile.close();
// set the file modification time of the uploaded file to that
// of the original file
struct stat st;
::stat(TQFile::encodeName(src), &st);
struct utimbuf ut;
ut.modtime = st.st_mtime;
ut.actime = st.st_atime;
::utime(TQFile::encodeName(dest), &ut);
// Get new camera item information.
DMetadata meta;
TQFileInfo fi(dest);
TQString mime = mimeType(fi.extension(false).lower());
if (!mime.isEmpty())
{
TQSize dims;
TQDateTime dt;
if (mime == TQString("image/x-raw"))
{
// Try to load image metadata with Raw files.
meta.load(fi.filePath());
dt = meta.getImageDateTime();
dims = meta.getImageDimensions();
}
else
{
meta.load(fi.filePath());
dt = meta.getImageDateTime();
dims = meta.getImageDimensions();
if (dims.isNull())
{
// In all others case, try KFileMetaInfo.
KFileMetaInfo kmeta(fi.filePath());
if (kmeta.isValid())
{
if (kmeta.containsGroup("Jpeg EXIF Data"))
dims = kmeta.group("Jpeg EXIF Data").item("Dimensions").value().toSize();
else if (kmeta.containsGroup("General"))
dims = kmeta.group("General").item("Dimensions").value().toSize();
else if (kmeta.containsGroup("Technical"))
dims = kmeta.group("Technical").item("Dimensions").value().toSize();
}
}
}
if (dt.isNull())
{
// If date is not found in metadata, use file time stamp
dt = fi.created();
}
info.name = fi.fileName();
info.folder = !folder.endsWith("/") ? folder + TQString("/") : folder;
info.mime = mime;
info.mtime = dt.toTime_t();
info.size = fi.size();
info.width = getImageDimensions ? dims.width() : -1;
info.height = getImageDimensions ? dims.height() : -1;
info.downloaded = GPItemInfo::DownloadUnknow;
info.readPermissions = fi.isReadable();
info.writePermissions = fi.isWritable();
}
return true;
}
void UMSCamera::listFolders(const TQString& folder, TQStringList& subFolderList)
{
if (m_cancel)
return;
TQDir dir(folder);
dir.setFilter(TQDir::Dirs|TQDir::Executable);
const TQFileInfoList *list = dir.entryInfoList();
if (!list)
return;
TQFileInfoListIterator it( *list );
TQFileInfo *fi;
while ((fi = it.current()) != 0 && !m_cancel)
{
++it;
if (fi->fileName() == "." || fi->fileName() == "..")
continue;
TQString subfolder = folder + TQString(folder.endsWith("/") ? "" : "/") + fi->fileName();
subFolderList.append(subfolder);
listFolders(subfolder, subFolderList);
}
}
bool UMSCamera::cameraSummary(TQString& summary)
{
summary = TQString(i18n("<b>Mounted Camera</b> driver for USB/IEEE1394 mass storage cameras and "
"Flash disk card readers.<br><br>"));
summary.append(i18n("Title: %1<br>"
"Model: %2<br>"
"Port: %3<br>"
"Path: %4<br>")
.arg(title())
.arg(model())
.arg(port())
.arg(path()));
return true;
}
bool UMSCamera::cameraManual(TQString& manual)
{
manual = TQString(i18n("For more information about the <b>Mounted Camera</b> driver, "
"please read <b>Supported Digital Still "
"Cameras</b> section in the digiKam manual."));
return true;
}
bool UMSCamera::cameraAbout(TQString& about)
{
about = TQString(i18n("The <b>Mounted Camera</b> driver is a simple interface to a camera disk "
"mounted locally on your system.<br><br>"
"It doesn't use libgphoto2 drivers.<br><br>"
"To report any problems with this driver, please contact the digiKam team at:<br><br>"
"http://www.digikam.org/?q=contact"));
return true;
}
} // namespace Digikam