diff --git a/AnnotationDialog/ImagePreview.cpp b/AnnotationDialog/ImagePreview.cpp index c0b5a81e..7cea10ec 100644 --- a/AnnotationDialog/ImagePreview.cpp +++ b/AnnotationDialog/ImagePreview.cpp @@ -1,598 +1,598 @@ /* Copyright (C) 2003-2018 Jesper K. Pedersen 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 of the License, 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. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ImagePreview.h" #include "Logging.h" #include #include #include -#include +#include #include "ResizableFrame.h" #include #include #include #include #include #include #include using namespace AnnotationDialog; ImagePreview::ImagePreview( QWidget* parent ) : QLabel( parent ) , m_selectionRect(0) , m_aspectRatio(1) , m_reloadTimer( new QTimer(this) ) , m_areaCreationEnabled( false ) { setAlignment( Qt::AlignCenter ); setMinimumSize( 64, 64 ); // "the widget can make use of extra space, so it should get as much space as possible" setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); m_reloadTimer->setSingleShot(true); connect(m_reloadTimer, &QTimer::timeout, this, &ImagePreview::resizeFinished); } void ImagePreview::resizeEvent( QResizeEvent* ev ) { qCDebug(AnnotationDialogLog) << "Resizing from" << ev->oldSize() <<"to"<size(); // during resizing, a scaled image will do QImage scaledImage = m_currentImage.getImage().scaled(size(),Qt::KeepAspectRatio); setPixmap(QPixmap::fromImage(scaledImage)); updateScaleFactors(); // (re)start the timer to do a full reload m_reloadTimer->start(200); QLabel::resizeEvent(ev); } int ImagePreview::heightForWidth(int width) const { int height = width * m_aspectRatio; return height; } QSize ImagePreview::sizeHint() const { QSize hint = m_info.size(); qCDebug(AnnotationDialogLog) << "Preview size hint is" << hint; return hint; } void ImagePreview::rotate(int angle) { if (! m_info.isNull()) { m_currentImage.setAngle( m_info.angle() ); m_info.rotate( angle, DB::RotateImageInfoOnly ); } else { // Can this really happen? m_angle += angle; } m_preloader.cancelPreload(); m_lastImage.reset(); reload(); rotateAreas(angle); } void ImagePreview::setImage( const DB::ImageInfo& info ) { m_info = info; reload(); } /** This method should only be used for the non-user images. Currently this includes two images: the search image and the configure several images at a time image. */ void ImagePreview::setImage( const QString& fileName ) { m_fileName = fileName; m_info = DB::ImageInfo(); m_angle = 0; // Set the current angle that will be passed to m_lastImage m_currentImage.setAngle( m_info.angle() ); reload(); } void ImagePreview::reload() { m_aspectRatio = 1; if ( !m_info.isNull() ) { if (m_preloader.has(m_info.fileName(), m_info.angle())) { qCDebug(AnnotationDialogLog) << "reload(): set preloader image"; setCurrentImage(m_preloader.getImage()); } else if (m_lastImage.has(m_info.fileName(), m_info.angle())) { qCDebug(AnnotationDialogLog) << "reload(): set last image"; //don't pass by reference, the additional constructor is needed here //see setCurrentImage for the reason (where m_lastImage is changed...) setCurrentImage(QImage(m_lastImage.getImage())); } else { if (!m_currentImage.has(m_info.fileName(), m_info.angle())) { // erase old image to prevent a laggy feel, // but only erase old image if it is a different image // (otherwise we get flicker when resizing) setPixmap(QPixmap()); } qCDebug(AnnotationDialogLog) << "reload(): set another image"; ImageManager::AsyncLoader::instance()->stop(this); ImageManager::ImageRequest* request = new ImageManager::ImageRequest( m_info.fileName(), size(), m_info.angle(), this ); request->setPriority( ImageManager::Viewer ); ImageManager::AsyncLoader::instance()->load( request ); } } else { qCDebug(AnnotationDialogLog) << "reload(): set image from file"; QImage img( m_fileName ); img = rotateAndScale( img, width(), height(), m_angle ); setPixmap( QPixmap::fromImage(img) ); } } int ImagePreview::angle() const { Q_ASSERT( !m_info.isNull() ); return m_angle; } QSize ImagePreview::getActualImageSize() { if (! m_info.size().isValid()) { // We have to fetch the size from the image m_info.setSize(QImageReader(m_info.fileName().absolute()).size()); m_aspectRatio = m_info.size().height() / m_info.size().width(); } return m_info.size(); } void ImagePreview::setCurrentImage(const QImage &image) { // Cache the current image as the last image before changing it m_lastImage.set(m_currentImage); m_currentImage.set(m_info.fileName(), image, m_info.angle()); setPixmap(QPixmap::fromImage(image)); if (!m_anticipated.m_fileName.isNull()) m_preloader.preloadImage(m_anticipated.m_fileName, width(), height(), m_anticipated.m_angle); updateScaleFactors(); // Clear the full size image (if we have loaded one) m_fullSizeImage = QImage(); } void ImagePreview::pixmapLoaded(ImageManager::ImageRequest* request, const QImage& image) { const DB::FileName fileName = request->databaseFileName(); const bool loadedOK = request->loadedOK(); if ( loadedOK && !m_info.isNull() ) { if (m_info.fileName() == fileName) setCurrentImage(image); } } void ImagePreview::anticipate(DB::ImageInfo &info1) { //We cannot call m_preloader.preloadImage right here: //this function is called before reload(), so if we preload here, //the preloader will always be loading the image after the next image. m_anticipated.set(info1.fileName(), info1.angle()); } ImagePreview::PreloadInfo::PreloadInfo() : m_angle(0) { } void ImagePreview::PreloadInfo::set(const DB::FileName& fileName, int angle) { m_fileName=fileName; m_angle=angle; } bool ImagePreview::PreviewImage::has(const DB::FileName &fileName, int angle) const { return fileName==m_fileName && !m_image.isNull() && angle==m_angle; } QImage &ImagePreview::PreviewImage::getImage() { return m_image; } void ImagePreview::PreviewImage::set(const DB::FileName &fileName, const QImage &image, int angle) { m_fileName = fileName; m_image = image; m_angle = angle; } void ImagePreview::PreviewImage::set(const PreviewImage &other) { m_fileName = other.m_fileName; m_image = other.m_image; m_angle = other.m_angle; } void ImagePreview::PreviewImage::setAngle( int angle ) { m_angle = angle; } void ImagePreview::PreviewImage::reset() { m_fileName = DB::FileName(); m_image=QImage(); } void ImagePreview::PreviewLoader::pixmapLoaded(ImageManager::ImageRequest* request, const QImage& image) { if ( request->loadedOK() ) { const DB::FileName fileName = request->databaseFileName(); set( fileName, image, request->angle() ); } } void ImagePreview::PreviewLoader::preloadImage(const DB::FileName &fileName, int width, int height, int angle) { //no need to worry about concurrent access: everything happens in the event loop thread reset(); ImageManager::AsyncLoader::instance()->stop(this); ImageManager::ImageRequest* request = new ImageManager::ImageRequest( fileName, QSize( width, height ), angle, this ); request->setPriority( ImageManager::ViewerPreload ); ImageManager::AsyncLoader::instance()->load( request ); } void ImagePreview::PreviewLoader::cancelPreload() { reset(); ImageManager::AsyncLoader::instance()->stop(this); } QImage ImagePreview::rotateAndScale(QImage img, int width, int height, int angle) const { if ( angle != 0 ) { QMatrix matrix; matrix.rotate( angle ); img = img.transformed( matrix ); } img = Utilities::scaleImage(img, QSize(width, height), Qt::KeepAspectRatio ); return img; } void ImagePreview::updateScaleFactors() { if (m_info.isNull()) return; // search mode // Calculate a scale factor from the original image's size and it's current preview QSize actualSize = getActualImageSize(); QSize previewSize = pixmap()->size(); m_scaleWidth = double(actualSize.width()) / double(previewSize.width()); m_scaleHeight = double(actualSize.height()) / double(previewSize.height()); // Calculate the min and max coordinates inside the preview widget int previewWidth = previewSize.width(); int previewHeight = previewSize.height(); int widgetWidth = this->frameGeometry().width(); int widgetHeight = this->frameGeometry().height(); m_minX = (widgetWidth - previewWidth) / 2; m_maxX = m_minX + previewWidth - 1; m_minY = (widgetHeight - previewHeight) / 2; m_maxY = m_minY + previewHeight - 1; // Put all areas to their respective position on the preview remapAreas(); } void ImagePreview::mousePressEvent(QMouseEvent *event) { if (! m_areaCreationEnabled) { return; } if (event->button() & Qt::LeftButton) { if (! m_selectionRect) { m_selectionRect = new QRubberBand(QRubberBand::Rectangle, this); } m_areaStart = event->pos(); if (m_areaStart.x() < m_minX || m_areaStart.x() > m_maxX || m_areaStart.y() < m_minY || m_areaStart.y() > m_maxY) { // Dragging started outside of the preview image return; } m_selectionRect->setGeometry(QRect(m_areaStart, QSize())); m_selectionRect->show(); } } void ImagePreview::mouseMoveEvent(QMouseEvent *event) { if (! m_areaCreationEnabled) { return; } if (m_selectionRect && m_selectionRect->isVisible()) { m_currentPos = event->pos(); // Restrict the coordinates to the preview images's size if (m_currentPos.x() < m_minX) { m_currentPos.setX(m_minX); } if (m_currentPos.y() < m_minY) { m_currentPos.setY(m_minY); } if (m_currentPos.x() > m_maxX) { m_currentPos.setX(m_maxX); } if (m_currentPos.y() > m_maxY) { m_currentPos.setY(m_maxY); } m_selectionRect->setGeometry(QRect( m_areaStart, m_currentPos ).normalized()); } } void ImagePreview::mouseReleaseEvent(QMouseEvent *event) { if (! m_areaCreationEnabled) { return; } if (event->button() & Qt::LeftButton && m_selectionRect->isVisible()) { m_areaEnd = event->pos(); processNewArea(); m_selectionRect->hide(); } } QPixmap ImagePreview::grabAreaImage(QRect area) { return QPixmap::fromImage(m_currentImage.getImage().copy(area.left() - m_minX, area.top() - m_minY, area.width(), area.height())); } QRect ImagePreview::areaPreviewToActual(QRect area) const { return QRect(QPoint(int(double(area.left() - m_minX) * m_scaleWidth), int(double(area.top() - m_minY) * m_scaleHeight)), QPoint(int(double(area.right() - m_minX) * m_scaleWidth), int(double(area.bottom() - m_minY) * m_scaleHeight))); } QRect ImagePreview::areaActualToPreview(QRect area) const { return QRect(QPoint(int(double(area.left() / m_scaleWidth)) + m_minX, int(double(area.top() / m_scaleHeight)) + m_minY), QPoint(int(double(area.right() / m_scaleWidth)) + m_minX, int(double(area.bottom() / m_scaleHeight)) + m_minY)); } void ImagePreview::createNewArea(QRect geometry, QRect actualGeometry) { // Create a ResizableFrame (cleaned up in Dialog::tidyAreas()) ResizableFrame *newArea = new ResizableFrame(this); newArea->setGeometry(geometry); // Be sure not to create an invisible area newArea->checkGeometry(); // In case the geometry has been changed by checkGeometry() actualGeometry = areaPreviewToActual(newArea->geometry()); // Store the coordinates on the real image (not on the preview) newArea->setActualCoordinates(actualGeometry); emit areaCreated(newArea); newArea->show(); newArea->showContextMenu(); } void ImagePreview::processNewArea() { if (m_areaStart == m_areaEnd) { // It was just a click, no area has been dragged return; } QRect newAreaPreview = QRect(m_areaStart, m_currentPos).normalized(); createNewArea(newAreaPreview, areaPreviewToActual(newAreaPreview)); } void ImagePreview::remapAreas() { QList allAreas = this->findChildren(); if (allAreas.isEmpty()) { return; } foreach (ResizableFrame *area, allAreas) { area->setGeometry(areaActualToPreview(area->actualCoordinates())); } } QRect ImagePreview::rotateArea(QRect originalAreaGeometry, int angle) { // This is the current state of the image. We need the state before, so ... QSize unrotatedOriginalImageSize = getActualImageSize(); // ... un-rotate it unrotatedOriginalImageSize.transpose(); QRect rotatedAreaGeometry; rotatedAreaGeometry.setWidth(originalAreaGeometry.height()); rotatedAreaGeometry.setHeight(originalAreaGeometry.width()); if (angle == 90) { rotatedAreaGeometry.moveTo( unrotatedOriginalImageSize.height() - (originalAreaGeometry.height() + originalAreaGeometry.y()), originalAreaGeometry.x() ); } else { rotatedAreaGeometry.moveTo( originalAreaGeometry.y(), unrotatedOriginalImageSize.width() - (originalAreaGeometry.width() + originalAreaGeometry.x()) ); } return rotatedAreaGeometry; } void ImagePreview::rotateAreas(int angle) { // Map all areas to their respective coordinates on the rotated actual image QList allAreas = this->findChildren(); foreach (ResizableFrame *area, allAreas) { area->setActualCoordinates(rotateArea(area->actualCoordinates(), angle)); } } void ImagePreview::resizeFinished() { qCDebug(AnnotationDialogLog) << "Reloading image after resize"; m_preloader.cancelPreload(); m_lastImage.reset(); reload(); } QRect ImagePreview::minMaxAreaPreview() const { return QRect(m_minX, m_minY, m_maxX, m_maxY); } void ImagePreview::createTaggedArea(QString category, QString tag, QRect geometry, bool showArea) { // Create a ResizableFrame (cleaned up in Dialog::tidyAreas()) ResizableFrame *newArea = new ResizableFrame(this); emit areaCreated(newArea); newArea->setGeometry(areaActualToPreview(geometry)); newArea->setActualCoordinates(geometry); newArea->setTagData(category, tag, AutomatedChange); newArea->setVisible(showArea); } void ImagePreview::setAreaCreationEnabled(bool state) { m_areaCreationEnabled = state; } // Currently only called when face detection/recognition is used void ImagePreview::fetchFullSizeImage() { if (m_fullSizeImage.isNull()) { m_fullSizeImage = QImage(m_info.fileName().absolute()); } if (m_angle != m_info.angle()) { QMatrix matrix; matrix.rotate(m_info.angle()); m_fullSizeImage = m_fullSizeImage.transformed(matrix); } } void ImagePreview::acceptProposedTag(QPair tagData, ResizableFrame *area) { // Be sure that we do have the category the proposed tag belongs to bool categoryFound = false; // Any warnings should only happen when the recognition database is e. g. copied from another // database location or has been changed outside of KPA. Anyways, this m_can_ happen, so we // have to handle it. QList categories = DB::ImageDB::instance()->categoryCollection()->categories(); for(QList::ConstIterator categoryIt = categories.constBegin(); categoryIt != categories.constEnd(); ++categoryIt) { if ((*categoryIt)->name() == tagData.first) { if (! (*categoryIt)->positionable()) { KMessageBox::sorry(this, i18n( "

Can't associate tag \"%2\"

" "

The category \"%1\" the tag \"%2\" belongs to is not positionable.

" "

If you want to use this tag, change this in the settings dialog. " "If this tag shouldn't be in the recognition database anymore, it can " "be deleted in the settings.

", tagData.first, tagData.second )); return; } categoryFound = true; break; } } if (! categoryFound) { KMessageBox::sorry(this, i18n( "

Can't associate tag \"%2\"

" "

The category \"%1\" the tag \"%2\" belongs to does not exist.

" "

If you want to use this tag, add this category and mark it as positionable. " "If this tag shouldn't be in the recognition database anymore, it can " "be deleted in the settings dialog.

", tagData.first, tagData.second )); return; } // Tell all ListSelects that we accepted a proposed tag, so that the ListSelect // holding the respective category can ensure that the tag is checked emit proposedTagSelected(tagData.first, tagData.second); // Associate the area with the proposed tag area->setTagData(tagData.first, tagData.second); } bool ImagePreview::fuzzyAreaExists(QList &existingAreas, QRect area) { float maximumDeviation; for (int i = 0; i < existingAreas.size(); ++i) { // maximumDeviation is 15% of the mean value of the width and height of each area maximumDeviation = float(existingAreas.at(i).width() + existingAreas.at(i).height()) * 0.075; if ( distance(existingAreas.at(i).topLeft(), area.topLeft()) < maximumDeviation && distance(existingAreas.at(i).topRight(), area.topRight()) < maximumDeviation && distance(existingAreas.at(i).bottomLeft(), area.bottomLeft()) < maximumDeviation && distance(existingAreas.at(i).bottomRight(), area.bottomRight()) < maximumDeviation ) { return true; } } return false; } float ImagePreview::distance(QPoint point1, QPoint point2) { QPoint difference = point1 - point2; return sqrt(pow(difference.x(), 2) + pow(difference.y(), 2)); } // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/BackgroundJobs/ExtractOneThumbnailJob.cpp b/BackgroundJobs/ExtractOneThumbnailJob.cpp index a8a69d30..c8d57347 100644 --- a/BackgroundJobs/ExtractOneThumbnailJob.cpp +++ b/BackgroundJobs/ExtractOneThumbnailJob.cpp @@ -1,99 +1,99 @@ /* Copyright 2012 Jesper K. Pedersen 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 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "ExtractOneThumbnailJob.h" #include #include #include #include -#include +#include #include #include #include namespace BackgroundJobs { ExtractOneThumbnailJob::ExtractOneThumbnailJob(const DB::FileName& fileName, int index, BackgroundTaskManager::Priority priority) : JobInterface(priority), m_fileName(fileName), m_index(index), m_wasCanceled(false) { Q_ASSERT( index >= 0 && index <= 9 ); } void ExtractOneThumbnailJob::execute() { if ( m_wasCanceled || frameName().exists() ) emit completed(); else { DB::ImageInfoPtr info = DB::ImageDB::instance()->info(m_fileName); const int length = info->videoLength(); ImageManager::ExtractOneVideoFrame::extract(m_fileName, length*m_index/10.0, this, SLOT(frameLoaded(QImage))); } } QString ExtractOneThumbnailJob::title() const { return i18n("Extracting Thumbnail"); } QString ExtractOneThumbnailJob::details() const { return QString::fromLatin1("%1 #%2").arg(m_fileName.relative()).arg(m_index); } int ExtractOneThumbnailJob::index() const { return m_index; } void ExtractOneThumbnailJob::cancel() { m_wasCanceled = true; } void ExtractOneThumbnailJob::frameLoaded(const QImage& image) { if ( !image.isNull() ) { #if 0 QImage img = image; { QPainter painter(&img); QFont fnt; fnt.setPointSize(24); painter.setFont(fnt); painter.drawText(QPoint(100,100),QString::number(m_index)); } #endif Utilities::saveImage(frameName(), image, "JPEG"); } else { // Create empty file to avoid that we recheck at next start up. QFile file(frameName().absolute()); file.open(QFile::WriteOnly); file.close(); } emit completed(); } DB::FileName ExtractOneThumbnailJob::frameName() const { return BackgroundJobs::HandleVideoThumbnailRequestJob::frameName(m_fileName, m_index); } } // namespace BackgroundJobs // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/BackgroundJobs/HandleVideoThumbnailRequestJob.cpp b/BackgroundJobs/HandleVideoThumbnailRequestJob.cpp index 2972ecf5..5c833247 100644 --- a/BackgroundJobs/HandleVideoThumbnailRequestJob.cpp +++ b/BackgroundJobs/HandleVideoThumbnailRequestJob.cpp @@ -1,114 +1,114 @@ /* Copyright 2012 Jesper K. Pedersen 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 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. 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. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "HandleVideoThumbnailRequestJob.h" #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include namespace BackgroundJobs { HandleVideoThumbnailRequestJob::HandleVideoThumbnailRequestJob(ImageManager::ImageRequest* request, BackgroundTaskManager::Priority priority) : BackgroundTaskManager::JobInterface(priority), m_request(request) { } QString HandleVideoThumbnailRequestJob::title() const { return i18n("Extract Video Thumbnail"); } QString HandleVideoThumbnailRequestJob::details() const { return m_request->databaseFileName().relative(); } void HandleVideoThumbnailRequestJob::execute() { QImage image( pathForRequest(m_request->fileSystemFileName()).absolute()); if (!image.isNull()) frameLoaded(image); else ImageManager::ExtractOneVideoFrame::extract(m_request->fileSystemFileName(), 0, this, SLOT(frameLoaded(QImage))); } void HandleVideoThumbnailRequestJob::frameLoaded(QImage image ) { if ( image.isNull() ) image = brokenImage(); saveFullScaleFrame(m_request->databaseFileName(), image); sendResult(image); emit completed(); } void HandleVideoThumbnailRequestJob::saveFullScaleFrame(const DB::FileName& fileName, const QImage &image) { Utilities::saveImage(pathForRequest(fileName), image, "JPEG"); } DB::FileName HandleVideoThumbnailRequestJob::pathForRequest(const DB::FileName &fileName) { QCryptographicHash md5(QCryptographicHash::Md5); md5.addData(fileName.absolute().toUtf8()); return DB::FileName::fromRelativePath(QString::fromLatin1(".videoThumbnails/%2").arg(QString::fromUtf8(md5.result().toHex()))); } DB::FileName HandleVideoThumbnailRequestJob::frameName(const DB::FileName &videoName, int frameNumber) { return DB::FileName::fromRelativePath( pathForRequest(videoName).relative() + QLatin1String("-") + QString::number(frameNumber)); } void HandleVideoThumbnailRequestJob::removeFullScaleFrame(const DB::FileName &fileName) { QDir().remove(BackgroundJobs::HandleVideoThumbnailRequestJob::pathForRequest(fileName).absolute()); } void HandleVideoThumbnailRequestJob::sendResult(QImage image) { //if ( m_request->isRequestStillValid(m_request) ) { image = image.scaled( QSize(m_request->width(), m_request->height()), Qt::KeepAspectRatio, Qt::SmoothTransformation ); if ( m_request->isThumbnailRequest() ) ImageManager::ThumbnailCache::instance()->insert( m_request->databaseFileName(), image ); m_request->setLoadedOK(!image.isNull()); m_request->client()->pixmapLoaded( m_request, image); //} } QImage HandleVideoThumbnailRequestJob::brokenImage() const { return QIcon::fromTheme(QString::fromUtf8("applications-multimedia")).pixmap( ThumbnailView::CellGeometry::preferredIconSize()).toImage(); } } // namespace BackgroundJobs // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cc4ad28..480c8998 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,533 +1,534 @@ cmake_minimum_required(VERSION 3.2.0) project(kphotoalbum VERSION 5.4) if(POLICY CMP0063) cmake_policy(SET CMP0063 NEW) endif() # provide drop-down menu for build-type in cmake-gui: set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ";Debug;Release;RelWithDebInfo;MinSizeRel") list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) find_package(ECM REQUIRED NO_MODULE) list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ) include(KDEInstallDirs) include(KDECompilerSettings) include(KDECMakeSettings) include(FeatureSummary) # enable exceptions: kde_enable_exceptions() add_definitions( -DQT_NO_CAST_FROM_ASCII -DQT_NO_CAST_TO_ASCII -DQT_NO_URL_CAST_FROM_STRING -DQT_NO_CAST_FROM_BYTEARRAY -DQT_DEPRECATED_WARNINGS ) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_REQUIRED TRUE) ########### dependencies ############### find_package(Qt5 5.9 REQUIRED COMPONENTS Sql Xml Widgets Network) find_package(Phonon4Qt5 REQUIRED) find_package(KF5 5.44 REQUIRED COMPONENTS Archive Completion Config CoreAddons DocTools I18n IconThemes JobWidgets KIO TextWidgets XmlGui WidgetsAddons) find_package(JPEG REQUIRED) if(JPEG_FOUND) include_directories(${JPEG_INCLUDE_DIR}) endif() ### 2018-12-30 jzarl # When Exiv2 0.26 can be deprecated, FindExiv2.cmake should be removed # and only find_package(exiv2) should be used find_package(exiv2 CONFIG QUIET) if(exiv2_FOUND) # search againg with REQUIRED, so that the feature summary correctly shows exiv as required dependency find_package(exiv2 CONFIG REQUIRED) set(EXIV2_LIBRARIES exiv2lib) else() find_package(Exiv2 REQUIRED) endif() find_package(KF5Kipi 5.1.0) set_package_properties(KF5Kipi PROPERTIES TYPE RECOMMENDED PURPOSE "Enables integration of KDE image plugin interface (shared functionality between KPhotoAlbum and other apps like gwenview or digikam)" ) set(HASKIPI ${KF5Kipi_FOUND}) find_package(KF5KDcraw) set_package_properties(KF5KDcraw PROPERTIES TYPE OPTIONAL PURPOSE "Enables RAW image support" ) set(HAVE_KDCRAW ${KF5KDcraw_FOUND} ) find_package(KF5KGeoMap) set_package_properties(KF5KGeoMap PROPERTIES TYPE OPTIONAL PURPOSE "Enables support for geographic map location using embedded GPS information." ) set(HAVE_KGEOMAP ${KF5KGeoMap_FOUND}) add_custom_target( UpdateVersion ALL COMMAND ${CMAKE_COMMAND} -DBASE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -DPROJECT_NAME=KPA -DPROJECT_VERSION="${PROJECT_VERSION}" -DCMAKE_BUILD_TYPE="${CMAKE_BUILD_TYPE}" -P "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/UpdateVersion.cmake" COMMENT "Updating version header." BYPRODUCTS "${CMAKE_CURRENT_SOURCE_DIR}/version.h" ) # For config-kpa-*.h include_directories(${CMAKE_CURRENT_BINARY_DIR}) set(libdatebar_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/DateBar/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/DateBar/DateBarWidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DateBar/ViewHandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DateBar/MouseHandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DateBar/MouseHandler.cpp ) set(libSettings_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/Settings/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/Settings/SettingsData.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/SettingsDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/ViewerSizeConfig.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/CategoryItem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/CategoryPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/TagGroupsPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/GeneralPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/FileVersionDetectionPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/ThumbnailsPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/ViewerPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/DatabaseBackendPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/UntaggedGroupBox.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/CategoriesGroupsWidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/BirthdayPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/DateTableWidgetItem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/Logging.cpp ) set(libxmldb_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/XMLDB/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/XMLDB/Database.cpp ${CMAKE_CURRENT_SOURCE_DIR}/XMLDB/XMLCategoryCollection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/XMLDB/XMLCategory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/XMLDB/XMLImageDateCollection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/XMLDB/NumberedBackup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/XMLDB/FileReader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/XMLDB/FileWriter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/XMLDB/ElementWriter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/XMLDB/XmlReader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/XMLDB/CompressFileInfo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/XMLDB/Logging.cpp ) set(libThumbnailView_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/ThumbnailRequest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/ThumbnailToolTip.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/ThumbnailWidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/GridResizeInteraction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/GridResizeSlider.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/SelectionInteraction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/MouseTrackingInteraction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/CellGeometry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/ThumbnailModel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/ThumbnailFacade.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/ThumbnailComponent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/KeyboardEventHandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/ThumbnailDND.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/Delegate.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/SelectionMaintainer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/VideoThumbnailCycler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/Logging.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/MouseInteraction.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/ThumbnailFactory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ThumbnailView/enums.cpp ) set(libPlugins_SRCS) if(KF5Kipi_FOUND) set(libPlugins_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/Plugins/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/Plugins/Interface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Plugins/ImageCollection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Plugins/ImageInfo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Plugins/CategoryImageCollection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Plugins/ImageCollectionSelector.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/PluginsPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Plugins/UploadWidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Plugins/UploadImageCollection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Plugins/Logging.cpp ) endif() set(libViewer_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/ViewerWidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/ImageDisplay.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/ViewHandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/SpeedDisplay.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/InfoBox.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/CategoryImageConfig.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/AbstractDisplay.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/VideoDisplay.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/TextDisplay.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/InfoBoxResizer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/VisibleOptionsMenu.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/VideoShooter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/TaggedArea.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Viewer/Logging.cpp ) set(libCategoryListView_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/CategoryListView/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/CategoryListView/DragableTreeWidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/CategoryListView/CheckDropItem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/CategoryListView/DragItemInfo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/CategoryListView/Logging.cpp ) set(libHTMLGenerator_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/HTMLGenerator/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/HTMLGenerator/HTMLDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/HTMLGenerator/Generator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/HTMLGenerator/Setup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/HTMLGenerator/ImageSizeCheckBox.h ${CMAKE_CURRENT_SOURCE_DIR}/HTMLGenerator/Logging.cpp ${CMAKE_CURRENT_SOURCE_DIR}/HTMLGenerator/ImageSizeCheckBox.cpp ) set(libUtilities_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/AlgorithmHelper.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ShowBusyCursor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/List.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/UniqFilenameMapper.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/Util.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/BooleanGuard.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/Process.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/DeleteFiles.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ToolTip.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/Logging.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/JpeglibWithFix.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/QStr.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/StringSet.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/FastJpeg.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/DemoUtil.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/DescriptionUtil.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/FileNameUtil.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/VideoUtil.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ImageUtil.cpp ) set(libMainWindow_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/DeleteDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/RunDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/FeatureDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/InvalidDateFinder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/AutoStackImages.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/TokenEditor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/WelcomeDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/Window.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/SplashScreen.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/ExternalPopup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/CategoryImagePopup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/SearchBar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/ImageCounter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/DirtyIndicator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/StatisticsDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/BreadcrumbViewer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/StatusBar.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/UpdateVideoThumbnail.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/DuplicateMerger/DuplicateMerger.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/DuplicateMerger/DuplicateMatch.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/DuplicateMerger/MergeToolTip.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/CopyPopup.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/Options.cpp ${CMAKE_CURRENT_SOURCE_DIR}/MainWindow/Logging.cpp ) set(libImageManager_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/ImageLoaderThread.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/AsyncLoader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/ImageRequest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/ImageClientInterface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/ImageDecoder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/RawImageDecoder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/RequestQueue.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/ThumbnailCache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/ImageEvent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/ThumbnailBuilder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/PreloadRequest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/CancelEvent.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/VideoImageRescaleRequest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/VideoThumbnails.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/VideoLengthExtractor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/ExtractOneVideoFrame.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/Logging.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/CacheFileInfo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImageManager/enums.cpp ) set(libDB_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/DB/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/DB/ImageInfo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/Category.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/CategoryCollection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/ExactCategoryMatcher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/ImageDate.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/MD5Map.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/MemberMap.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/ImageInfoList.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/ImageDB.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/FileInfo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/NegationCategoryMatcher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/NewImageFinder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/ImageScout.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/NoTagCategoryMatcher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/GroupCounter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/CategoryMatcher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/ImageSearchInfo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/CategoryItem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/ContainerCategoryMatcher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/ValueCategoryMatcher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/OrCategoryMatcher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/AndCategoryMatcher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/FastDir.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/OptimizedFileList.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/FileName.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/FileNameList.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/Logging.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/CategoryPtr.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/ExifMode.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/ImageDateCollection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/ImageInfoPtr.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/MD5.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/MediaCount.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/RawId.cpp ${CMAKE_CURRENT_SOURCE_DIR}/DB/SimpleCategoryMatcher.cpp ) set(libImportExport_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/Export.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/Import.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/ImportMatcher.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/XMLHandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/MiniViewer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/ImportHandler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/ImageRow.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/ImportDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/ImportSettings.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/KimFileReader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/MD5CheckPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ImportExport/Logging.cpp ) set(libAnnotationDialog_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/Dialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/ListSelect.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/ImagePreview.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/ImagePreviewWidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/DateEdit.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/CompletableLineEdit.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/ListViewItemHider.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/ShowSelectionOnlyManager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/ShortCutManager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/ResizableFrame.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/DescriptionEdit.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/AreaTagSelectDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/Logging.cpp ${CMAKE_CURRENT_SOURCE_DIR}/AnnotationDialog/enums.cpp ) set(libBrowser_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/Browser/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/Browser/BrowserWidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/BrowserPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/OverviewPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/CategoryPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/ImageViewPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/TreeFilter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/Breadcrumb.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/BreadcrumbList.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/AbstractCategoryModel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/FlatCategoryModel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/TreeCategoryModel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/CenteringIconView.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/Logging.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/enums.cpp ) set(libExif_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/Exif/documentation.h ${CMAKE_CURRENT_SOURCE_DIR}/Exif/Database.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Exif/InfoDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Exif/SearchDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Exif/SearchInfo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Exif/TreeView.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Exif/Info.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Exif/RangeWidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Exif/DatabaseElement.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Exif/ReReadDialog.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Exif/Grid.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Exif/Logging.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Exif/SearchDialogSettings.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Settings/ExifPage.cpp ) set(libBackgroundTaskManager_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundTaskManager/JobInterface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundTaskManager/JobManager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundTaskManager/StatusIndicator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundTaskManager/JobViewer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundTaskManager/JobModel.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundTaskManager/JobInfo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundTaskManager/CompletedJobInfo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundTaskManager/Priority.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundTaskManager/PriorityQueue.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundTaskManager/Logging.cpp ) set(libBackgroundJobs_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundJobs/SearchForVideosWithoutLengthInfo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundJobs/ReadVideoLengthJob.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundJobs/SearchForVideosWithoutVideoThumbnailsJob.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundJobs/HandleVideoThumbnailRequestJob.cpp ${CMAKE_CURRENT_SOURCE_DIR}/BackgroundJobs/ExtractOneThumbnailJob.cpp ) set(libRemoteControl_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/RemoteControl/RemoteCommand.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RemoteControl/RemoteConnection.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RemoteControl/Server.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RemoteControl/RemoteInterface.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RemoteControl/SearchInfo.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RemoteControl/RemoteImageRequest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RemoteControl/ImageNameStore.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RemoteControl/ConnectionIndicator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/RemoteControl/Logging.cpp ) set(libMap_SRCS) if(KF5KGeoMap_FOUND) set(libMap_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/Browser/GeoPositionPage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Browser/PositionBrowserWidget.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Map/MapView.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Map/MapMarkerModelHelper.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Map/SearchMarkerTiler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/Map/Logging.cpp ) endif() add_subdirectory(images) add_subdirectory(icons) add_subdirectory(demo) add_subdirectory(themes) add_subdirectory(scripts) add_subdirectory(doc) ########### next target ############### set(kphotoalbum_SRCS main.cpp ${libdatebar_SRCS} ${libSettings_SRCS} ${libsurvey_SRCS} ${libxmldb_SRCS} ${libThumbnailView_SRCS} ${libPlugins_SRCS} ${libViewer_SRCS} ${libCategoryListView_SRCS} ${libHTMLGenerator_SRCS} ${libMainWindow_SRCS} ${libImageManager_SRCS} ${libDB_SRCS} ${libImportExport_SRCS} ${libAnnotationDialog_SRCS} ${libExif_SRCS} ${libBrowser_SRCS} ${libBackgroundTaskManager_SRCS} ${libBackgroundJobs_SRCS} ${libRemoteControl_SRCS} ${libMap_SRCS} ${libUtilities_SRCS} # add doxygen headers so that they get visibiltiy in IDEs: ${CMAKE_CURRENT_SOURCE_DIR}/documentation/coding-standards.h ${CMAKE_CURRENT_SOURCE_DIR}/documentation/mainpage.h ${CMAKE_CURRENT_SOURCE_DIR}/documentation/phrase-book.h ${CMAKE_CURRENT_SOURCE_DIR}/documentation/videothumbnails.h ) add_executable(kphotoalbum ${kphotoalbum_SRCS}) add_dependencies(kphotoalbum UpdateVersion) # External components target_link_libraries(kphotoalbum ${JPEG_LIBRARY} ${EXIV2_LIBRARIES} KF5::Archive KF5::Completion KF5::ConfigCore KF5::ConfigGui KF5::CoreAddons KF5::I18n KF5::IconThemes KF5::JobWidgets KF5::KIOCore KF5::KIOWidgets KF5::TextWidgets KF5::XmlGui KF5::WidgetsAddons Phonon::phonon4qt5 Qt5::Network Qt5::Sql ) if(KF5Kipi_FOUND) target_link_libraries(kphotoalbum KF5::Kipi) endif() if(KF5KDcraw_FOUND) target_link_libraries(kphotoalbum KF5::KDcraw) endif() if(KF5KGeoMap_FOUND) target_link_libraries(kphotoalbum KF5::KGeoMap ) endif() install(TARGETS kphotoalbum ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) ########### install files ############### install(PROGRAMS org.kde.kphotoalbum.desktop org.kde.kphotoalbum-import.desktop DESTINATION ${KDE_INSTALL_APPDIR}) install(FILES kphotoalbumrc DESTINATION ${KDE_INSTALL_CONFDIR}) install(FILES tips default-setup DESTINATION ${KDE_INSTALL_DATADIR}/kphotoalbum) install(FILES kphotoalbumui.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/kphotoalbum) install(FILES org.kde.kphotoalbum.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) configure_file(config-kpa-kdcraw.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kpa-kdcraw.h) configure_file(config-kpa-kipi.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kpa-kipi.h) configure_file(config-kpa-kgeomap.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kpa-kgeomap.h) feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) # vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/DB/Category.cpp b/DB/Category.cpp index 40d80eca..3f9895c9 100644 --- a/DB/Category.cpp +++ b/DB/Category.cpp @@ -1,190 +1,190 @@ /* Copyright (C) 2003-2018 Jesper K. Pedersen 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 of the License, 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. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Category.h" #include #include #include #include #include #include #include #include "DB/ImageDB.h" #include "DB/MemberMap.h" #include "CategoryItem.h" #include #include -#include +#include using Utilities::StringSet; QPixmap DB::Category::icon( int size, KIconLoader::States state ) const { QPixmap pixmap = KIconLoader::global()->loadIcon( iconName(), KIconLoader::Desktop, size, state, QStringList(), 0L, true); DB::Category* This = const_cast(this); if ( pixmap.isNull() ) { This->blockSignals(true); This->setIconName(defaultIconName()); This->blockSignals(false); pixmap = QIcon::fromTheme(iconName()).pixmap(size); } return pixmap; } QStringList DB::Category::itemsInclCategories() const { // values including member groups QStringList items = this->items(); // add the groups to the list too, but only if the group is not there already, which will be the case // if it has ever been selected once. QStringList groups = DB::ImageDB::instance()->memberMap().groups( name() ); for( QStringList::ConstIterator it = groups.constBegin(); it != groups.constEnd(); ++it ) { if ( ! items.contains( *it ) ) items << *it ; }; return items; } DB::CategoryItem* createItem( const QString& categoryName, const QString& itemName, StringSet handledItems, QMap& categoryItems, QMap& potentialToplevelItems ) { handledItems.insert( itemName ); DB::CategoryItem* result = new DB::CategoryItem( itemName ); const QStringList members = DB::ImageDB::instance()->memberMap().members( categoryName, itemName, false ); for( QStringList::ConstIterator memberIt = members.constBegin(); memberIt != members.constEnd(); ++memberIt ) { if ( !handledItems.contains( *memberIt ) ) { DB::CategoryItem* child; if ( categoryItems.contains( *memberIt ) ) child = categoryItems[*memberIt]->clone(); else child = createItem( categoryName, *memberIt, handledItems, categoryItems, potentialToplevelItems ); potentialToplevelItems.remove( *memberIt ); result->mp_subcategories.append( child ); } } categoryItems.insert( itemName, result ); return result; } DB::CategoryItemPtr DB::Category::itemsCategories() const { const MemberMap& map = ImageDB::instance()->memberMap(); const QStringList groups = map.groups( name() ); QMap categoryItems; QMap potentialToplevelItems; for( QStringList::ConstIterator groupIt = groups.constBegin(); groupIt != groups.constEnd(); ++groupIt ) { if ( !categoryItems.contains( *groupIt ) ) { StringSet handledItems; DB::CategoryItem* child = createItem( name(), *groupIt, handledItems, categoryItems, potentialToplevelItems ); potentialToplevelItems.insert( *groupIt, child ); } } CategoryItem* result = new CategoryItem( QString::fromLatin1("top"), true ); for( QMap::ConstIterator toplevelIt = potentialToplevelItems.constBegin(); toplevelIt != potentialToplevelItems.constEnd(); ++toplevelIt ) { result->mp_subcategories.append( *toplevelIt ); } // Add items not found yet. QStringList elms = items(); for( QStringList::ConstIterator elmIt = elms.constBegin(); elmIt != elms.constEnd(); ++elmIt ) { if ( !categoryItems.contains( *elmIt ) ) result->mp_subcategories.append( new DB::CategoryItem( *elmIt ) ); } return CategoryItemPtr( result ); } QString DB::Category::defaultIconName() const { const QString nm = name().toLower(); if ( nm == QString::fromLatin1("people") ) return QString::fromLatin1("system-users"); if ( nm == QString::fromLatin1("places") || nm == QString::fromLatin1("locations") ) return QString::fromLatin1("network-workgroup"); if ( nm == QString::fromLatin1("events") || nm == QString::fromLatin1("keywords") ) return QString::fromLatin1("dialog-password"); if ( nm == QString::fromLatin1("tokens") ) return QString::fromLatin1("preferences-other"); if ( nm == QString::fromLatin1("folder") ) return QString::fromLatin1("folder"); if ( nm == QString::fromLatin1("media type") ) return QString::fromLatin1("video"); return QString(); } QPixmap DB::Category::categoryImage( const QString& category, QString member, int width, int height ) const { QString fileName = fileForCategoryImage( category, member ); QString key = QString::fromLatin1( "%1-%2" ).arg(width).arg(fileName); QPixmap res; if ( QPixmapCache::find( key, res ) ) return res; QImage img; bool ok = img.load( fileName, "JPEG" ); if ( ! ok ) { if ( DB::ImageDB::instance()->memberMap().isGroup( category, member ) ) img = KIconLoader::global()->loadIcon( QString::fromLatin1( "kuser" ), KIconLoader::Desktop, qMax(width,height) ).toImage(); else img = icon( qMax(width,height) ).toImage(); } res = QPixmap::fromImage( Utilities::scaleImage(img, QSize(width, height), Qt::KeepAspectRatio) ); QPixmapCache::insert( key, res ); return res; } void DB::Category::setCategoryImage( const QString& category, QString member, const QImage& image ) { QString dir = Settings::SettingsData::instance()->imageDirectory() + QString::fromLatin1("CategoryImages" ); QFileInfo fi( dir ); bool ok; if ( !fi.exists() ) { bool ok = QDir().mkdir( dir ); if ( !ok ) { KMessageBox::error( nullptr, i18n("Unable to create directory '%1'.", dir ), i18n("Unable to Create Directory") ); return; } } QString fileName = fileForCategoryImage( category, member ); ok = image.save( fileName, "JPEG" ); if ( !ok ) { KMessageBox::error( nullptr, i18n("Error when saving image '%1'.",fileName), i18n("Error Saving Image") ); return; } QPixmapCache::clear(); } QString DB::Category::fileForCategoryImage( const QString& category, QString member ) const { QString dir = Settings::SettingsData::instance()->imageDirectory() + QString::fromLatin1("CategoryImages" ); member.replace( QChar::fromLatin1(' '), QChar::fromLatin1('_') ); member.replace( QChar::fromLatin1('/'), QChar::fromLatin1('_') ); QString fileName = dir + QString::fromLatin1("/%1-%2.jpg").arg( category ).arg( member ); return fileName; } // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/ImageManager/ImageLoaderThread.cpp b/ImageManager/ImageLoaderThread.cpp index 2b04412f..c114223d 100644 --- a/ImageManager/ImageLoaderThread.cpp +++ b/ImageManager/ImageLoaderThread.cpp @@ -1,159 +1,159 @@ /* Copyright (C) 2003-2010 Jesper K. Pedersen 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 of the License, 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. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ImageLoaderThread.h" #include "ThumbnailCache.h" #include "ImageDecoder.h" #include "AsyncLoader.h" #include "RawImageDecoder.h" #include "Utilities/FastJpeg.h" -#include "Utilities/Util.h" +#include "Utilities/ImageUtil.h" #include #include extern "C" { #include #include #include #include #include #include #include } #include #include #include "ImageEvent.h" namespace ImageManager { // Create a global instance. Its constructor will itself register it. RAWImageDecoder rawdecoder; } ImageManager::ImageLoaderThread::ImageLoaderThread( size_t bufsize ) : m_imageLoadBuffer( new char[bufsize] ), m_bufSize( bufsize ) { } ImageManager::ImageLoaderThread::~ImageLoaderThread() { delete[] m_imageLoadBuffer; } void ImageManager::ImageLoaderThread::run() { while ( true ) { ImageRequest* request = AsyncLoader::instance()->next(); Q_ASSERT( request ); if ( request->isExitRequest() ) { return; } bool ok; QImage img = loadImage( request, ok ); if ( ok ) { img = scaleAndRotate( request, img ); } request->setLoadedOK( ok ); ImageEvent* iew = new ImageEvent( request, img ); QApplication::postEvent( AsyncLoader::instance(), iew ); } } QImage ImageManager::ImageLoaderThread::loadImage( ImageRequest* request, bool& ok ) { int dim = calcLoadSize( request ); QSize fullSize; ok = false; if ( !request->fileSystemFileName().exists() ) return QImage(); QImage img; if (Utilities::isJPEG(request->fileSystemFileName())) { ok = Utilities::loadJPEG( &img, request->fileSystemFileName(), &fullSize, dim, m_imageLoadBuffer, m_bufSize ); if (ok == true) request->setFullSize( fullSize ); } else { // At first, we have to give our RAW decoders a try. If we allowed // QImage's load() method, it'd for example load a tiny thumbnail from // NEF files, which is not what we want. ok = ImageDecoder::decode( &img, request->fileSystemFileName(), &fullSize, dim); if (ok) request->setFullSize( img.size() ); } if (!ok) { // Now we can try QImage's stuff as a fallback... ok = img.load( request->fileSystemFileName().absolute() ); if (ok) request->setFullSize( img.size() ); } return img; } int ImageManager::ImageLoaderThread::calcLoadSize( ImageRequest* request ) { return qMax( request->width(), request->height() ); } QImage ImageManager::ImageLoaderThread::scaleAndRotate( ImageRequest* request, QImage img ) { if ( request->angle() != 0 ) { QMatrix matrix; matrix.rotate( request->angle() ); img = img.transformed( matrix ); int angle = (request->angle() + 360)%360; Q_ASSERT( angle >= 0 && angle <= 360 ); if ( angle == 90 || angle == 270 ) request->setFullSize( QSize( request->fullSize().height(), request->fullSize().width() ) ); } // If we are looking for a scaled version, then scale if ( shouldImageBeScale( img, request ) ) img = Utilities::scaleImage(img, request->size(), Qt::KeepAspectRatio ); return img; } bool ImageManager::ImageLoaderThread::shouldImageBeScale( const QImage& img, ImageRequest* request ) { // No size specified, meaning we want it full size. if ( request->width() == -1 ) return false; if ( img.width() < request->width() && img.height() < request->height() ) { // The image is smaller than the requets. return request->doUpScale(); } return true; } // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/Utilities/ImageUtil.cpp b/Utilities/ImageUtil.cpp new file mode 100644 index 00000000..e1c7a39e --- /dev/null +++ b/Utilities/ImageUtil.cpp @@ -0,0 +1,39 @@ +/* Copyright (C) 2003-2010 Jesper K. Pedersen + + 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 of the License, 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. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "ImageUtil.h" + +#include + +#include +#include + + +QImage Utilities::scaleImage(const QImage &image, const QSize& size, Qt::AspectRatioMode mode ) +{ + return image.scaled( size, mode, Settings::SettingsData::instance()->smoothScale() ? Qt::SmoothTransformation : Qt::FastTransformation ); +} + +void Utilities::saveImage( const DB::FileName& fileName, const QImage& image, const char* format ) +{ + const QFileInfo info(fileName.absolute()); + QDir().mkpath(info.path()); + const bool ok = image.save(fileName.absolute(),format); + Q_ASSERT(ok); Q_UNUSED(ok); +} +// vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/Utilities/Util.h b/Utilities/ImageUtil.h similarity index 73% copy from Utilities/Util.h copy to Utilities/ImageUtil.h index 8a8dc769..53f51af1 100644 --- a/Utilities/Util.h +++ b/Utilities/ImageUtil.h @@ -1,60 +1,48 @@ /* Copyright (C) 2003-2010 Jesper K. Pedersen 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 of the License, 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. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef UTIL_H -#define UTIL_H +#ifndef IMAGE_UTIL_H +#define IMAGE_UTIL_H #include "DB/FileName.h" #include -#include namespace Utilities { -void checkForBackupFile( const QString& fileName, const QString& message = QString() ); -bool copy( const QString& from, const QString& to ); -bool makeSymbolicLink( const QString& from, const QString& to ); -bool makeHardLink( const QString& from, const QString& to ); -bool canReadImage( const DB::FileName& fileName ); -QString locateDataFile(const QString& fileName); - /** * @brief scaleImage returns the scaled image, honoring the settings for smooth scaling. * @param image * @param size * @param mode aspect ratio mode * @return a scaled image */ QImage scaleImage(const QImage &image, const QSize& size, Qt::AspectRatioMode mode=Qt::IgnoreAspectRatio ); -QString cStringWithEncoding( const char *c_str, const QString& charset ); - -QColor contrastColor( const QColor& ); - /** * @brief saveImage saves a QImage to a FileName, making sure that the directory exists. * @param fileName * @param image * @param format the storage format for QImage::save(), usually "JPEG" */ void saveImage( const DB::FileName& fileName, const QImage& image, const char* format ); } -#endif /* UTIL_H */ +#endif /* IMAGE_UTIL_H */ // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/Utilities/Util.cpp b/Utilities/Util.cpp index 890e69be..e9e4f126 100644 --- a/Utilities/Util.cpp +++ b/Utilities/Util.cpp @@ -1,157 +1,141 @@ /* Copyright (C) 2003-2010 Jesper K. Pedersen 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 of the License, 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. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "Util.h" #include "Logging.h" #include #include -#include #include #include -#include #include #include #include #include #include #include #include -#include #include #include #include #include -#include extern "C" { #include } void Utilities::checkForBackupFile( const QString& fileName, const QString& message ) { QString backupName = QFileInfo( fileName ).absolutePath() + QString::fromLatin1("/.#") + QFileInfo( fileName ).fileName(); QFileInfo backUpFile( backupName); QFileInfo indexFile( fileName ); if ( !backUpFile.exists() || indexFile.lastModified() > backUpFile.lastModified() || backUpFile.size() == 0 ) if ( !( backUpFile.exists() && !message.isNull() ) ) return; int code; if ( message.isNull() ) code = KMessageBox::questionYesNo( nullptr, i18n("Autosave file '%1' exists (size %3 KB) and is newer than '%2'. " "Should the autosave file be used?", backupName, fileName, backUpFile.size() >> 10 ), i18n("Found Autosave File") ); else if ( backUpFile.size() > 0 ) code = KMessageBox::warningYesNo( nullptr,i18n( "

Error: Cannot use current database file '%1':

%2

" "

Do you want to use autosave (%3 - size %4 KB) instead of exiting?

" "

(Manually verifying and copying the file might be a good idea)

", fileName, message, backupName, backUpFile.size() >> 10 ), i18n("Recover from Autosave?") ); else { KMessageBox::error( nullptr, i18n( "

Error: %1

Also autosave file is empty, check manually " "if numbered backup files exist and can be used to restore index.xml.

", message ) ); exit(-1); } if ( code == KMessageBox::Yes ) { QFile in( backupName ); if ( in.open( QIODevice::ReadOnly ) ) { QFile out( fileName ); if (out.open( QIODevice::WriteOnly ) ) { char data[1024]; int len; while ( (len = in.read( data, 1024 ) ) ) out.write( data, len ); } } } else if ( !message.isNull() ) exit(-1); } bool Utilities::copy( const QString& from, const QString& to ) { if ( QFileInfo(to).exists()) QDir().remove(to); return QFile::copy(from,to); } bool Utilities::makeHardLink( const QString& from, const QString& to ) { if (link(from.toLocal8Bit().constData(), to.toLocal8Bit().constData()) != 0) return false; else return true; } bool Utilities::makeSymbolicLink( const QString& from, const QString& to ) { if (symlink(from.toLocal8Bit().constData(), to.toLocal8Bit().constData()) != 0) return false; else return true; } bool Utilities::canReadImage( const DB::FileName& fileName ) { bool fastMode = !Settings::SettingsData::instance()->ignoreFileExtension(); QMimeDatabase::MatchMode mode = fastMode ? QMimeDatabase::MatchExtension : QMimeDatabase::MatchDefault; QMimeDatabase db; QMimeType mimeType = db.mimeTypeForFile( fileName.absolute(), mode ); return QImageReader::supportedMimeTypes().contains( mimeType.name().toUtf8() ) || ImageManager::ImageDecoder::mightDecode( fileName ); } QString Utilities::locateDataFile(const QString& fileName) { return QStandardPaths::locate(QStandardPaths::DataLocation, fileName); } -QImage Utilities::scaleImage(const QImage &image, const QSize& size, Qt::AspectRatioMode mode ) -{ - return image.scaled( size, mode, Settings::SettingsData::instance()->smoothScale() ? Qt::SmoothTransformation : Qt::FastTransformation ); -} - QString Utilities::cStringWithEncoding( const char *c_str, const QString& charset ) { QTextCodec* codec = QTextCodec::codecForName( charset.toLatin1() ); if (!codec) codec = QTextCodec::codecForLocale(); return codec->toUnicode( c_str ); } QColor Utilities::contrastColor( const QColor& col ) { if ( col.red() < 127 && col.green() < 127 && col.blue() < 127 ) return Qt::white; else return Qt::black; } -void Utilities::saveImage( const DB::FileName& fileName, const QImage& image, const char* format ) -{ - const QFileInfo info(fileName.absolute()); - QDir().mkpath(info.path()); - const bool ok = image.save(fileName.absolute(),format); - Q_ASSERT(ok); Q_UNUSED(ok); -} // vi:expandtab:tabstop=4 shiftwidth=4: diff --git a/Utilities/Util.h b/Utilities/Util.h index 8a8dc769..cef1386c 100644 --- a/Utilities/Util.h +++ b/Utilities/Util.h @@ -1,60 +1,44 @@ /* Copyright (C) 2003-2010 Jesper K. Pedersen 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 of the License, 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. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef UTIL_H #define UTIL_H #include "DB/FileName.h" #include #include namespace Utilities { void checkForBackupFile( const QString& fileName, const QString& message = QString() ); bool copy( const QString& from, const QString& to ); bool makeSymbolicLink( const QString& from, const QString& to ); bool makeHardLink( const QString& from, const QString& to ); bool canReadImage( const DB::FileName& fileName ); QString locateDataFile(const QString& fileName); -/** - * @brief scaleImage returns the scaled image, honoring the settings for smooth scaling. - * @param image - * @param size - * @param mode aspect ratio mode - * @return a scaled image - */ -QImage scaleImage(const QImage &image, const QSize& size, Qt::AspectRatioMode mode=Qt::IgnoreAspectRatio ); - QString cStringWithEncoding( const char *c_str, const QString& charset ); QColor contrastColor( const QColor& ); -/** - * @brief saveImage saves a QImage to a FileName, making sure that the directory exists. - * @param fileName - * @param image - * @param format the storage format for QImage::save(), usually "JPEG" - */ -void saveImage( const DB::FileName& fileName, const QImage& image, const char* format ); } #endif /* UTIL_H */ // vi:expandtab:tabstop=4 shiftwidth=4: