diff --git a/core/libs/database/item/lister/itemlister_salbum.cpp b/core/libs/database/item/lister/itemlister_salbum.cpp index f119f24e74..e326e8e5bf 100644 --- a/core/libs/database/item/lister/itemlister_salbum.cpp +++ b/core/libs/database/item/lister/itemlister_salbum.cpp @@ -1,438 +1,438 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-03-20 * Description : Listing information from database - SAlbum helpers. * * Copyright (C) 2007-2012 by Marcel Wiesweg * Copyright (C) 2007-2019 by Gilles Caulier * Copyright (C) 2015 by Mohamed_Anwer * Copyright (C) 2018 by Mario Frank * * 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. * * ============================================================ */ #include "itemlister_p.h" namespace Digikam { void ItemLister::listSearch(ItemListerReceiver* const receiver, const QString& xml, int limit, qlonglong referenceImageId) { if (xml.isEmpty()) { return; } QList boundValues; QList values; QString sqlQuery; QString errMsg; // query head sqlQuery = QString::fromUtf8( "SELECT DISTINCT Images.id, Images.name, Images.album, " " Albums.albumRoot, " " ImageInformation.rating, Images.category, " " ImageInformation.format, ImageInformation.creationDate, " " Images.modificationDate, Images.fileSize, " " ImageInformation.width, ImageInformation.height, " " ImagePositions.latitudeNumber, ImagePositions.longitudeNumber " " FROM Images " " LEFT JOIN ImageInformation ON Images.id=ImageInformation.imageid " - " LEFT JOIN ImageMetadata ON Images.id=ImageMetadata.imageid " - " LEFT JOIN VideoMetadata ON Images.id=VideoMetadata.imageid " - " LEFT JOIN ImagePositions ON Images.id=ImagePositions.imageid " - " INNER JOIN Albums ON Albums.id=Images.album " + " LEFT JOIN ImageMetadata ON Images.id=ImageMetadata.imageid " + " LEFT JOIN VideoMetadata ON Images.id=VideoMetadata.imageid " + " LEFT JOIN ImagePositions ON Images.id=ImagePositions.imageid " + " INNER JOIN Albums ON Albums.id=Images.album " "WHERE Images.status=1 AND ( "); // query body ItemQueryBuilder builder; ItemQueryPostHooks hooks; sqlQuery += builder.buildQuery(xml, &boundValues, &hooks); if (limit > 0) { sqlQuery += QString::fromUtf8(" ) LIMIT %1;").arg(limit); } else { sqlQuery += QString::fromUtf8(" );"); } qCDebug(DIGIKAM_DATABASE_LOG) << "Search query:\n" << sqlQuery << "\n" << boundValues; bool executionSuccess; { CoreDbAccess access; executionSuccess = access.backend()->execSql(sqlQuery, boundValues, &values); if (!executionSuccess) { errMsg = access.backend()->lastError(); } } if (!executionSuccess) { receiver->error(errMsg); return; } qCDebug(DIGIKAM_DATABASE_LOG) << "Search result:" << values.size() / 14; QSet albumRoots = albumRootsToList(); int width, height; double lat, lon; CoreDbAccess access; for (QList::const_iterator it = values.constBegin() ; it != values.constEnd() ;) { ItemListerRecord record; record.imageID = (*it).toLongLong(); ++it; record.name = (*it).toString(); ++it; record.albumID = (*it).toInt(); ++it; record.albumRootID = (*it).toInt(); ++it; record.rating = (*it).toInt(); ++it; record.category = (DatabaseItem::Category)(*it).toInt(); ++it; record.format = (*it).toString(); ++it; record.creationDate = (*it).toDateTime(); ++it; record.modificationDate = (*it).toDateTime(); ++it; record.fileSize = d->toInt32BitSafe(it); ++it; width = (*it).toInt(); ++it; height = (*it).toInt(); ++it; lat = (*it).toDouble(); ++it; lon = (*it).toDouble(); ++it; record.currentSimilarity = SimilarityDbAccess().db()->getImageSimilarity(record.imageID, referenceImageId); if (record.currentSimilarity < 0) { // Ignore nonexistence and invalid db entry. record.currentSimilarity = 0.0; } record.currentFuzzySearchReferenceImage = referenceImageId; if (d->listOnlyAvailableImages && !albumRoots.contains(record.albumRootID)) { continue; } if (!hooks.checkPosition(lat, lon)) { continue; } record.imageSize = QSize(width, height); receiver->receive(record); } } void ItemLister::listHaarSearch(ItemListerReceiver* const receiver, const QString& xml) { //qCDebug(DIGIKAM_GENERAL_LOG) << "Query: " << xml; // ------------------------------------------------ // read basic info SearchXmlReader reader(xml); reader.readToFirstField(); if (reader.fieldName() != QLatin1String("similarity")) { receiver->error(QLatin1String("Unsupported field name \"") + reader.fieldName() + QLatin1String("\" in Haar search")); return; } QStringRef type = reader.attributes().value(QLatin1String("type")); QStringRef numResultsString = reader.attributes().value(QLatin1String("numberofresults")); QStringRef thresholdString = reader.attributes().value(QLatin1String("threshold")); QStringRef maxThresholdString = reader.attributes().value(QLatin1String("maxthreshold")); QStringRef sketchTypeString = reader.attributes().value(QLatin1String("sketchtype")); double threshold = 0.9; double maxThreshold = 1.0; int numberOfResults = 20; HaarIface::SketchType sketchType = HaarIface::ScannedSketch; QList targetAlbums; // ------------------------------------------------ // read target albums SearchXmlReader albumsReader(xml); SearchXml::Element element; while ((element = albumsReader.readNext()) != SearchXml::End) { // Get the target albums, i.e. the albums in which the similar images must be located. if ((element == SearchXml::Field) && (albumsReader.fieldName().compare(QLatin1String("noeffect_targetAlbums")) == 0)) { targetAlbums = albumsReader.valueToIntList(); //qCDebug(DIGIKAM_GENERAL_LOG) << "Searching in " << targetAlbums.size() << " Albums"; break; } } // ------------------------------------------------- if (!numResultsString.isNull()) { numberOfResults = numResultsString.toString().toInt(); //qCDebug(DIGIKAM_GENERAL_LOG) << "Returning " << numberOfResults << " results"; } if (!thresholdString.isNull()) { threshold = qMax(thresholdString.toString().toDouble(), 0.1); //qCDebug(DIGIKAM_GENERAL_LOG) << "Minimum threshold: " << threshold; } if (!maxThresholdString.isNull()) { maxThreshold = qMax(maxThresholdString.toString().toDouble(), threshold); //qCDebug(DIGIKAM_GENERAL_LOG) << "Maximum threshold: " << maxThreshold; } if (!sketchTypeString.isNull() && sketchTypeString == QLatin1String("handdrawn")) { sketchType = HaarIface::HanddrawnSketch; } QMap imageSimilarityMap; if (type == QLatin1String("signature")) { QString sig = reader.value(); HaarIface iface; if (d->listOnlyAvailableImages) { iface.setAlbumRootsToSearch(albumRootsToList()); } imageSimilarityMap = iface.bestMatchesForSignature(sig, targetAlbums, numberOfResults, sketchType); } else if (type == QLatin1String("imageid")) { qlonglong id = reader.valueToLongLong(); HaarIface iface; if (d->listOnlyAvailableImages) { iface.setAlbumRootsToSearch(albumRootsToList()); } imageSimilarityMap = iface.bestMatchesForImageWithThreshold(id, threshold, maxThreshold, targetAlbums, HaarIface::DuplicatesSearchRestrictions::None, sketchType).second; } else if (type == QLatin1String("image")) { // If the given SAlbum contains a dropped image, get all images which are similar to this one. QString path = reader.value(); HaarIface iface; if (d->listOnlyAvailableImages) { iface.setAlbumRootsToSearch(albumRootsToList()); } imageSimilarityMap = iface.bestMatchesForImageWithThreshold(path, threshold,maxThreshold, targetAlbums, HaarIface::DuplicatesSearchRestrictions::None, sketchType).second; } listFromHaarSearch(receiver, imageSimilarityMap); } void ItemLister::listFromHaarSearch(ItemListerReceiver* const receiver, const QMap& imageSimilarityMap) { QList values; QString errMsg; bool executionSuccess = true; { // Generate the query that returns the similarity as constant for a given image id. CoreDbAccess access; DbEngineSqlQuery query = access.backend()->prepareQuery(QString::fromUtf8( "SELECT DISTINCT Images.id, Images.name, Images.album, " " Albums.albumRoot, " " ImageInformation.rating, Images.category, " " ImageInformation.format, ImageInformation.creationDate, " " Images.modificationDate, Images.fileSize, " " ImageInformation.width, ImageInformation.height " " FROM Images " " LEFT JOIN ImageInformation ON Images.id=ImageInformation.imageid " " LEFT JOIN Albums ON Albums.id=Images.album " " WHERE Images.status=1 AND Images.id = ?;")); qlonglong imageId; double similarity; // Iterate over the image similarity map and bind the image id and similarity to the query. for (QMap::const_iterator it = imageSimilarityMap.constBegin() ; it != imageSimilarityMap.constEnd() ; ++it) { similarity = it.value(); imageId = it.key(); query.bindValue(0, imageId); executionSuccess = access.backend()->exec(query); if (!executionSuccess) { errMsg = access.backend()->lastError(); break; } // Add the similarity to the table row. QList tableRow = access.backend()->readToList(query); tableRow.append(similarity); // append results to list values << tableRow; } } if (!executionSuccess) { receiver->error(errMsg); return; } int width, height; for (QList::const_iterator it = values.constBegin() ; it != values.constEnd() ; ) { ItemListerRecord record; record.imageID = (*it).toLongLong(); ++it; record.name = (*it).toString(); ++it; record.albumID = (*it).toInt(); ++it; record.albumRootID = (*it).toInt(); ++it; record.rating = (*it).toInt(); ++it; record.category = (DatabaseItem::Category)(*it).toInt(); ++it; record.format = (*it).toString(); ++it; record.creationDate = (*it).toDateTime(); ++it; record.modificationDate = (*it).toDateTime(); ++it; record.fileSize = d->toInt32BitSafe(it); ++it; width = (*it).toInt(); ++it; height = (*it).toInt(); ++it; record.imageSize = QSize(width, height); record.currentSimilarity = (*it).toDouble(); ++it; receiver->receive(record); } } void ItemLister::listAreaRange(ItemListerReceiver* const receiver, double lat1, double lat2, double lon1, double lon2) { QList values; QList boundValues; boundValues << lat1 << lat2 << lon1 << lon2; qCDebug(DIGIKAM_DATABASE_LOG) << "Listing area" << lat1 << lat2 << lon1 << lon2; CoreDbAccess access; access.backend()->execSql(QString::fromUtf8("SELECT DISTINCT Images.id, " " Albums.albumRoot, ImageInformation.rating, ImageInformation.creationDate, " " ImagePositions.latitudeNumber, ImagePositions.longitudeNumber " " FROM Images " " LEFT JOIN ImageInformation ON Images.id=ImageInformation.imageid " " INNER JOIN Albums ON Albums.id=Images.album " " INNER JOIN ImagePositions ON Images.id=ImagePositions.imageid " " WHERE Images.status=1 " " AND (ImagePositions.latitudeNumber>? AND ImagePositions.latitudeNumber? AND ImagePositions.longitudeNumber albumRoots = albumRootsToList(); double lat, lon; for (QList::const_iterator it = values.constBegin() ; it != values.constEnd() ; ) { ItemListerRecord record(d->allowExtraValues ? ItemListerRecord::ExtraValueFormat : ItemListerRecord::TraditionalFormat); record.imageID = (*it).toLongLong(); ++it; record.albumRootID = (*it).toInt(); ++it; record.rating = (*it).toInt(); ++it; record.creationDate = (*it).toDateTime(); ++it; lat = (*it).toDouble(); ++it; lon = (*it).toDouble(); ++it; if (d->listOnlyAvailableImages && !albumRoots.contains(record.albumRootID)) { continue; } record.extraValues << lat << lon; receiver->receive(record); } } } // namespace Digikam