diff --git a/core/dplugins/generic/tools/printcreator/manager/advprinttask.cpp b/core/dplugins/generic/tools/printcreator/manager/advprinttask.cpp index 60f9d05d82..73c7c8855a 100644 --- a/core/dplugins/generic/tools/printcreator/manager/advprinttask.cpp +++ b/core/dplugins/generic/tools/printcreator/manager/advprinttask.cpp @@ -1,733 +1,737 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-11-07 * Description : a tool to print images * * Copyright (C) 2017-2020 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. * * ============================================================ */ #include "advprinttask.h" // C++ includes #include // Qt includes #include #include #include #include // KDE includes #include // Local includes #include "advprintwizard.h" #include "advprintphoto.h" #include "advprintcaptionpage.h" #include "dmetadata.h" #include "dfileoperations.h" #include "dimg.h" #include "digikam_debug.h" #include "digikam_config.h" namespace DigikamGenericPrintCreatorPlugin { class Q_DECL_HIDDEN AdvPrintTask::Private { public: explicit Private() : settings(nullptr), mode(AdvPrintTask::PRINT), sizeIndex(0) { } public: AdvPrintSettings* settings; PrintMode mode; QSize size; int sizeIndex; }; // ------------------------------------------------------- AdvPrintTask::AdvPrintTask(AdvPrintSettings* const settings, PrintMode mode, const QSize& size, int sizeIndex) : ActionJob(), d(new Private) { d->settings = settings; d->mode = mode; d->size = size; d->sizeIndex = sizeIndex; } AdvPrintTask::~AdvPrintTask() { cancel(); delete d; } void AdvPrintTask::run() { switch (d->mode) { case PREPAREPRINT: qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Start prepare to print"; preparePrint(); emit signalDone(!m_cancel); qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Prepare to print is done"; break; case PRINT: qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Start to print"; - if (d->settings->printerName != d->settings->outputName(AdvPrintSettings::FILES) && - d->settings->printerName != d->settings->outputName(AdvPrintSettings::GIMP)) + if ((d->settings->printerName != d->settings->outputName(AdvPrintSettings::FILES)) && + (d->settings->printerName != d->settings->outputName(AdvPrintSettings::GIMP))) { printPhotos(); emit signalDone(!m_cancel); } else { QStringList files = printPhotosToFile(); if (d->settings->printerName == d->settings->outputName(AdvPrintSettings::GIMP)) { d->settings->gimpFiles << files; } emit signalDone(!m_cancel && !files.isEmpty()); } qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Print is done"; break; default: // PREVIEW qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Start to compute preview"; QImage img(d->size, QImage::Format_ARGB32_Premultiplied); QPainter p(&img); p.setCompositionMode(QPainter::CompositionMode_Clear); p.fillRect(img.rect(), Qt::color0); p.setCompositionMode(QPainter::CompositionMode_SourceOver); paintOnePage(p, d->settings->photos, d->settings->outputLayouts->m_layouts, d->settings->currentPreviewPage, d->settings->disableCrop, true); p.end(); if (!m_cancel) + { emit signalPreview(img); + } qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Preview computation is done"; break; } } void AdvPrintTask::preparePrint() { int photoIndex = 0; for (QList::iterator it = d->settings->photos.begin() ; it != d->settings->photos.end() ; ++it) { AdvPrintPhoto* const photo = static_cast(*it); - if (photo && photo->m_cropRegion == QRect(-1, -1, -1, -1)) + if (photo && (photo->m_cropRegion == QRect(-1, -1, -1, -1))) { QRect* const curr = d->settings->getLayout(photoIndex, d->sizeIndex); photo->updateCropRegion(curr->width(), curr->height(), d->settings->outputLayouts->m_autoRotate); } photoIndex++; emit signalProgress(photoIndex); if (m_cancel) { signalMessage(i18n("Printing canceled"), true); return; } } } void AdvPrintTask::printPhotos() { AdvPrintPhotoSize* const layouts = d->settings->outputLayouts; QPrinter* const printer = d->settings->outputPrinter; Q_ASSERT(layouts); Q_ASSERT(printer); Q_ASSERT(layouts->m_layouts.count() > 1); QList photos = d->settings->photos; QPainter p; p.begin(printer); int current = 0; int pageCount = 1; bool printing = true; while (printing) { signalMessage(i18n("Processing page %1", pageCount), false); printing = paintOnePage(p, photos, layouts->m_layouts, current, d->settings->disableCrop); if (printing) { printer->newPage(); } pageCount++; emit signalProgress(current); if (m_cancel) { printer->abort(); signalMessage(i18n("Printing canceled"), true); return; } } p.end(); } QStringList AdvPrintTask::printPhotosToFile() { AdvPrintPhotoSize* const layouts = d->settings->outputLayouts; QString dir = d->settings->outputPath; Q_ASSERT(layouts); Q_ASSERT(!dir.isEmpty()); Q_ASSERT(layouts->m_layouts.count() > 1); - QList photos = d->settings->photos; + QList photos = d->settings->photos; QStringList files; - int current = 0; - int pageCount = 1; - bool printing = true; - QRect* const srcPage = layouts->m_layouts.at(0); + int current = 0; + int pageCount = 1; + bool printing = true; + QRect* const srcPage = layouts->m_layouts.at(0); while (printing) { // make a pixmap to save to file. Make it just big enough to show the // highest-dpi image on the page without losing data. double dpi = layouts->m_dpi; if (dpi == 0.0) { dpi = getMaxDPI(photos, layouts->m_layouts, current) * 1.1; (void)dpi; // Remove clang warnings. } int w = AdvPrintWizard::normalizedInt(srcPage->width()); int h = AdvPrintWizard::normalizedInt(srcPage->height()); QImage image(w, h, QImage::Format_ARGB32_Premultiplied); QPainter painter; painter.begin(&image); QString ext = d->settings->format(); QString name = QLatin1String("output"); QString filename = dir + QLatin1Char('/') + name + QLatin1Char('_') + QString::number(pageCount) + QLatin1Char('.') + ext; if (QFile::exists(filename) && - d->settings->conflictRule != FileSaveConflictBox::OVERWRITE) + (d->settings->conflictRule != FileSaveConflictBox::OVERWRITE)) { filename = DFileOperations::getUniqueFileUrl(QUrl::fromLocalFile(filename)).toLocalFile(); } signalMessage(i18n("Processing page %1", pageCount), false); printing = paintOnePage(painter, photos, layouts->m_layouts, current, d->settings->disableCrop); painter.end(); if (!image.save(filename, nullptr, 100)) { signalMessage(i18n("Could not save file %1", filename), true); break; } else { files.append(filename); signalMessage(i18n("Page %1 saved as %2", pageCount, filename), false); } pageCount++; emit signalProgress(current); if (m_cancel) { signalMessage(i18n("Printing canceled"), true); break; } } return files; } bool AdvPrintTask::paintOnePage(QPainter& p, const QList& photos, const QList& layouts, int& current, bool cropDisabled, bool useThumbnails) { if (layouts.isEmpty()) { qCWarning(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Invalid layout content"; return true; } if (photos.count() == 0) { qCWarning(DIGIKAM_DPLUGIN_GENERIC_LOG) << "no photo to print"; // no photos => last photo return true; } QList::const_iterator it = layouts.begin(); QRect* const srcPage = static_cast(*it); ++it; QRect* layout = static_cast(*it); // scale the page size to best fit the painter // size the rectangle based on the minimum image dimension int destW = p.window().width(); int destH = p.window().height(); int srcW = srcPage->width(); int srcH = srcPage->height(); if (destW < destH) { destH = AdvPrintWizard::normalizedInt((double) destW * ((double) srcH / (double) srcW)); if (destH > p.window().height()) { destH = p.window().height(); destW = AdvPrintWizard::normalizedInt((double) destH * ((double) srcW / (double) srcH)); } } else { destW = AdvPrintWizard::normalizedInt((double) destH * ((double) srcW / (double) srcH)); if (destW > p.window().width()) { destW = p.window().width(); destH = AdvPrintWizard::normalizedInt((double) destW * ((double) srcH / (double) srcW)); } } - double xRatio = (double) destW / (double) srcPage->width(); - double yRatio = (double) destH / (double) srcPage->height(); - int left = (p.window().width() - destW) / 2; - int top = (p.window().height() - destH) / 2; + double xRatio1 = (double) destW / (double) srcPage->width(); + double yRatio1 = (double) destH / (double) srcPage->height(); + int left = (p.window().width() - destW) / 2; + int top = (p.window().height() - destH) / 2; // FIXME: may not want to erase the background page p.eraseRect(left, top, - AdvPrintWizard::normalizedInt((double) srcPage->width() * xRatio), - AdvPrintWizard::normalizedInt((double) srcPage->height() * yRatio)); + AdvPrintWizard::normalizedInt((double) srcPage->width() * xRatio1), + AdvPrintWizard::normalizedInt((double) srcPage->height() * yRatio1)); for ( ; (current < photos.count()) && !m_cancel ; ++current) { AdvPrintPhoto* const photo = photos.at(current); // crop QImage img; if (useThumbnails) { img = photo->thumbnail().copyQImage(); } else { img = photo->loadPhoto().copyQImage(); } // next, do we rotate? if (photo->m_rotation != 0) { // rotate QMatrix matrix; matrix.rotate(photo->m_rotation); img = img.transformed(matrix); } - if (useThumbnails) + if (useThumbnails) { // scale the crop region to thumbnail coords - double xRatio = 0.0; - double yRatio = 0.0; + double xRatio2 = 0.0; + double yRatio2 = 0.0; if (photo->thumbnail().width() != 0) { - xRatio = (double)photo->thumbnail().width() / (double)photo->width(); + xRatio2 = (double)photo->thumbnail().width() / (double)photo->width(); } if (photo->thumbnail().height() != 0) { - yRatio = (double)photo->thumbnail().height() / (double)photo->height(); + yRatio2 = (double)photo->thumbnail().height() / (double)photo->height(); } - int x1 = AdvPrintWizard::normalizedInt((double)photo->m_cropRegion.left() * xRatio); - int y1 = AdvPrintWizard::normalizedInt((double)photo->m_cropRegion.top() * yRatio); - int w = AdvPrintWizard::normalizedInt((double)photo->m_cropRegion.width() * xRatio); - int h = AdvPrintWizard::normalizedInt((double)photo->m_cropRegion.height() * yRatio); + int x1 = AdvPrintWizard::normalizedInt((double)photo->m_cropRegion.left() * xRatio2); + int y1 = AdvPrintWizard::normalizedInt((double)photo->m_cropRegion.top() * yRatio2); + int w = AdvPrintWizard::normalizedInt((double)photo->m_cropRegion.width() * xRatio2); + int h = AdvPrintWizard::normalizedInt((double)photo->m_cropRegion.height() * yRatio2); img = img.copy(QRect(x1, y1, w, h)); } else if (!cropDisabled) { img = img.copy(photo->m_cropRegion); } - int x1 = AdvPrintWizard::normalizedInt((double) layout->left() * xRatio); - int y1 = AdvPrintWizard::normalizedInt((double) layout->top() * yRatio); - int w = AdvPrintWizard::normalizedInt((double) layout->width() * xRatio); - int h = AdvPrintWizard::normalizedInt((double) layout->height() * yRatio); + int x1 = AdvPrintWizard::normalizedInt((double) layout->left() * xRatio1); + int y1 = AdvPrintWizard::normalizedInt((double) layout->top() * yRatio1); + int w = AdvPrintWizard::normalizedInt((double) layout->width() * xRatio1); + int h = AdvPrintWizard::normalizedInt((double) layout->height() * yRatio1); QRect rectViewPort = p.viewport(); QRect newRectViewPort = QRect(x1 + left, y1 + top, w, h); QSize imageSize = img.size(); /* qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Image " << photo->filename << " size " << imageSize; qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "viewport size " << newRectViewPort.size(); */ QPoint point; if (cropDisabled) { imageSize.scale(newRectViewPort.size(), Qt::KeepAspectRatio); int spaceLeft = (newRectViewPort.width() - imageSize.width()) / 2; int spaceTop = (newRectViewPort.height() - imageSize.height()) / 2; p.setViewport(spaceLeft + newRectViewPort.x(), spaceTop + newRectViewPort.y(), imageSize.width(), imageSize.height()); point = QPoint(newRectViewPort.x() + spaceLeft + imageSize.width(), newRectViewPort.y() + spaceTop + imageSize.height()); } else { p.setViewport(newRectViewPort); point = QPoint(x1 + left + w, y1 + top + w); } QRect rectWindow = p.window(); p.setWindow(img.rect()); p.drawImage(0, 0, img); p.setViewport(rectViewPort); p.setWindow(rectWindow); p.setBrushOrigin(point); if (photo->m_pAdvPrintCaptionInfo && (photo->m_pAdvPrintCaptionInfo->m_captionType != AdvPrintSettings::NONE)) { p.save(); QString caption = AdvPrintCaptionPage::captionFormatter(photo); qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Caption for" << photo->m_url << ":" << caption; // draw the text at (0,0), but we will translate and rotate the world // before drawing so the text will be in the correct location // next, do we rotate? int captionW = w - 2; double ratio = photo->m_pAdvPrintCaptionInfo->m_captionSize * 0.01; int captionH = (int)(qMin(w, h) * ratio); int orientatation = photo->m_rotation; int exifOrientation = DMetadata::ORIENTATION_NORMAL; (void)exifOrientation; // prevent cppcheck warning. if (photo->m_iface) { DItemInfo info(photo->m_iface->itemInfo(photo->m_url)); exifOrientation = info.orientation(); } else { DMetadata meta(photo->m_url.toLocalFile()); exifOrientation = meta.getItemOrientation(); } // ROT_90_HFLIP .. ROT_270 if ( (exifOrientation == DMetadata::ORIENTATION_ROT_90_HFLIP) || (exifOrientation == DMetadata::ORIENTATION_ROT_90) || (exifOrientation == DMetadata::ORIENTATION_ROT_90_VFLIP) || (exifOrientation == DMetadata::ORIENTATION_ROT_270) ) { orientatation = (photo->m_rotation + 270) % 360; // -90 degrees } if ((orientatation == 90) || (orientatation == 270)) { captionW = h; } p.rotate(orientatation); qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "rotation " << photo->m_rotation << " orientation " << orientatation; int tx = left; int ty = top; switch (orientatation) { case 0: { tx += x1 + 1; ty += y1 + (h - captionH - 1); break; } case 90: { tx = top + y1 + 1; ty = -left - x1 - captionH - 1; break; } case 180: { tx = -left - x1 - w + 1; ty = -top - y1 - (captionH + 1); break; } case 270: { tx = -top - y1 - h + 1; ty = left + x1 + (w - captionH) - 1; break; } } p.translate(tx, ty); printCaption(p, photo, captionW, captionH, caption); p.restore(); } // iterate to the next position ++it; layout = (it == layouts.end()) ? nullptr : static_cast(*it); if (layout == nullptr) { current++; break; } } // did we print the last photo? return (current < photos.count()); } double AdvPrintTask::getMaxDPI(const QList& photos, const QList& layouts, int current) { Q_ASSERT(layouts.count() > 1); QList::const_iterator it = layouts.begin(); QRect* layout = static_cast(*it); double maxDPI = 0.0; for ( ; current < photos.count() ; ++current) { AdvPrintPhoto* const photo = photos.at(current); double dpi = ((double) photo->m_cropRegion.width() + (double) photo->m_cropRegion.height()) / (((double) layout->width() / 1000.0) + ((double) layout->height() / 1000.0)); if (dpi > maxDPI) + { maxDPI = dpi; + } // iterate to the next position ++it; layout = (it == layouts.end()) ? nullptr : static_cast(*it); if (layout == nullptr) { break; } } return maxDPI; } void AdvPrintTask::printCaption(QPainter& p, AdvPrintPhoto* const photo, int captionW, int captionH, const QString& caption) { QStringList captionByLines; int captionIndex = 0; while (captionIndex < caption.length()) { QString newLine; bool breakLine = false; // End Of Line found int currIndex; // Caption QString current index // Check minimal lines dimension // TODO: fix length, maybe useless int captionLineLocalLength = 40; for (currIndex = captionIndex ; - currIndex < caption.length() && !breakLine ; ++currIndex) + (currIndex < caption.length()) && !breakLine ; ++currIndex) { if ((caption[currIndex] == QLatin1Char('\n')) || caption[currIndex].isSpace()) { breakLine = true; } } if (captionLineLocalLength <= (currIndex - captionIndex)) { captionLineLocalLength = (currIndex - captionIndex); } breakLine = false; - for (currIndex = captionIndex; - (currIndex <= captionIndex + captionLineLocalLength) && - (currIndex < caption.length()) && !breakLine; + for (currIndex = captionIndex ; + (currIndex <= (captionIndex + captionLineLocalLength)) && + (currIndex < caption.length()) && !breakLine ; ++currIndex) { breakLine = (caption[currIndex] == QLatin1Char('\n')) ? true : false; if (breakLine) { newLine.append(QLatin1Char(' ')); } else { newLine.append(caption[currIndex]); } } captionIndex = currIndex; // The line is ended if (captionIndex != caption.length()) { while (!newLine.endsWith(QLatin1Char(' '))) { newLine.truncate(newLine.length() - 1); captionIndex--; } } captionByLines.prepend(newLine.trimmed()); } QFont font(photo->m_pAdvPrintCaptionInfo->m_captionFont); font.setStyleHint(QFont::SansSerif); font.setPixelSize((int)(captionH * 0.8F)); // Font height ratio font.setWeight(QFont::Normal); QFontMetrics fm(font); int pixelsHigh = fm.height(); p.setFont(font); p.setPen(photo->m_pAdvPrintCaptionInfo->m_captionColor); qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Number of lines " << (int) captionByLines.count() ; // Now draw the caption // TODO allow printing captions per photo and on top, bottom and vertically for (int lineNumber = 0 ; - lineNumber < (int) captionByLines.count() ; ++lineNumber) + lineNumber < (int)captionByLines.count() ; ++lineNumber) { if (lineNumber > 0) { p.translate(0, - (int)(pixelsHigh)); } QRect r(0, 0, captionW, captionH); p.drawText(r, Qt::AlignLeft, captionByLines[lineNumber], &r); } } } // namespace DigikamGenericPrintCreatorPlugin diff --git a/core/dplugins/generic/tools/printcreator/tools/atkinspagelayouttree.cpp b/core/dplugins/generic/tools/printcreator/tools/atkinspagelayouttree.cpp index a76e43fa14..5f4ad80666 100644 --- a/core/dplugins/generic/tools/printcreator/tools/atkinspagelayouttree.cpp +++ b/core/dplugins/generic/tools/printcreator/tools/atkinspagelayouttree.cpp @@ -1,311 +1,312 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2007-02-13 * Description : Layouting photos on a page * * Copyright (C) 2007-2009 by Marcel Wiesweg * Copyright (C) 2006-2020 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. * * ============================================================ */ #include "atkinspagelayouttree.h" // C++ includes #include // Qt includes #include // Local includes #include "atkinspagelayoutnode.h" namespace DigikamGenericPrintCreatorPlugin { AtkinsPageLayoutTree::AtkinsPageLayoutTree(double aspectRatioPage, double absoluteAreaPage) : m_root(nullptr), m_count(0), m_aspectRatioPage(aspectRatioPage), m_absoluteAreaPage(absoluteAreaPage) { } AtkinsPageLayoutTree::AtkinsPageLayoutTree(const AtkinsPageLayoutTree& other) : m_root(nullptr) { (*this) = other; } AtkinsPageLayoutTree& AtkinsPageLayoutTree::operator=(const AtkinsPageLayoutTree& other) { if (this != &other) { delete m_root; m_root = new AtkinsPageLayoutNode(*(other.m_root)); m_count = other.m_count; m_aspectRatioPage = other.m_aspectRatioPage; m_absoluteAreaPage = other.m_absoluteAreaPage; } return *this; } AtkinsPageLayoutTree::~AtkinsPageLayoutTree() { delete m_root; } int AtkinsPageLayoutTree::addImage(double aspectRatio, double relativeArea) { int index = m_count; if (!m_root) { m_root = new AtkinsPageLayoutNode(aspectRatio, relativeArea, index); m_count++; return index; } // Section 2.1 AtkinsPageLayoutNode* bestTree = nullptr; double highScore = 0; for (int i = 0 ; i < m_count ; ++i) { for (int horizontal = 0 ; horizontal < 2 ; ++horizontal) { // create temporary tree AtkinsPageLayoutNode* candidateTree = new AtkinsPageLayoutNode(*m_root); // select the subtree which will be replace by a new internal node AtkinsPageLayoutNode* const candidateSubtree = candidateTree->nodeForIndex(i); // find parent node AtkinsPageLayoutNode* const parentNode = candidateTree->parentOf(candidateSubtree); // create new terminal node AtkinsPageLayoutNode* const newTerminalNode = new AtkinsPageLayoutNode(aspectRatio, relativeArea, index); // create new internal node AtkinsPageLayoutNode* const newInternalNode = new AtkinsPageLayoutNode(candidateSubtree, newTerminalNode, horizontal, index+1); // replace in tree if (parentNode) { // replace in tree parentNode->takeAndSetChild(candidateSubtree, newInternalNode); } else { // candidateTree is candidateSubtree is root candidateTree = newInternalNode; } // recompute sizes candidateTree->computeRelativeSizes(); double candidateScore = score(candidateTree, m_count+2); if (candidateScore > highScore) { highScore = candidateScore; delete bestTree; bestTree = candidateTree; } else { delete candidateTree; } } } delete m_root; m_root = bestTree; if (m_root) { m_root->computeDivisions(); } m_count += 2; return index; } /// Section 2.2.1 double AtkinsPageLayoutTree::score(AtkinsPageLayoutNode* const root, int nodeCount) { if (!root) { return 0; } double areaSum = 0; for (int i = 0 ; i < nodeCount ; ++i) { AtkinsPageLayoutNode* const node = root->nodeForIndex(i); if (node->type() == AtkinsPageLayoutNode::TerminalNode) { areaSum += node->relativeArea(); } } double minRatioPage = root->aspectRatio() < m_aspectRatioPage ? root->aspectRatio() : m_aspectRatioPage; double maxRatioPage = root->aspectRatio() > m_aspectRatioPage ? root->aspectRatio() : m_aspectRatioPage; return G() * (areaSum / root->relativeArea()) * (minRatioPage / maxRatioPage); } /// Section 2.2.2 double AtkinsPageLayoutTree::G() const { return 0.95 * 0.95; } /// Section 2.2.2 double AtkinsPageLayoutTree::absoluteArea(AtkinsPageLayoutNode* const node) { // min(a_pbb, a_page), max(a_pbb, a_page) double minRatioPage = m_root->aspectRatio() < m_aspectRatioPage ? m_root->aspectRatio() : m_aspectRatioPage; double maxRatioPage = m_root->aspectRatio() > m_aspectRatioPage ? m_root->aspectRatio() : m_aspectRatioPage; // A_pbb double absoluteAreaRoot = m_absoluteAreaPage * minRatioPage / maxRatioPage; if (node == m_root) { return absoluteAreaRoot; } // A_i + return (G() * node->relativeArea() / m_root->relativeArea() * absoluteAreaRoot); } QRectF AtkinsPageLayoutTree::drawingArea(int index, const QRectF& absoluteRectPage) { AtkinsPageLayoutNode* const node = m_root->nodeForIndex(index); if (!node) { return QRectF(); } // find out the "line of ancestry" of the node QList treePath; - AtkinsPageLayoutNode* parent = node; + AtkinsPageLayoutNode* parent1 = node; - while (parent) + while (parent1) { - treePath.prepend(parent); - parent = m_root->parentOf(parent); + treePath.prepend(parent1); + parent1 = m_root->parentOf(parent1); } // find out the rect of the page bounding box (the rect of the root node in the page rect) QRectF absoluteRect = rectInRect(absoluteRectPage, m_root->aspectRatio(), absoluteArea(m_root)); // go along the line of ancestry and narrow down the bounding rectangle, // as described in section 2.2.2 for (int i = 0 ; i < treePath.count() - 1 ; ++i) { - AtkinsPageLayoutNode* const parent = treePath[i]; - AtkinsPageLayoutNode* const child = treePath[i+1]; // only iterating to count-1 + AtkinsPageLayoutNode* const parent2 = treePath[i]; + AtkinsPageLayoutNode* const child = treePath[i+1]; // only iterating to count-1 - if (parent->type() == AtkinsPageLayoutNode::VerticalDivision) // side by side + if (parent2->type() == AtkinsPageLayoutNode::VerticalDivision) // side by side { - double leftWidth = absoluteRect.width() * parent->division(); + double leftWidth = absoluteRect.width() * parent2->division(); - if (child == parent->leftChild()) + if (child == parent2->leftChild()) { absoluteRect.setWidth(leftWidth); } else // right child { double rightWidth = absoluteRect.width() - leftWidth; absoluteRect.setWidth(rightWidth); absoluteRect.translate(leftWidth, 0); } } else // horizontal division: one on top of the other { // left child is topmost - double upperHeight = absoluteRect.height() * parent->division(); + double upperHeight = absoluteRect.height() * parent2->division(); - if (child == parent->leftChild()) + if (child == parent2->leftChild()) { absoluteRect.setHeight(upperHeight); } else // right child { double lowerHeight = absoluteRect.height() - upperHeight; absoluteRect.setHeight(lowerHeight); absoluteRect.translate(0, upperHeight); } } } return rectInRect(absoluteRect, node->aspectRatio(), absoluteArea(node)); } QRectF AtkinsPageLayoutTree::rectInRect(const QRectF &rect, double aspectRatio, double absoluteArea) { double width = std::sqrt(absoluteArea / aspectRatio); double height = std::sqrt(absoluteArea * aspectRatio); double x = rect.x() + (rect.width() - width) / 2; double y = rect.y() + (rect.height() - height) / 2; return QRectF(x, y, width, height); } } // Namespace Digikam diff --git a/core/dplugins/generic/tools/printcreator/wizard/advprintwizard.cpp b/core/dplugins/generic/tools/printcreator/wizard/advprintwizard.cpp index 1c0385d54c..445c8b4471 100644 --- a/core/dplugins/generic/tools/printcreator/wizard/advprintwizard.cpp +++ b/core/dplugins/generic/tools/printcreator/wizard/advprintwizard.cpp @@ -1,413 +1,415 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2008-01-11 * Description : a tool to print images * * Copyright (C) 2008-2012 by Angelo Naselli * Copyright (C) 2006-2020 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. * * ============================================================ */ #include "advprintwizard.h" // C++ includes #include // Qt includes #include #include #include #include #include #include #include #include #include #include #include #include // KDE includes #include #include #include // Local includes #include "digikam_globals.h" #include "digikam_debug.h" #include "advprintthread.h" #include "advprintintropage.h" #include "advprintalbumspage.h" #include "advprintphotopage.h" #include "advprintcaptionpage.h" #include "advprintcroppage.h" #include "advprintoutputpage.h" #include "advprintfinalpage.h" #include "templateicon.h" #include "dwizardpage.h" #include "dinfointerface.h" #include "dfiledialog.h" #include "dmetadata.h" namespace DigikamGenericPrintCreatorPlugin { class Q_DECL_HIDDEN AdvPrintWizard::Private { public: explicit Private() : introPage(nullptr), albumsPage(nullptr), photoPage(nullptr), captionPage(nullptr), cropPage(nullptr), outputPage(nullptr), finalPage(nullptr), settings(nullptr), previewThread(nullptr), iface(nullptr), tempPath(nullptr) { } AdvPrintIntroPage* introPage; AdvPrintAlbumsPage* albumsPage; AdvPrintPhotoPage* photoPage; AdvPrintCaptionPage* captionPage; AdvPrintCropPage* cropPage; AdvPrintOutputPage* outputPage; AdvPrintFinalPage* finalPage; AdvPrintSettings* settings; AdvPrintThread* previewThread; DInfoInterface* iface; QTemporaryDir* tempPath; }; AdvPrintWizard::AdvPrintWizard(QWidget* const parent, DInfoInterface* const iface) : DWizardDlg(parent, QLatin1String("PrintCreatorDialog")), d(new Private) { setWindowTitle(i18n("Print Creator")); - d->iface = iface; - d->settings = new AdvPrintSettings; - d->previewThread = new AdvPrintThread(this); + d->iface = iface; + d->settings = new AdvPrintSettings; + d->previewThread = new AdvPrintThread(this); KConfig config; KConfigGroup group = config.group("PrintCreator"); d->settings->readSettings(group); - d->introPage = new AdvPrintIntroPage(this, i18n("Welcome to Print Creator")); - d->albumsPage = new AdvPrintAlbumsPage(this, i18n("Albums Selection")); - d->photoPage = new AdvPrintPhotoPage(this, i18n("Select Page Layout")); - d->captionPage = new AdvPrintCaptionPage(this, i18n("Caption Settings")); - d->cropPage = new AdvPrintCropPage(this, i18n("Crop and Rotate Photos")); - d->outputPage = new AdvPrintOutputPage(this, i18n("Images Output Settings")); - d->finalPage = new AdvPrintFinalPage(this, i18n("Render Printing")); + d->introPage = new AdvPrintIntroPage(this, i18n("Welcome to Print Creator")); + d->albumsPage = new AdvPrintAlbumsPage(this, i18n("Albums Selection")); + d->photoPage = new AdvPrintPhotoPage(this, i18n("Select Page Layout")); + d->captionPage = new AdvPrintCaptionPage(this, i18n("Caption Settings")); + d->cropPage = new AdvPrintCropPage(this, i18n("Crop and Rotate Photos")); + d->outputPage = new AdvPrintOutputPage(this, i18n("Images Output Settings")); + d->finalPage = new AdvPrintFinalPage(this, i18n("Render Printing")); d->finalPage->setPhotoPage(d->photoPage); // ----------------------------------- connect(button(QWizard::CancelButton), SIGNAL(clicked()), this, SLOT(reject())); connect(d->photoPage->imagesList(), SIGNAL(signalImageListChanged()), d->captionPage, SLOT(slotUpdateImagesList())); connect(d->previewThread, SIGNAL(signalPreview(QImage)), this, SLOT(slotPreview(QImage))); - d->tempPath = new QTemporaryDir(); + d->tempPath = new QTemporaryDir(); d->settings->tempPath = d->tempPath->path(); installEventFilter(this); } AdvPrintWizard::~AdvPrintWizard() { d->previewThread->cancel(); KConfig config; KConfigGroup group = config.group("PrintCreator"); d->settings->writeSettings(group); delete d->settings; delete d->tempPath; delete d; } DInfoInterface* AdvPrintWizard::iface() const { return d->iface; } AdvPrintSettings* AdvPrintWizard::settings() const { return d->settings; } int AdvPrintWizard::nextId() const { if (d->settings->selMode == AdvPrintSettings::ALBUMS) { if (currentPage() == d->introPage) { return d->albumsPage->id(); } } else { if (currentPage() == d->introPage) { return d->photoPage->id(); } } if (d->settings->printerName == d->settings->outputName(AdvPrintSettings::FILES)) { if (currentPage() == d->cropPage) { return d->outputPage->id(); } } else { if (currentPage() == d->cropPage) { return d->finalPage->id(); } } return DWizardDlg::nextId(); } QList AdvPrintWizard::itemsList() const { QList urls; for (QList::iterator it = d->settings->photos.begin() ; it != d->settings->photos.end() ; ++it) { AdvPrintPhoto* const photo = static_cast(*it); urls << photo->m_url; } return urls; } void AdvPrintWizard::setItemsList(const QList& fileList) { QList list = fileList; for (int i = 0 ; i < d->settings->photos.count() ; ++i) { delete d->settings->photos.at(i); } d->settings->photos.clear(); if (list.isEmpty() && d->iface) { list = d->iface->currentSelectedItems(); } for (int i = 0 ; i < list.count() ; ++i) { AdvPrintPhoto* const photo = new AdvPrintPhoto(150, d->iface); photo->m_url = list[i]; photo->m_first = true; d->settings->photos.append(photo); } d->cropPage->ui()->BtnCropPrev->setEnabled(false); if (d->settings->photos.count() == 1) { d->cropPage->ui()->BtnCropNext->setEnabled(false); } emit currentIdChanged(d->photoPage->id()); } void AdvPrintWizard::updateCropFrame(AdvPrintPhoto* const photo, int photoIndex) { int sizeIndex = d->photoPage->ui()->ListPhotoSizes->currentRow(); AdvPrintPhotoSize* const s = d->settings->photosizes.at(sizeIndex); d->cropPage->ui()->cropFrame->init(photo, d->settings->getLayout(photoIndex, sizeIndex)->width(), d->settings->getLayout(photoIndex, sizeIndex)->height(), s->m_autoRotate, true); d->cropPage->ui()->LblCropPhoto->setText(i18n("Photo %1 of %2", photoIndex + 1, d->settings->photos.count())); } void AdvPrintWizard::previewPhotos() { if (d->settings->photosizes.isEmpty()) { qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Photo sizes is null"; return; } d->previewThread->cancel(); // get the selected layout int photoCount = d->settings->photos.count(); - int curr = d->photoPage->ui()->ListPhotoSizes->currentRow(); - AdvPrintPhotoSize* const s = d->settings->photosizes.at(curr); + int curr1 = d->photoPage->ui()->ListPhotoSizes->currentRow(); + AdvPrintPhotoSize* const s = d->settings->photosizes.at(curr1); int emptySlots = 0; int pageCount = 0; int photosPerPage = 0; if (photoCount > 0) { // how many pages? Recall that the first layout item is the paper size photosPerPage = s->m_layouts.count() - 1; int remainder = photoCount % photosPerPage; if (remainder > 0) { emptySlots = photosPerPage - remainder; } pageCount = photoCount / photosPerPage; if (emptySlots > 0) { pageCount++; } } d->photoPage->ui()->LblPhotoCount->setText(QString::number(photoCount)); d->photoPage->ui()->LblSheetsPrinted->setText(QString::number(pageCount)); d->photoPage->ui()->LblEmptySlots->setText(QString::number(emptySlots)); if (photoCount > 0) { // photo previews // preview the first page. // find the first page of photos int count = 0; int page = 0; int current = 0; for (QList::iterator it = d->settings->photos.begin() ; it != d->settings->photos.end() ; ++it) { AdvPrintPhoto* const photo = static_cast(*it); if (page == d->settings->currentPreviewPage) { photo->m_cropRegion.setRect(-1, -1, -1, -1); - photo->m_rotation = 0; - QRect* const curr = s->m_layouts.at(count + 1); - photo->updateCropRegion(curr->width(), - curr->height(), + photo->m_rotation = 0; + QRect* const curr2 = s->m_layouts.at(count + 1); + photo->updateCropRegion(curr2->width(), + curr2->height(), s->m_autoRotate); } count++; if (count >= photosPerPage) { if (page == d->settings->currentPreviewPage) + { break; + } page++; current += photosPerPage; count = 0; } } // send this photo list to the painter AdvPrintSettings* const pwSettings = new AdvPrintSettings; pwSettings->photos = d->settings->photos; pwSettings->outputLayouts = s; pwSettings->currentPreviewPage = current; pwSettings->disableCrop = d->cropPage->ui()->m_disableCrop->isChecked(); d->previewThread->preview(pwSettings, d->photoPage->ui()->BmpFirstPagePreview->size()); d->previewThread->start(); } else { d->photoPage->ui()->BmpFirstPagePreview->clear(); d->photoPage->ui()->LblPreview->clear(); d->photoPage->ui()->LblPreview->setText(i18n("Page %1 of %2", 0, 0)); d->photoPage->manageBtnPreviewPage(); d->photoPage->update(); } } void AdvPrintWizard::slotPreview(const QImage& img) { qCDebug(DIGIKAM_DPLUGIN_GENERIC_LOG) << "Receive Preview" << img.size(); d->photoPage->ui()->BmpFirstPagePreview->clear(); d->photoPage->ui()->BmpFirstPagePreview->setPixmap(QPixmap::fromImage(img)); d->photoPage->ui()->LblPreview->setText(i18n("Page %1 of %2", d->settings->currentPreviewPage + 1, d->photoPage->getPageCount())); d->photoPage->manageBtnPreviewPage(); d->photoPage->update(); } int AdvPrintWizard::normalizedInt(double n) { return (int)(n + 0.5); } bool AdvPrintWizard::eventFilter(QObject* o, QEvent* e) { if (e && (e->type() == QEvent::KeyRelease)) { QKeyEvent* const k = (QKeyEvent*)e; if ((k->key() == Qt::Key_PageUp) || (k->key() == Qt::Key_PageDown) || (k->key() == Qt::Key_Up) || (k->key() == Qt::Key_Down)) { if (currentPage() == d->cropPage) { // Pass the key event to move crop frame region. d->cropPage->ui()->cropFrame->setFocus(); QApplication::sendEvent(d->cropPage->ui()->cropFrame, e); return true; // eat event } } } return QWizard::eventFilter(o, e); } } // namespace DigikamGenericPrintCreatorPlugin diff --git a/core/dplugins/generic/tools/printcreator/wizard/advprintwizard.h b/core/dplugins/generic/tools/printcreator/wizard/advprintwizard.h index 2aa7524938..8562cec1b8 100644 --- a/core/dplugins/generic/tools/printcreator/wizard/advprintwizard.h +++ b/core/dplugins/generic/tools/printcreator/wizard/advprintwizard.h @@ -1,85 +1,85 @@ /* ============================================================ * * This file is a part of digiKam project * https://www.digikam.org * * Date : 2008-01-11 * Description : a tool to print images * * Copyright (C) 2008-2012 by Angelo Naselli * Copyright (C) 2006-2020 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. * * ============================================================ */ #ifndef DIGIKAM_ADV_PRINT_WIZARD_H #define DIGIKAM_ADV_PRINT_WIZARD_H // Qt includes #include // Local includes #include "advprintsettings.h" #include "ditemslist.h" #include "dinfointerface.h" #include "dwizarddlg.h" using namespace Digikam; namespace DigikamGenericPrintCreatorPlugin { class AdvPrintWizard : public DWizardDlg { Q_OBJECT public: explicit AdvPrintWizard(QWidget* const, DInfoInterface* const iface = nullptr); ~AdvPrintWizard(); void setItemsList(const QList& fileList = QList()); QList itemsList() const; DInfoInterface* iface() const; AdvPrintSettings* settings() const; /** * Update the pages to be printed and preview first/last pages. */ void previewPhotos(); void updateCropFrame(AdvPrintPhoto* const, int); - int nextId() const override; + int nextId() const override; static int normalizedInt(double n); private: bool eventFilter(QObject*, QEvent*) override; private Q_SLOTS: void slotPreview(const QImage&); private: class Private; Private* const d; }; } // namespace DigikamGenericPrintCreatorPlugin #endif // DIGIKAM_ADV_PRINT_WIZARD_H