/* ============================================================ * * 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 * Copyright (C) 2005-2008 by Gilles Caulier * * 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 #include #include #include } // TQt includes. #include #include #include #include #include #include // KDE includes. #include #include // LibKDcraw includes. #include // 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("Mounted Camera driver for USB/IEEE1394 mass storage cameras and " "Flash disk card readers.

")); summary.append(i18n("Title: %1
" "Model: %2
" "Port: %3
" "Path: %4
") .arg(title()) .arg(model()) .arg(port()) .arg(path())); return true; } bool UMSCamera::cameraManual(TQString& manual) { manual = TQString(i18n("For more information about the Mounted Camera driver, " "please read Supported Digital Still " "Cameras section in the digiKam manual.")); return true; } bool UMSCamera::cameraAbout(TQString& about) { about = TQString(i18n("The Mounted Camera driver is a simple interface to a camera disk " "mounted locally on your system.

" "It doesn't use libgphoto2 drivers.

" "To report any problems with this driver, please contact the digiKam team at:

" "http://www.digikam.org/?q=contact")); return true; } } // namespace Digikam