diff options
Diffstat (limited to 'src/utilities/cameragui/umscamera.cpp')
-rw-r--r-- | src/utilities/cameragui/umscamera.cpp | 519 |
1 files changed, 519 insertions, 0 deletions
diff --git a/src/utilities/cameragui/umscamera.cpp b/src/utilities/cameragui/umscamera.cpp new file mode 100644 index 00000000..537c29ba --- /dev/null +++ b/src/utilities/cameragui/umscamera.cpp @@ -0,0 +1,519 @@ +/* ============================================================ + * + * 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 <[email protected]> + * 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 <tdelocale.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 |