From 6382335ec3344c3c3c3154f3b45c3765f43cb50b Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Tue, 20 Feb 2018 12:02:23 +0300 Subject: [PATCH 01/20] ~ --- OrderByDeviationProvider.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OrderByDeviationProvider.cpp b/OrderByDeviationProvider.cpp index 256dbff51..307312aad 100644 --- a/OrderByDeviationProvider.cpp +++ b/OrderByDeviationProvider.cpp @@ -1,8 +1,8 @@ #include "OrderByDeviationProvider.h" -OrderByDeviationProvider::OrderByDeviationProvider(const DeviationProvider& settings) - : m_deviationProvider(&settings) { +OrderByDeviationProvider::OrderByDeviationProvider(const DeviationProvider& deviationProvider) + : m_deviationProvider(&deviationProvider) { } bool OrderByDeviationProvider::precedes(const PageId& lhs_page, From 82e8395bf054354594e547f2ce719c701de1e6c6 Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Wed, 21 Feb 2018 13:40:19 +0300 Subject: [PATCH 02/20] ~ PhysicalTransformation class removed. Its functionality has been replaced by UnitsConverter::transform method. UnitsConverter allows to get transformations for any units but not only pixels and millimetres. --- CMakeLists.txt | 1 - PhysicalTransformation.cpp | 31 ----------------- PhysicalTransformation.h | 44 ------------------------- UnitsConverter.cpp | 8 +++++ UnitsConverter.h | 3 ++ filters/page_layout/ImageView.cpp | 16 +++++---- filters/page_layout/ImageView.h | 5 +-- filters/page_layout/Utils.cpp | 12 +++---- filters/select_content/PhysSizeCalc.cpp | 4 +-- 9 files changed, 31 insertions(+), 93 deletions(-) delete mode 100644 PhysicalTransformation.cpp delete mode 100644 PhysicalTransformation.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f998ccf4..8b4f4a810 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -475,7 +475,6 @@ SET( PageSelectionAccessor.cpp PageSelectionAccessor.h PageSelectionProvider.h ContentSpanFinder.cpp ContentSpanFinder.h - PhysicalTransformation.cpp PhysicalTransformation.h ImageTransformation.cpp ImageTransformation.h ImagePixmapUnion.h ImageViewBase.cpp ImageViewBase.h diff --git a/PhysicalTransformation.cpp b/PhysicalTransformation.cpp deleted file mode 100644 index 730e34642..000000000 --- a/PhysicalTransformation.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - Scan Tailor - Interactive post-processing tool for scanned pages. - Copyright (C) 2007-2008 Joseph Artsimovich - - 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 3 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. If not, see . - */ - -#include "PhysicalTransformation.h" -#include "Dpi.h" -#include "imageproc/Constants.h" - -using namespace imageproc::constants; - -PhysicalTransformation::PhysicalTransformation(const Dpi& dpi) { - const double xscale = dpi.horizontal() * (DPI2DPM / 1000.0); - const double yscale = dpi.vertical() * (DPI2DPM / 1000.0); - m_mmToPixels.scale(xscale, yscale); - m_pixelsToMM.scale(1.0 / xscale, 1.0 / yscale); -} - diff --git a/PhysicalTransformation.h b/PhysicalTransformation.h deleted file mode 100644 index 1ab70c512..000000000 --- a/PhysicalTransformation.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - Scan Tailor - Interactive post-processing tool for scanned pages. - Copyright (C) 2007-2008 Joseph Artsimovich - - 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 3 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. If not, see . - */ - -#ifndef PHYSICALTRANSFORMATION_H_ -#define PHYSICALTRANSFORMATION_H_ - -#include - -class Dpi; - -class PhysicalTransformation { -public: - explicit PhysicalTransformation(const Dpi& dpi); - - const QTransform& pixelsToMM() const { - return m_pixelsToMM; - } - - const QTransform& mmToPixels() const { - return m_mmToPixels; - } - -private: - QTransform m_pixelsToMM; - QTransform m_mmToPixels; -}; - - -#endif diff --git a/UnitsConverter.cpp b/UnitsConverter.cpp index d2f22c751..786d2403f 100644 --- a/UnitsConverter.cpp +++ b/UnitsConverter.cpp @@ -91,6 +91,14 @@ void UnitsConverter::convert(double& horizontalValue, } } +QTransform UnitsConverter::transform(Units fromUnits, Units toUnits) const { + double xScaleFactor = 1.0; + double yScaleFactor = 1.0; + convert(xScaleFactor, yScaleFactor, fromUnits, toUnits); + + return QTransform().scale(xScaleFactor, yScaleFactor); +} + const Dpi& UnitsConverter::getDpi() const { return dpi; } diff --git a/UnitsConverter.h b/UnitsConverter.h index 28094b050..ecc8ea192 100644 --- a/UnitsConverter.h +++ b/UnitsConverter.h @@ -3,6 +3,7 @@ #define SCANTAILOR_UNITSCONVERTER_H +#include #include "Dpi.h" #include "Units.h" @@ -17,6 +18,8 @@ class UnitsConverter { void convert(double& horizontalValue, double& verticalValue, Units fromUnits, Units toUnits) const; + QTransform transform(Units fromUnits, Units toUnits) const; + const Dpi& getDpi() const; void setDpi(const Dpi& dpi); diff --git a/filters/page_layout/ImageView.cpp b/filters/page_layout/ImageView.cpp index a939c9ff6..14c82d50a 100644 --- a/filters/page_layout/ImageView.cpp +++ b/filters/page_layout/ImageView.cpp @@ -27,6 +27,7 @@ #include #include #include +#include using namespace imageproc; @@ -48,7 +49,8 @@ namespace page_layout { m_zoomHandler(*this), m_ptrSettings(settings), m_pageId(page_id), - m_physXform(xform.origDpi()), + m_pixelsToMmXform(UnitsConverter(xform.origDpi()).transform(PIXELS, MILLIMETRES)), + m_mmToPixelsXform(m_pixelsToMmXform.inverted()), m_innerRect(adapted_content_rect), m_aggregateHardSizeMM(settings->getAggregateHardSizeMM()), m_committedAggregateHardSizeMM(m_aggregateHardSizeMM), @@ -509,8 +511,8 @@ namespace page_layout { * m_aggregateHardSizeMM and m_alignment, updates the displayed area. */ void ImageView::recalcBoxesAndFit(const Margins& margins_mm) { - const QTransform virt_to_mm(virtualToImage() * m_physXform.pixelsToMM()); - const QTransform mm_to_virt(m_physXform.mmToPixels() * imageToVirtual()); + const QTransform virt_to_mm(virtualToImage() * m_pixelsToMmXform); + const QTransform mm_to_virt(m_mmToPixelsXform * imageToVirtual()); QPolygonF poly_mm(virt_to_mm.map(m_innerRect)); Utils::extendPolyRectWithMargins(poly_mm, margins_mm); @@ -610,7 +612,7 @@ namespace page_layout { QPointF(m_middleRect.right(), center.y()) ); - const QTransform virt_to_mm(virtualToImage() * m_physXform.pixelsToMM()); + const QTransform virt_to_mm(virtualToImage() * m_pixelsToMmXform); Margins margins; margins.setTop(virt_to_mm.map(top_margin_line).length()); @@ -626,8 +628,8 @@ namespace page_layout { * and m_alignment. */ void ImageView::recalcOuterRect() { - const QTransform virt_to_mm(virtualToImage() * m_physXform.pixelsToMM()); - const QTransform mm_to_virt(m_physXform.mmToPixels() * imageToVirtual()); + const QTransform virt_to_mm(virtualToImage() * m_pixelsToMmXform); + const QTransform mm_to_virt(m_mmToPixelsXform * imageToVirtual()); QPolygonF poly_mm(virt_to_mm.map(m_middleRect)); @@ -651,7 +653,7 @@ namespace page_layout { } QSizeF ImageView::origRectToSizeMM(const QRectF& rect) const { - const QTransform virt_to_mm(virtualToImage() * m_physXform.pixelsToMM()); + const QTransform virt_to_mm(virtualToImage() * m_pixelsToMmXform); const QLineF hor_line(rect.topLeft(), rect.topRight()); const QLineF vert_line(rect.topLeft(), rect.bottomLeft()); diff --git a/filters/page_layout/ImageView.h b/filters/page_layout/ImageView.h index 8e25922ff..d7e398abb 100644 --- a/filters/page_layout/ImageView.h +++ b/filters/page_layout/ImageView.h @@ -21,7 +21,6 @@ #include "ImageViewBase.h" #include "ImageTransformation.h" -#include "PhysicalTransformation.h" #include "InteractionHandler.h" #include "DragHandler.h" #include "ZoomHandler.h" @@ -176,7 +175,9 @@ namespace page_layout { * assuming that point (0, 0) in pixel coordinates corresponds to point * (0, 0) in millimeter coordinates. */ - const PhysicalTransformation m_physXform; + const QTransform m_pixelsToMmXform; + const QTransform m_mmToPixelsXform; + const ImageTransformation m_xform; /** diff --git a/filters/page_layout/Utils.cpp b/filters/page_layout/Utils.cpp index 99ed7886f..ee41ff5cd 100644 --- a/filters/page_layout/Utils.cpp +++ b/filters/page_layout/Utils.cpp @@ -21,8 +21,8 @@ #include "Alignment.h" #include "Params.h" #include "ImageTransformation.h" -#include "PhysicalTransformation.h" #include +#include namespace page_layout { QRectF Utils::adaptContentRect(const ImageTransformation& xform, const QRectF& content_rect) { @@ -37,8 +37,8 @@ namespace page_layout { } QSizeF Utils::calcRectSizeMM(const ImageTransformation& xform, const QRectF& rect) { - const PhysicalTransformation phys_xform(xform.origDpi()); - const QTransform virt_to_mm(xform.transformBack() * phys_xform.pixelsToMM()); + const QTransform virt_to_mm(xform.transformBack() + * UnitsConverter(xform.origDpi()).transform(PIXELS, MILLIMETRES)); const QLineF hor_line(rect.topLeft(), rect.topRight()); const QLineF ver_line(rect.topLeft(), rect.bottomLeft()); @@ -304,9 +304,9 @@ namespace page_layout { const Params& params, const QSizeF& aggregate_hard_size_mm, const QRectF& agg_content_rect) { - const PhysicalTransformation phys_xform(xform.origDpi()); + const QTransform pixelsToMmTransform(UnitsConverter(xform.origDpi()).transform(PIXELS, MILLIMETRES)); - QPolygonF poly_mm(phys_xform.pixelsToMM().map(content_rect_phys)); + QPolygonF poly_mm(pixelsToMmTransform.map(content_rect_phys)); extendPolyRectWithMargins(poly_mm, params.hardMarginsMM()); const QSizeF hard_size_mm( @@ -321,7 +321,7 @@ namespace page_layout { extendPolyRectWithMargins(poly_mm, soft_margins_mm); - return phys_xform.mmToPixels().map(poly_mm); + return pixelsToMmTransform.inverted().map(poly_mm); } QPointF Utils::getRightUnitVector(const QPolygonF& poly_rect) { diff --git a/filters/select_content/PhysSizeCalc.cpp b/filters/select_content/PhysSizeCalc.cpp index a0ecbfda5..12df21caa 100644 --- a/filters/select_content/PhysSizeCalc.cpp +++ b/filters/select_content/PhysSizeCalc.cpp @@ -16,15 +16,15 @@ along with this program. If not, see . */ +#include #include "PhysSizeCalc.h" #include "ImageTransformation.h" -#include "PhysicalTransformation.h" namespace select_content { PhysSizeCalc::PhysSizeCalc() = default; PhysSizeCalc::PhysSizeCalc(const ImageTransformation& xform) - : m_virtToPhys(xform.transformBack() * PhysicalTransformation(xform.origDpi()).pixelsToMM()) { + : m_virtToPhys(xform.transformBack() * UnitsConverter(xform.origDpi()).transform(PIXELS, MILLIMETRES)) { } QSizeF PhysSizeCalc::sizeMM(const QRectF& rect_px) const { From 95cfb28d72d5c01a616dcd0748073034412ecb9b Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Wed, 21 Feb 2018 13:42:35 +0300 Subject: [PATCH 03/20] ~ Pages are now sorted by the physical size of the content area but not pixel one. --- filters/select_content/OrderByHeightProvider.cpp | 4 ++-- filters/select_content/OrderByWidthProvider.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/filters/select_content/OrderByHeightProvider.cpp b/filters/select_content/OrderByHeightProvider.cpp index 9c6117c00..ffa9dab18 100644 --- a/filters/select_content/OrderByHeightProvider.cpp +++ b/filters/select_content/OrderByHeightProvider.cpp @@ -34,11 +34,11 @@ namespace select_content { QSizeF lhs_size; if (lhs_params) { - lhs_size = lhs_params->contentRect().size(); + lhs_size = lhs_params->contentSizeMM(); } QSizeF rhs_size; if (rhs_params) { - rhs_size = rhs_params->contentRect().size(); + rhs_size = rhs_params->contentSizeMM(); } const bool lhs_valid = !lhs_incomplete && lhs_size.isValid(); diff --git a/filters/select_content/OrderByWidthProvider.cpp b/filters/select_content/OrderByWidthProvider.cpp index 68b8f0e13..71765cedd 100644 --- a/filters/select_content/OrderByWidthProvider.cpp +++ b/filters/select_content/OrderByWidthProvider.cpp @@ -34,11 +34,11 @@ namespace select_content { QSizeF lhs_size; if (lhs_params) { - lhs_size = lhs_params->contentRect().size(); + lhs_size = lhs_params->contentSizeMM(); } QSizeF rhs_size; if (rhs_params) { - rhs_size = rhs_params->contentRect().size(); + rhs_size = rhs_params->contentSizeMM(); } const bool lhs_valid = !lhs_incomplete && lhs_size.isValid(); From 0689f45302c6db3e82efcb35f1e4b677df101e8e Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Wed, 21 Feb 2018 00:43:29 +0300 Subject: [PATCH 04/20] ~ Performance optimization: std::map => std::unordered_map. Update: * No more use of QString::toStdString for QString hash calculation. * Occurrences of std::map with QString key replaced. (Relates to 03e0da7872991c9711c177bf1e5425c9ac6210c4) --- ImageId.h | 3 ++- RelinkingModel.h | 5 +++-- foundation/CMakeLists.txt | 2 +- foundation/Hashes.h | 25 +++++++++++++++++++++++++ foundation/PropertyFactory.h | 5 +++-- 5 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 foundation/Hashes.h diff --git a/ImageId.h b/ImageId.h index d1e2e2c0c..1299e809f 100644 --- a/ImageId.h +++ b/ImageId.h @@ -20,6 +20,7 @@ #define IMAGEID_H_ #include +#include class QFileInfo; @@ -84,7 +85,7 @@ namespace std { template<> struct hash { size_t operator()(const ImageId& imageId) const noexcept { - return (hash()(imageId.filePath().toStdString()) + return (hashes::hash()(imageId.filePath()) ^ hash()(imageId.page()) << 1); } }; diff --git a/RelinkingModel.h b/RelinkingModel.h index 79cddff60..a1dc77523 100644 --- a/RelinkingModel.h +++ b/RelinkingModel.h @@ -24,6 +24,7 @@ #include "RelinkablePath.h" #include "AbstractRelinker.h" #include "intrusive_ptr.h" +#include "Hashes.h" #include #include #include @@ -33,7 +34,7 @@ #include #include #include -#include +#include class RelinkingModel : public QAbstractListModel, public VirtualFunction1 { DECLARE_NON_COPYABLE(RelinkingModel) @@ -127,7 +128,7 @@ DECLARE_NON_COPYABLE(RelinkingModel) void swap(Relinker& other); private: - std::map m_mappings; + std::unordered_map> m_mappings; }; diff --git a/foundation/CMakeLists.txt b/foundation/CMakeLists.txt index fed2e9029..c8d651303 100644 --- a/foundation/CMakeLists.txt +++ b/foundation/CMakeLists.txt @@ -28,7 +28,7 @@ SET( PriorityQueue.h Grid.h ValueConv.h -) + Hashes.h) SOURCE_GROUP("Sources" FILES ${sources}) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) diff --git a/foundation/Hashes.h b/foundation/Hashes.h new file mode 100644 index 000000000..bc35d97a5 --- /dev/null +++ b/foundation/Hashes.h @@ -0,0 +1,25 @@ + +#ifndef SCANTAILOR_HASHES_H +#define SCANTAILOR_HASHES_H + +#include + +namespace hashes { + template + struct hash; + + template<> + struct hash { + std::size_t operator()(const QString& str) const noexcept { + const QChar* data = str.constData(); + std::size_t hash = 5381; + for (int i = 0; i < str.size(); ++i) { + hash = ((hash << 5) + hash) ^ ((data[i].row() << 8) | data[i].cell()); + } + + return hash; + } + }; +} + +#endif //SCANTAILOR_HASHES_H diff --git a/foundation/PropertyFactory.h b/foundation/PropertyFactory.h index 7ab3d0365..c00c8defc 100644 --- a/foundation/PropertyFactory.h +++ b/foundation/PropertyFactory.h @@ -21,8 +21,9 @@ #include "Property.h" #include "intrusive_ptr.h" +#include "Hashes.h" #include -#include +#include class QDomElement; @@ -38,7 +39,7 @@ class PropertyFactory { intrusive_ptr construct(const QDomElement& el) const; private: - typedef std::map Registry; + typedef std::unordered_map> Registry; Registry m_registry; }; From 01387c32a4652008fd62caf3fb8e4472557873b6 Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Wed, 21 Feb 2018 02:23:05 +0300 Subject: [PATCH 05/20] ~ Fixed: units weren't saved correctly when non-English localization used. --- DefaultParamsDialog.cpp | 2 +- StatusBarPanel.cpp | 2 +- Units.cpp | 28 ++++++++++++++++++++++++---- Units.h | 2 ++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/DefaultParamsDialog.cpp b/DefaultParamsDialog.cpp index 045f46eb7..b281c8de3 100644 --- a/DefaultParamsDialog.cpp +++ b/DefaultParamsDialog.cpp @@ -793,7 +793,7 @@ std::unique_ptr DefaultParamsDialog::buildParams() const { void DefaultParamsDialog::updateUnits(const Units units) { currentUnits = units; - unitsLabel->setText(unitsToString(units)); + unitsLabel->setText(unitsToLocalizedString(units)); { int decimals; diff --git a/StatusBarPanel.cpp b/StatusBarPanel.cpp index c1a7a294b..f7d0aaf09 100644 --- a/StatusBarPanel.cpp +++ b/StatusBarPanel.cpp @@ -121,7 +121,7 @@ void StatusBarPanel::physSizeChanged() { } ui.physSizeLine->setVisible(true); - ui.physSizeLabel->setText(QString("%1 x %2 %3").arg(width).arg(height).arg(unitsToString(units))); + ui.physSizeLabel->setText(QString("%1 x %2 %3").arg(width).arg(height).arg(unitsToLocalizedString(units))); } else { ui.physSizeLabel->clear(); ui.physSizeLine->setVisible(false); diff --git a/Units.cpp b/Units.cpp index 51edc40ec..07e7dc34d 100644 --- a/Units.cpp +++ b/Units.cpp @@ -6,16 +6,16 @@ QString unitsToString(Units units) { QString unitsStr; switch (units) { case PIXELS: - unitsStr = QObject::tr("px"); + unitsStr = "px"; break; case MILLIMETRES: - unitsStr = QObject::tr("mm"); + unitsStr = "mm"; break; case CENTIMETRES: - unitsStr = QObject::tr("cm"); + unitsStr = "cm"; break; case INCHES: - unitsStr = QObject::tr("in"); + unitsStr = "in"; break; } @@ -32,4 +32,24 @@ Units unitsFromString(const QString& string) { } else { return MILLIMETRES; } +} + +QString unitsToLocalizedString(Units units) { + QString unitsStr; + switch (units) { + case PIXELS: + unitsStr = QObject::tr("px"); + break; + case MILLIMETRES: + unitsStr = QObject::tr("mm"); + break; + case CENTIMETRES: + unitsStr = QObject::tr("cm"); + break; + case INCHES: + unitsStr = QObject::tr("in"); + break; + } + + return unitsStr; } \ No newline at end of file diff --git a/Units.h b/Units.h index a6be9dcdf..347907663 100644 --- a/Units.h +++ b/Units.h @@ -16,4 +16,6 @@ QString unitsToString(Units units); Units unitsFromString(const QString& string); +QString unitsToLocalizedString(Units units); + #endif //SCANTAILOR_UNITS_H From a47ede1e4eb6ca1fc63b1f349ae6b62eacf6ea21 Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Wed, 21 Feb 2018 17:11:40 +0300 Subject: [PATCH 06/20] ~ Fixed missing initializer. --- filters/select_content/ImageView.cpp | 3 ++- filters/select_content/ImageView.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/filters/select_content/ImageView.cpp b/filters/select_content/ImageView.cpp index 352bdcdf0..384c0e414 100644 --- a/filters/select_content/ImageView.cpp +++ b/filters/select_content/ImageView.cpp @@ -43,7 +43,8 @@ namespace select_content { m_contentRect(content_rect), m_pageRect(page_rect), m_minBoxSize(10.0, 10.0), - m_pageRectEnabled(page_rect_enabled) { + m_pageRectEnabled(page_rect_enabled), + m_pageRectReloadRequested(false) { setMouseTracking(true); interactionState().setDefaultStatusTip( diff --git a/filters/select_content/ImageView.h b/filters/select_content/ImageView.h index ac3933f9f..8a0416b62 100644 --- a/filters/select_content/ImageView.h +++ b/filters/select_content/ImageView.h @@ -111,6 +111,7 @@ namespace select_content { void pageRectMoveRequest(const QPolygonF& pos); + DraggablePoint m_contentRectCorners[4]; ObjectDragHandler m_contentRectCornerHandlers[4]; From d13ced916ef3bb43cc3e474c614cd9b2012efe74 Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Thu, 22 Feb 2018 15:33:46 +0300 Subject: [PATCH 07/20] ~ Default noise reduction value of the segmenter set to 7. --- filters/output/BlackWhiteOptions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filters/output/BlackWhiteOptions.cpp b/filters/output/BlackWhiteOptions.cpp index f0bb53aa9..a4c2766c6 100644 --- a/filters/output/BlackWhiteOptions.cpp +++ b/filters/output/BlackWhiteOptions.cpp @@ -203,7 +203,7 @@ namespace output { BlackWhiteOptions::ColorSegmenterOptions::ColorSegmenterOptions() : enabled(false), - noiseReduction(12), + noiseReduction(7), redThresholdAdjustment(0), greenThresholdAdjustment(0), blueThresholdAdjustment(0) { From c548a25bf74127546b34d0f8903ab581b9a79623 Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Thu, 22 Feb 2018 20:51:48 +0300 Subject: [PATCH 08/20] Deviation parameters added into the settings dialog. The deviation default settings have been calibrated. --- MainWindow.cpp | 7 +- MainWindow.h | 1 - SettingsDialog.cpp | 20 ++- filters/deskew/CacheDrivenTask.cpp | 8 +- filters/page_layout/CacheDrivenTask.cpp | 8 +- filters/page_layout/Settings.cpp | 3 - filters/select_content/CacheDrivenTask.cpp | 8 +- filters/select_content/Settings.cpp | 4 +- ui/SettingsDialog.ui | 172 +++++++++++++++++++-- 9 files changed, 202 insertions(+), 29 deletions(-) diff --git a/MainWindow.cpp b/MainWindow.cpp index a25b6405b..b27e12ce9 100644 --- a/MainWindow.cpp +++ b/MainWindow.cpp @@ -343,7 +343,6 @@ MainWindow::MainWindow() } } m_autoSaveProject = settings.value("settings/auto_save_project").toBool(); - m_highlightDeviation = settings.value("settings/highlight_deviation", true).toBool(); } MainWindow::~MainWindow() { @@ -1569,11 +1568,7 @@ void MainWindow::onSettingsChanged() { app->installLanguage(settings.value("settings/language").toString()); } - bool highlightDeviation = settings.value("settings/highlight_deviation").toBool(); - if (highlightDeviation != m_highlightDeviation) { - m_highlightDeviation = highlightDeviation; - m_ptrThumbSequence->invalidateAllThumbnails(); - } + m_ptrThumbSequence->invalidateAllThumbnails(); } void MainWindow::showAboutDialog() { diff --git a/MainWindow.h b/MainWindow.h index 120dfd839..23763ed4c 100644 --- a/MainWindow.h +++ b/MainWindow.h @@ -332,7 +332,6 @@ private slots: QTimer m_thumbResizeTimer; QTimer m_autoSaveTimer; bool m_autoSaveProject; - bool m_highlightDeviation; std::unique_ptr m_statusBarPanel; std::unique_ptr m_unitsMenuActionGroup; }; diff --git a/SettingsDialog.cpp b/SettingsDialog.cpp index 4b99b04c1..fd324f285 100644 --- a/SettingsDialog.cpp +++ b/SettingsDialog.cpp @@ -86,9 +86,18 @@ SettingsDialog::SettingsDialog(QWidget* parent) ui.languageBox->setEnabled(ui.languageBox->count() > 1); } + + ui.deskewDeviationCoefSB->setValue(settings.value("settings/deskewDeviationCoef", 1.5).toDouble()); + ui.deskewDeviationThresholdSB->setValue(settings.value("settings/deskewDeviationThreshold", 1.0).toDouble()); + ui.selectContentDeviationCoefSB->setValue(settings.value("settings/selectContentDeviationCoef", 0.35).toDouble()); + ui.selectContentDeviationThresholdSB->setValue( + settings.value("settings/selectContentDeviationThreshold", 1.0).toDouble() + ); + ui.marginsDeviationCoefSB->setValue(settings.value("settings/marginsDeviationCoef", 0.35).toDouble()); + ui.marginsDeviationThresholdSB->setValue(settings.value("settings/marginsDeviationThreshold", 1.0).toDouble()); connect(ui.buttonBox, SIGNAL(accepted()), SLOT(commitChanges())); - ui.AutoSaveProject->setChecked(settings.value("settings/auto_save_project").toBool()); + ui.autoSaveProjectCB->setChecked(settings.value("settings/auto_save_project").toBool()); ui.highlightDeviationCB->setChecked(settings.value("settings/highlight_deviation", true).toBool()); connect( @@ -102,7 +111,7 @@ SettingsDialog::~SettingsDialog() = default; void SettingsDialog::commitChanges() { QSettings settings; settings.setValue("settings/enable_opengl", ui.enableOpenglCb->isChecked()); - settings.setValue("settings/auto_save_project", ui.AutoSaveProject->isChecked()); + settings.setValue("settings/auto_save_project", ui.autoSaveProjectCB->isChecked()); settings.setValue("settings/highlight_deviation", ui.highlightDeviationCB->isChecked()); if (ui.colorSchemeBox->currentIndex() == 0) { settings.setValue("settings/color_scheme", "dark"); @@ -114,6 +123,13 @@ void SettingsDialog::commitChanges() { settings.setValue("settings/color_compression", ui.tiffCompressionColorBox->currentData().toInt()); settings.setValue("settings/language", ui.languageBox->currentData().toString()); + settings.setValue("settings/deskewDeviationCoef", ui.deskewDeviationCoefSB->value()); + settings.setValue("settings/deskewDeviationThreshold", ui.deskewDeviationThresholdSB->value()); + settings.setValue("settings/selectContentDeviationCoef", ui.selectContentDeviationCoefSB->value()); + settings.setValue("settings/selectContentDeviationThreshold", ui.selectContentDeviationThresholdSB->value()); + settings.setValue("settings/marginsDeviationCoef", ui.marginsDeviationCoefSB->value()); + settings.setValue("settings/marginsDeviationThreshold", ui.marginsDeviationThresholdSB->value()); + emit settingsChanged(); } diff --git a/filters/deskew/CacheDrivenTask.cpp b/filters/deskew/CacheDrivenTask.cpp index 25fcb86e6..52396b750 100644 --- a/filters/deskew/CacheDrivenTask.cpp +++ b/filters/deskew/CacheDrivenTask.cpp @@ -19,6 +19,7 @@ #include "CacheDrivenTask.h" #include +#include #include "Thumbnail.h" #include "IncompleteThumbnail.h" #include "Settings.h" @@ -67,6 +68,10 @@ namespace deskew { return; } + QSettings settings; + const double deviationCoef = settings.value("settings/deskewDeviationCoef", 1.5).toDouble(); + const double deviationThreshold = settings.value("settings/deskewDeviationThreshold", 1.0).toDouble(); + if (auto* thumb_col = dynamic_cast(collector)) { thumb_col->processThumbnail( std::unique_ptr( @@ -74,7 +79,8 @@ namespace deskew { thumb_col->thumbnailCache(), thumb_col->maxLogicalThumbSize(), page_info.imageId(), new_xform, - m_ptrSettings->deviationProvider().isDeviant(page_info.id(), 1.2, 0.3) + m_ptrSettings->deviationProvider().isDeviant( + page_info.id(), deviationCoef, deviationThreshold) ) ) ); diff --git a/filters/page_layout/CacheDrivenTask.cpp b/filters/page_layout/CacheDrivenTask.cpp index 50efe134f..77a2d66f2 100644 --- a/filters/page_layout/CacheDrivenTask.cpp +++ b/filters/page_layout/CacheDrivenTask.cpp @@ -19,6 +19,7 @@ #include "CacheDrivenTask.h" #include +#include #include "Settings.h" #include "Params.h" #include "Thumbnail.h" @@ -82,6 +83,10 @@ namespace page_layout { return; } + QSettings settings; + const double deviationCoef = settings.value("settings/marginsDeviationCoef", 0.35).toDouble(); + const double deviationThreshold = settings.value("settings/marginsDeviationThreshold", 1.0).toDouble(); + if (auto* thumb_col = dynamic_cast(collector)) { thumb_col->processThumbnail( std::unique_ptr( @@ -91,7 +96,8 @@ namespace page_layout { page_info.imageId(), *params, xform, content_rect_phys, xform.transform().map(page_rect_phys).boundingRect(), - m_ptrSettings->deviationProvider().isDeviant(page_info.id()) + m_ptrSettings->deviationProvider().isDeviant( + page_info.id(), deviationCoef, deviationThreshold) ) ) ); diff --git a/filters/page_layout/Settings.cpp b/filters/page_layout/Settings.cpp index 945eb64f1..c854745e9 100644 --- a/filters/page_layout/Settings.cpp +++ b/filters/page_layout/Settings.cpp @@ -414,9 +414,6 @@ namespace page_layout { auto it(m_items.find(pageId)); if (it != m_items.end()) { if (it->alignment.isNull()) { - const Margins& hardMarginsMM = it->hardMarginsMM; - const QSizeF& contentSizeMM = it->contentSizeMM; - return std::sqrt(it->hardWidthMM() * it->hardHeightMM() / 4 / 25.4); } else { return .0; diff --git a/filters/select_content/CacheDrivenTask.cpp b/filters/select_content/CacheDrivenTask.cpp index 724b24208..d4c836c1b 100644 --- a/filters/select_content/CacheDrivenTask.cpp +++ b/filters/select_content/CacheDrivenTask.cpp @@ -28,6 +28,7 @@ #include #include +#include namespace select_content { CacheDrivenTask::CacheDrivenTask(intrusive_ptr settings, @@ -69,6 +70,10 @@ namespace select_content { return; } + QSettings settings; + const double deviationCoef = settings.value("settings/selectContentDeviationCoef", 0.35).toDouble(); + const double deviationThreshold = settings.value("settings/selectContentDeviationThreshold", 1.0).toDouble(); + if (auto* thumb_col = dynamic_cast(collector)) { thumb_col->processThumbnail( std::unique_ptr( @@ -79,7 +84,8 @@ namespace select_content { params->contentRect(), params->pageRect(), params->isPageDetectionEnabled(), - m_ptrSettings->deviationProvider().isDeviant(page_info.id()) + m_ptrSettings->deviationProvider().isDeviant( + page_info.id(), deviationCoef, deviationThreshold) ) ) ); diff --git a/filters/select_content/Settings.cpp b/filters/select_content/Settings.cpp index 7c862019f..4bd1104cb 100644 --- a/filters/select_content/Settings.cpp +++ b/filters/select_content/Settings.cpp @@ -31,9 +31,9 @@ namespace select_content { auto it(m_pageParams.find(pageId)); if (it != m_pageParams.end()) { const Params& params = it->second; - const QSizeF& contentSize = params.contentRect().size(); + const QSizeF& contentSizeMM = params.contentSizeMM(); - return std::sqrt(contentSize.width() * contentSize.height() / 4 / 600); + return std::sqrt(contentSizeMM.width() * contentSizeMM.height() / 4 / 25.4); } else { return .0; }; diff --git a/ui/SettingsDialog.ui b/ui/SettingsDialog.ui index 5dd938ee5..010e0b768 100644 --- a/ui/SettingsDialog.ui +++ b/ui/SettingsDialog.ui @@ -6,8 +6,8 @@ 0 0 - 318 - 311 + 313 + 457 @@ -35,19 +35,12 @@ - + Auto-save the existing project - - - - Highlight the thumbnails of pages with high deviation - - - @@ -104,9 +97,8 @@ enableOpenglCb - AutoSaveProject + autoSaveProjectCB openglDeviceLabel - highlightDeviationCB @@ -155,6 +147,162 @@ + + + + Deviation + + + + + + Highlight the thumbnails of pages with high deviation + + + + + + + Params + + + + + + + + Deksew: + + + + + + + Select content: + + + + + + + Deviation multiplier: a higher value means lower sensivity. + + + 0.100000000000000 + + + 9.990000000000000 + + + 0.050000000000000 + + + + + + + Margins: + + + + + + + Deviation multiplier: a higher value means lower sensivity. + + + 0.100000000000000 + + + 9.990000000000000 + + + 0.050000000000000 + + + + + + + The minimum deviation to be highlighted. + + + 45.000000000000000 + + + 0.100000000000000 + + + + + + + The minimum deviation to be highlighted. + + + 1 + + + 999.000000000000000 + + + 1.000000000000000 + + + + + + + Deviation multiplier: a higher value means lower sensivity. + + + 0.100000000000000 + + + 9.990000000000000 + + + 0.050000000000000 + + + + + + + The minimum deviation to be highlighted. + + + 1 + + + 999.000000000000000 + + + 1.000000000000000 + + + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + + + From 6f8c85f8deea6f65593a18a4701e45502ee6bdfe Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Fri, 23 Feb 2018 20:20:18 +0300 Subject: [PATCH 09/20] ~ fixed an error of processing indexed images having light content on dark background at output. --- filters/output/OutputGenerator.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/filters/output/OutputGenerator.cpp b/filters/output/OutputGenerator.cpp index dd70b4c72..b9528c090 100644 --- a/filters/output/OutputGenerator.cpp +++ b/filters/output/OutputGenerator.cpp @@ -563,14 +563,14 @@ namespace output { const GrayImage inputGrayImage = input.isBlackOnWhite() ? input.grayImage() : input.grayImage().inverted(); const QImage inputOrigImage = [&input]() { QImage result = input.origImage(); - if (!input.isBlackOnWhite()) { - result.invertPixels(); - } if (!result.allGray() && (result.format() != QImage::Format_ARGB32) && (result.format() != QImage::Format_RGB32)) { result = result.convertToFormat(QImage::Format_RGB32); } + if (!input.isBlackOnWhite()) { + result.invertPixels(); + } return result; }(); @@ -1120,14 +1120,14 @@ namespace output { const GrayImage inputGrayImage = input.isBlackOnWhite() ? input.grayImage() : input.grayImage().inverted(); const QImage inputOrigImage = [&input]() { QImage result = input.origImage(); - if (!input.isBlackOnWhite()) { - result.invertPixels(); - } if (!result.allGray() && (result.format() != QImage::Format_ARGB32) && (result.format() != QImage::Format_RGB32)) { result = result.convertToFormat(QImage::Format_RGB32); } + if (!input.isBlackOnWhite()) { + result.invertPixels(); + } return result; }(); From 57f488231af5a70fd0882f65759058b73af3c9ec Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Fri, 23 Feb 2018 20:32:48 +0300 Subject: [PATCH 10/20] ~ Conversions of image format from RGB to Indexed are replaced by the custom implementation as Qt's QImage::convertToFormat is very slow for that type of conversion. --- filters/output/SplitImage.cpp | 11 +----- imageproc/ColorTable.cpp | 70 +++++++++++++++++++++-------------- imageproc/ColorTable.h | 4 +- 3 files changed, 46 insertions(+), 39 deletions(-) diff --git a/filters/output/SplitImage.cpp b/filters/output/SplitImage.cpp index 651f3ce9b..d501d915e 100644 --- a/filters/output/SplitImage.cpp +++ b/filters/output/SplitImage.cpp @@ -90,21 +90,12 @@ namespace output { QImage foreground(backgroundImage); applyMask(foreground, mask); - const int dpmX = foreground.dotsPerMeterX(); - const int dpmY = foreground.dotsPerMeterY(); - if (binaryForeground) { foreground = foreground.convertToFormat(QImage::Format_Mono); } else if (indexedForeground) { - QVector palette = ColorTable(foreground).getPalette(); - if (palette.size() <= 256) { - foreground = foreground.convertToFormat(QImage::Format_Indexed8, palette); - } + foreground = ColorTable(foreground).toIndexedImage(); } - foreground.setDotsPerMeterX(dpmX); - foreground.setDotsPerMeterY(dpmY); - return foreground; } diff --git a/imageproc/ColorTable.cpp b/imageproc/ColorTable.cpp index 49795eb4e..06543aa7e 100644 --- a/imageproc/ColorTable.cpp +++ b/imageproc/ColorTable.cpp @@ -8,9 +8,7 @@ namespace imageproc { ColorTable::ColorTable(const QImage& image) { - if ((image.format() != QImage::Format_Mono) - && (image.format() != QImage::Format_MonoLSB) - && (image.format() != QImage::Format_Indexed8) + if ((image.format() != QImage::Format_Indexed8) && (image.format() != QImage::Format_RGB32) && (image.format() != QImage::Format_ARGB32)) { throw std::invalid_argument("Image format not supported."); @@ -26,10 +24,6 @@ namespace imageproc { QVector ColorTable::getPalette() const { std::unordered_map paletteMap; switch (image.format()) { - case QImage::Format_Mono: - case QImage::Format_MonoLSB: - paletteMap = paletteFromMonoWithStatistics(); - break; case QImage::Format_Indexed8: paletteMap = paletteFromIndexedWithStatistics(); break; @@ -142,25 +136,6 @@ namespace imageproc { return *this; } - std::unordered_map ColorTable::paletteFromMonoWithStatistics() const { - std::unordered_map palette; - - BinaryImage bwImage(image); - - const int allCount = bwImage.size().width() * bwImage.size().height(); - const int blackCount = bwImage.countBlackPixels(); - const int whiteCount = allCount - blackCount; - - if (blackCount != 0) { - palette[0xff000000u] = blackCount; - } - if (whiteCount != 0) { - palette[0xffffffffu] = whiteCount; - } - - return palette; - } - std::unordered_map ColorTable::paletteFromIndexedWithStatistics() const { std::unordered_map palette; @@ -271,7 +246,7 @@ namespace imageproc { newColorTable.push_back(color); } - image = image.convertToFormat(QImage::Format_Indexed8, newColorTable); + image = toIndexedImage(&newColorTable); } std::unordered_map ColorTable::normalizePalette( @@ -367,4 +342,45 @@ namespace imageproc { } } + QImage ColorTable::toIndexedImage(const QVector* colorTable) const { + if (image.format() == QImage::Format_Indexed8) { + return image; + } + + const QVector& palette = (colorTable) ? *colorTable : getPalette(); + if (palette.size() > 256) { + return image; + } + + QImage dst(image.size(), QImage::Format_Indexed8); + dst.setColorTable(palette); + + const int width = image.width(); + const int height = image.height(); + + const auto* img_line = reinterpret_cast(image.bits()); + const int img_stride = image.bytesPerLine() / sizeof(uint32_t); + + uint8_t* dst_line = dst.bits(); + const int dst_stride = dst.bytesPerLine(); + + std::unordered_map colorToIndex; + for (int i = 0; i < palette.size(); ++i) { + colorToIndex[palette[i]] = static_cast(i); + } + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + dst_line[x] = colorToIndex[img_line[x]]; + } + img_line += img_stride; + dst_line += dst_stride; + } + + dst.setDotsPerMeterX(image.dotsPerMeterX()); + dst.setDotsPerMeterY(image.dotsPerMeterY()); + + return dst; + } + } // namespace imageproc \ No newline at end of file diff --git a/imageproc/ColorTable.h b/imageproc/ColorTable.h index 83d21b5ee..a44a49c65 100644 --- a/imageproc/ColorTable.h +++ b/imageproc/ColorTable.h @@ -24,9 +24,9 @@ namespace imageproc { QImage getImage() const; - private: - std::unordered_map paletteFromMonoWithStatistics() const; + QImage toIndexedImage(const QVector* colorTable = nullptr) const; + private: std::unordered_map paletteFromIndexedWithStatistics() const; std::unordered_map paletteFromRgbWithStatistics() const; From 4e1b667fb3c79db50fbd7ed9f994264462b8b140 Mon Sep 17 00:00:00 2001 From: Alexander Trufanov Date: Sat, 24 Feb 2018 06:00:57 +0300 Subject: [PATCH 11/20] ~ Fixed a bug of thumbnails drawing. Here's a small bug. In case you have two thumbnails scaled to 90x200 (height x width) and 200x100 the second thumbnail might be drawn as ~ 100x100 (bottom part clipped) as temp_pixmap won't be resized to match bigger height. Resolves #11 Closes #11 --- ThumbnailBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ThumbnailBase.cpp b/ThumbnailBase.cpp index c0d2c82d7..fe708257c 100644 --- a/ThumbnailBase.cpp +++ b/ThumbnailBase.cpp @@ -140,7 +140,7 @@ void ThumbnailBase::paint(QPainter* painter, const QStyleOptionGraphicsItem* opt const QString cache_key(QString::fromLatin1("ThumbnailBase::temp_pixmap")); if (!QPixmapCache::find(cache_key, temp_pixmap) || (temp_pixmap.width() < display_rect.width()) - || (temp_pixmap.height() < display_rect.width())) { + || (temp_pixmap.height() < display_rect.height())) { auto w = (int) display_rect.width(); auto h = (int) display_rect.height(); // Add some extra, to avoid rectreating the pixmap too often. From a90e7329449e398648f8f0791d47d6b69a9c668f Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Sun, 25 Feb 2018 02:09:45 +0300 Subject: [PATCH 12/20] Implemented the feature of auto adjusting content area. Use double-click on content to automatically adjust the content area. If the content is outside the area, the later will automatically be expanded and adjusted to the content at the position where double-click has been, otherwise the area edge, nearest to that position, will be adjusted. It's much faster now to correct the content area if, for example, the page number has been missed by the auto algorithm. It is no more required to manually and laboriously move the corners and edges of the content box. --- ImageViewBase.cpp | 17 +++- ImageViewBase.h | 2 + README.md | 10 ++ filters/select_content/ImageView.cpp | 142 ++++++++++++++++++++++++++- filters/select_content/ImageView.h | 19 ++++ filters/select_content/Task.cpp | 12 ++- interaction/InteractionHandler.cpp | 13 +++ interaction/InteractionHandler.h | 5 + 8 files changed, 216 insertions(+), 4 deletions(-) diff --git a/ImageViewBase.cpp b/ImageViewBase.cpp index 2918e3612..bd5210a54 100644 --- a/ImageViewBase.cpp +++ b/ImageViewBase.cpp @@ -508,7 +508,7 @@ void ImageViewBase::mousePressEvent(QMouseEvent* event) { m_rootInteractionHandler.mousePressEvent(event, m_interactionState); event->setAccepted(true); updateStatusTipAndCursor(); - void maybeQueueRedraw(); + maybeQueueRedraw(); } void ImageViewBase::mouseReleaseEvent(QMouseEvent* event) { @@ -526,6 +526,21 @@ void ImageViewBase::mouseReleaseEvent(QMouseEvent* event) { maybeQueueRedraw(); } +void ImageViewBase::mouseDoubleClickEvent(QMouseEvent* event) { + m_interactionState.resetProximity(); + if (!m_interactionState.captured()) { + m_rootInteractionHandler.proximityUpdate( + QPointF(0.5, 0.5) + event->pos(), m_interactionState + ); + } + + event->setAccepted(false); + m_rootInteractionHandler.mouseDoubleClickEvent(event, m_interactionState); + event->setAccepted(true); + updateStatusTipAndCursor(); + maybeQueueRedraw(); +} + void ImageViewBase::mouseMoveEvent(QMouseEvent* event) { m_interactionState.resetProximity(); if (!m_interactionState.captured()) { diff --git a/ImageViewBase.h b/ImageViewBase.h index 5f0398843..ce51af786 100644 --- a/ImageViewBase.h +++ b/ImageViewBase.h @@ -275,6 +275,8 @@ Q_OBJECT void mouseReleaseEvent(QMouseEvent* event) override; + void mouseDoubleClickEvent(QMouseEvent* event) override; + void mouseMoveEvent(QMouseEvent* event) override; void wheelEvent(QWheelEvent* event) override; diff --git a/README.md b/README.md index 36034915b..73f3c342e 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ brings new ones and fixes. * [Status bar panel](#status-bar-panel) * [Default parameters](#default-parameters) * [Collapsible filter options](#collapsible-filter-options) + * [Auto adjusting content area](#auto-adjusting-content-area) * [Building](#building) Description @@ -318,6 +319,15 @@ Features Now group boxes containing filter options can be collapsed/expanded. The collapse status is preserved between restarts of the application. + * ##### Auto adjusting content area. + + Use **`double-click`** on content to automatically adjust the content area. + If the content is outside the area, the later will automatically be expanded and adjusted to the content at the position where double-click has been, + otherwise the area edge, nearest to that position, will be adjusted. + + It's much faster now to correct the content area if, for example, the page number has been missed by the auto algorithm. + It is no more required to manually and laboriously move the corners and edges of the content box. + Building ---------- diff --git a/filters/select_content/ImageView.cpp b/filters/select_content/ImageView.cpp index 384c0e414..562e77bce 100644 --- a/filters/select_content/ImageView.cpp +++ b/filters/select_content/ImageView.cpp @@ -24,10 +24,20 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include + +using namespace imageproc; namespace select_content { ImageView::ImageView(const QImage& image, const QImage& downscaled_image, + const GrayImage& gray_image, const ImageTransformation& xform, const QRectF& content_rect, const QRectF& page_rect, @@ -48,7 +58,7 @@ namespace select_content { setMouseTracking(true); interactionState().setDefaultStatusTip( - tr("Use the context menu to enable / disable the content box. Hold Shift to drag a box.") + tr("Use the context menu to enable / disable the content box. Hold Shift to drag a box. Use double-click on content to automatically adjust the content area.") ); const QString content_rect_drag_tip(tr("Drag lines or corners to resize the content box.")); @@ -183,6 +193,8 @@ namespace select_content { addAction(remove); connect(create, SIGNAL(triggered(bool)), this, SLOT(createContentBox())); connect(remove, SIGNAL(triggered(bool)), this, SLOT(removeContentBox())); + + buildContentImage(gray_image, xform); } ImageView::~ImageView() = default; @@ -494,4 +506,132 @@ namespace select_content { update(); emit manualPageRectSet(m_pageRect); } + + void ImageView::buildContentImage(const GrayImage& gray_image, const ImageTransformation& xform) { + ImageTransformation xform_150dpi(xform); + xform_150dpi.preScaleToDpi(Dpi(150, 150)); + + QImage gray150( + transformToGray( + gray_image, xform_150dpi.transform(), + xform_150dpi.resultingRect().toRect(), + OutsidePixels::assumeColor(Qt::white) + ) + ); + + m_contentImage = binarizeWolf(gray150, QSize(51, 51), 50); + + PolygonRasterizer::fillExcept( + m_contentImage, WHITE, xform_150dpi.resultingPreCropArea(), Qt::WindingFill + ); + + class EmptyTaskStatus : public TaskStatus { + void cancel() override { + } + + bool isCancelled() const override { + return false; + } + + void throwIfCancelled() const override { + } + } status; + + Despeckle::despeckleInPlace(m_contentImage, Dpi(150, 150), Despeckle::NORMAL, status); + + m_originalToContentImage = xform_150dpi.transform(); + m_contentImageToOriginal = m_originalToContentImage.inverted(); + } + + void ImageView::onMouseDoubleClickEvent(QMouseEvent* event, InteractionState& interaction) { + if (event->button() == Qt::LeftButton) { + if (!m_contentRect.isEmpty()) { + correctContentBox(event->pos()); + } + } + } + + void ImageView::correctContentBox(const QPointF& pos) { + const QTransform widget_to_content_image(widgetToImage() * m_originalToContentImage); + const QTransform content_image_to_virtual(m_contentImageToOriginal * imageToVirtual()); + + const QPointF content_pos = widget_to_content_image.map(QPointF(0.5, 0.5) + pos); + + QRect finding_area((content_pos - QPointF(15, 15)).toPoint(), QSize(30, 30)); + finding_area = finding_area.intersected(m_contentImage.rect()); + if (finding_area.isEmpty()) { + return; + } + + QRect found_area = findContentInArea(finding_area); + if (found_area.isEmpty()) { + return; + } + + // If click position is inside the content rect, adjust the nearest side of the rect, + // else include the content at the position into the content rect. + const QPointF pos_in_virtual = widgetToVirtual().map(QPointF(0.5, 0.5) + pos); + const QRectF found_area_in_virtual = content_image_to_virtual.mapRect(QRectF(found_area)); + if (!m_contentRect.contains(pos_in_virtual)) { + m_contentRect |= found_area_in_virtual; + forcePageRectDescribeContent(); + } else { + std::map distanceMap; + distanceMap[pos_in_virtual.y() - m_contentRect.top()] = TOP; + distanceMap[pos_in_virtual.x() - m_contentRect.left()] = LEFT; + distanceMap[m_contentRect.bottom() - pos_in_virtual.y()] = BOTTOM; + distanceMap[m_contentRect.right() - pos_in_virtual.x()] = RIGHT; + + const Edge edge = distanceMap.begin()->second; + QPointF movePoint; + switch (edge) { + case TOP: + case LEFT: + movePoint = QPointF(found_area_in_virtual.left(), found_area_in_virtual.top()); + break; + case BOTTOM: + case RIGHT: + movePoint = QPointF(found_area_in_virtual.right(), found_area_in_virtual.bottom()); + break; + } + + contentRectCornerMoveRequest(edge, virtualToWidget().map(movePoint)); + } + + update(); + contentRectDragFinished(); + } + + QRect ImageView::findContentInArea(const QRect& area) { + const uint32_t* image_line = m_contentImage.data(); + const int image_stride = m_contentImage.wordsPerLine(); + const uint32_t msb = uint32_t(1) << 31; + + int top = std::numeric_limits::max(); + int left = std::numeric_limits::max(); + int bottom = std::numeric_limits::min(); + int right = std::numeric_limits::min(); + + image_line += area.top() * image_stride; + for (int y = area.top(); y <= area.bottom(); ++y) { + for (int x = area.left(); x <= area.right(); ++x) { + if (image_line[x >> 5] & (msb >> (x & 31))) { + top = std::min(top, y); + left = std::min(left, x); + bottom = std::max(bottom, y); + right = std::max(right, x); + } + } + image_line += image_stride; + } + + if (top > bottom) { + return QRect(); + } + + QRect found_area = QRect(left, top, right - left + 1, bottom - top + 1); + found_area.adjust(-1, -1, 1, 1); + + return found_area; + } } // namespace select_content \ No newline at end of file diff --git a/filters/select_content/ImageView.h b/filters/select_content/ImageView.h index 8a0416b62..be9840cce 100644 --- a/filters/select_content/ImageView.h +++ b/filters/select_content/ImageView.h @@ -29,10 +29,15 @@ #include #include #include +#include class ImageTransformation; class QMenu; +namespace imageproc { + class GrayImage; +} + namespace select_content { class ImageView : public ImageViewBase, private InteractionHandler { Q_OBJECT @@ -42,6 +47,7 @@ namespace select_content { */ ImageView(const QImage& image, const QImage& downscaled_image, + const imageproc::GrayImage& gray_image, const ImageTransformation& xform, const QRectF& content_rect, const QRectF& page_rect, @@ -61,6 +67,9 @@ namespace select_content { void pageRectSetExternally(const QRectF& pageRect); + protected: + void onMouseDoubleClickEvent(QMouseEvent* event, InteractionState& interaction) override; + private slots: void createContentBox(); @@ -111,6 +120,12 @@ namespace select_content { void pageRectMoveRequest(const QPolygonF& pos); + void buildContentImage(const imageproc::GrayImage& gray_image, const ImageTransformation& xform); + + void correctContentBox(const QPointF& pos); + + QRect findContentInArea(const QRect& area); + DraggablePoint m_contentRectCorners[4]; ObjectDragHandler m_contentRectCornerHandlers[4]; @@ -153,6 +168,10 @@ namespace select_content { bool m_pageRectReloadRequested; QSizeF m_minBoxSize; + + imageproc::BinaryImage m_contentImage; + QTransform m_originalToContentImage; + QTransform m_contentImageToOriginal; }; } // namespace select_content #endif // ifndef SELECT_CONTENT_IMAGEVIEW_H_ diff --git a/filters/select_content/Task.cpp b/filters/select_content/Task.cpp index ba153e178..d14dcab7e 100644 --- a/filters/select_content/Task.cpp +++ b/filters/select_content/Task.cpp @@ -33,6 +33,8 @@ #include #include "Dpm.h" +using namespace imageproc; + namespace select_content { class Task::UiUpdater : public FilterResult { public: @@ -41,6 +43,7 @@ namespace select_content { std::unique_ptr dbg, const QImage& image, const ImageTransformation& xform, + const GrayImage& gray_image, const OptionsWidget::UiData& ui_data, bool batch); @@ -56,6 +59,7 @@ namespace select_content { std::unique_ptr m_ptrDbg; QImage m_image; QImage m_downscaledImage; + GrayImage m_grayImage; ImageTransformation m_xform; OptionsWidget::UiData m_uiData; bool m_batchProcessing; @@ -188,7 +192,9 @@ namespace select_content { return FilterResultPtr( new UiUpdater( m_ptrFilter, m_pageId, std::move(m_ptrDbg), data.origImage(), - data.xform(), ui_data, m_batchProcessing + data.xform(), + data.isBlackOnWhite() ? data.grayImage() : data.grayImage().inverted(), + ui_data, m_batchProcessing ) ); } @@ -201,6 +207,7 @@ namespace select_content { std::unique_ptr dbg, const QImage& image, const ImageTransformation& xform, + const GrayImage& gray_image, const OptionsWidget::UiData& ui_data, const bool batch) : m_ptrFilter(std::move(filter)), @@ -209,6 +216,7 @@ namespace select_content { m_image(image), m_downscaledImage(ImageView::createDownscaledImage(image)), m_xform(xform), + m_grayImage(gray_image), m_uiData(ui_data), m_batchProcessing(batch) { } @@ -226,7 +234,7 @@ namespace select_content { } auto* view = new ImageView( - m_image, m_downscaledImage, + m_image, m_downscaledImage, m_grayImage, m_xform, m_uiData.contentRect(), m_uiData.pageRect(), m_uiData.isPageDetectionEnabled() ); diff --git a/interaction/InteractionHandler.cpp b/interaction/InteractionHandler.cpp index 16754b45a..662063f75 100644 --- a/interaction/InteractionHandler.cpp +++ b/interaction/InteractionHandler.cpp @@ -156,6 +156,19 @@ void InteractionHandler::mouseReleaseEvent(QMouseEvent* event, InteractionState& DISPATCH(followers, mouseReleaseEvent(event, interaction)); } +void InteractionHandler::mouseDoubleClickEvent(QMouseEvent* event, InteractionState& interaction) { + RETURN_IF_ACCEPTED(event); + // Keep them alive in case this object gets destroyed. + intrusive_ptr preceeders(m_ptrPreceeders); + intrusive_ptr followers(m_ptrFollowers); + + DISPATCH(preceeders, mouseDoubleClickEvent(event, interaction)); + RETURN_IF_ACCEPTED(event); + onMouseDoubleClickEvent(event, interaction); + ScopedClearAcceptance guard(event); + DISPATCH(followers, mouseDoubleClickEvent(event, interaction)); +} + void InteractionHandler::mouseMoveEvent(QMouseEvent* event, InteractionState& interaction) { RETURN_IF_ACCEPTED(event); diff --git a/interaction/InteractionHandler.h b/interaction/InteractionHandler.h index 3a27556d2..c345d5d93 100644 --- a/interaction/InteractionHandler.h +++ b/interaction/InteractionHandler.h @@ -54,6 +54,8 @@ DECLARE_NON_COPYABLE(InteractionHandler) void mouseReleaseEvent(QMouseEvent* event, InteractionState& interaction); + void mouseDoubleClickEvent(QMouseEvent* event, InteractionState& interaction); + void mouseMoveEvent(QMouseEvent* event, InteractionState& interaction); void wheelEvent(QWheelEvent* event, InteractionState& interaction); @@ -91,6 +93,9 @@ DECLARE_NON_COPYABLE(InteractionHandler) virtual void onMouseReleaseEvent(QMouseEvent* event, InteractionState& interaction) { } + virtual void onMouseDoubleClickEvent(QMouseEvent* event, InteractionState& interaction) { + } + virtual void onMouseMoveEvent(QMouseEvent* event, InteractionState& interaction) { } From ece382d04883f34b0258c873e1437b03a56e29ff Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Sun, 25 Feb 2018 02:18:16 +0300 Subject: [PATCH 13/20] ~ fixed README formatting. --- README.md | 94 +++++++++++++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 73f3c342e..24ff554e0 100644 --- a/README.md +++ b/README.md @@ -99,18 +99,18 @@ Features #### **Scan Tailor Featured** features * ##### Scan Tailor Featured fixes & improvements -1. Deleted 3 Red Points - The 3 central red points on the topmost (bottom-most) horizontal blue line of the dewarping - mesh are now eliminated. -2. Manual dewarping mode auto switch - The dewarping mode is now set to MANUAL (from OFF) after the user has moved the dewarping mesh. -3. Auto dewarping vertical half correction - This patch corrects the original auto-dewarping in half - the cases when it fails. If the vertical content boundary angle (calculated by auto-dewarping) - exceeds an empirical value (2.75 degrees from vertical), the patch adds a new point to - the distortion model (with the coordinates equal to the neighboring points) to make - this boundary vertical. The patch works ONLY for the linear end of the top (bottom) - horizontal line of the blue mesh (and not for the opposite curved end). + * Deleted 3 Red Points + The 3 central red points on the topmost (bottom-most) horizontal blue line of the dewarping + mesh are now eliminated. + * Manual dewarping mode auto switch + The dewarping mode is now set to MANUAL (from OFF) after the user has moved the dewarping mesh. + * Auto dewarping vertical half correction + This patch corrects the original auto-dewarping in half + the cases when it fails. If the vertical content boundary angle (calculated by auto-dewarping) + exceeds an empirical value (2.75 degrees from vertical), the patch adds a new point to + the distortion model (with the coordinates equal to the neighboring points) to make + this boundary vertical. The patch works ONLY for the linear end of the top (bottom) + horizontal line of the blue mesh (and not for the opposite curved end). * ##### Line vertical dragging on dewarp You can move the topmost (bottom-most) horizontal blue line of the dewarping mesh up and @@ -152,41 +152,41 @@ Features #### **Scan Tailor Advanced** features * ##### Scan Tailor Advanced fixes & improvements -* Portability. - The setting is stored in the folder with a program. - -* Page splitting had an influence on output only in b&w mode with dewarping disabled. - Now it works in all the modes. - -* Page layout and all the other views now consider splitting settings. - Corresponding improvements are done to thumbnails. - -* Changed Scan Tailor behavior on page split stage. - 1. Reworked apply cut feature. Now on applying cut to the pages with different dimensions - than the page the cut applied to, Scan Tailor tries to adapt cutters instead of fully - rejecting the cut setting and switching to auto mode for those pages as it was before. - The later was annoying as pages could be similar and had the difference in a few pixels. - 2. Added check to reject invalid cut settings in manual mode. - 3. UI: Added cutters interaction between each other. They can't more intersect each other, - which created a wrong page layout configuration before. - -* Optimized memory usage on the output stage. - -* Reworking on [multi column thumbnails view](#multi-column-thumbnails-view-reworked) feature from ver. Enhanced. - Now thumbnails are shown evenly. - -* Added option to control highlighting (with red asterisks) the thumbnails of pages with high deviation. - The option refreshes the thumbnails instantly. - -* Support for processing of images with light content on dark background. - Now that kind of images can correctly be handled on all the stages. Many book covers are examples of such images. - -* Deviation feature reworked. - 1. A deviation provider implemented. - It supports caching and recalculates the values on demand. There isn't more any necessity to store deviation in page parameters and so in the project file, that approach caused some problems as the deviation is not actually a page parameter and depends on all the pages in the project. - 2. Added sorting by decreasing deviation. - -* Fixed other bugs of official, Enhanced and Featured versions and made lots of other improvements. + * Portability. + The setting is stored in the folder with a program. + + * Page splitting had an influence on output only in b&w mode with dewarping disabled. + Now it works in all the modes. + + * Page layout and all the other views now consider splitting settings. + Corresponding improvements are done to thumbnails. + + * Changed Scan Tailor behavior on page split stage. + 1. Reworked apply cut feature. Now on applying cut to the pages with different dimensions + than the page the cut applied to, Scan Tailor tries to adapt cutters instead of fully + rejecting the cut setting and switching to auto mode for those pages as it was before. + The later was annoying as pages could be similar and had the difference in a few pixels. + 2. Added check to reject invalid cut settings in manual mode. + 3. UI: Added cutters interaction between each other. They can't more intersect each other, + which created a wrong page layout configuration before. + + * Optimized memory usage on the output stage. + + * Reworking on [multi column thumbnails view](#multi-column-thumbnails-view-reworked) feature from ver. Enhanced. + Now thumbnails are shown evenly. + + * Added option to control highlighting (with red asterisks) the thumbnails of pages with high deviation. + The option refreshes the thumbnails instantly. + + * Support for processing of images with light content on dark background. + Now that kind of images can correctly be handled on all the stages. Many book covers are examples of such images. + + * Deviation feature reworked. + 1. A deviation provider implemented. + It supports caching and recalculates the values on demand. There isn't more any necessity to store deviation in page parameters and so in the project file, that approach caused some problems as the deviation is not actually a page parameter and depends on all the pages in the project. + 2. Added sorting by decreasing deviation. + + * Fixed other bugs of official, Enhanced and Featured versions and made lots of other improvements. * ##### Light and Dark color schemes You can choose a desired color scheme in settings. From a55b258bf65d9ca484313fc4c7b4e079fc0fd928 Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Sun, 25 Feb 2018 02:39:50 +0300 Subject: [PATCH 14/20] Improved: The follow page button is no more activated automatically on switching a sorting method or on going to the previous/next page. (Relates to 9467b6ca384158c1534f850c3646ca0146d2bb66) --- MainWindow.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/MainWindow.cpp b/MainWindow.cpp index b27e12ce9..1774ede7c 100644 --- a/MainWindow.cpp +++ b/MainWindow.cpp @@ -961,8 +961,6 @@ void MainWindow::goPrevPage() { } void MainWindow::goToPage(const PageId& page_id) { - focusButton->setChecked(true); - m_ptrThumbSequence->setSelection(page_id); // If the page was already selected, it will be reloaded. @@ -1191,7 +1189,9 @@ void MainWindow::pageOrderingChanged(int idx) { return; } - focusButton->setChecked(true); // Keep the current page in view. + const int hor_scroll_bar_pos = thumbView->horizontalScrollBar()->value(); + const int ver_scroll_bar_pos = thumbView->verticalScrollBar()->value(); + m_ptrStages->filterAt(m_curFilter)->selectPageOrder(idx); m_ptrThumbSequence->reset( @@ -1199,6 +1199,11 @@ void MainWindow::pageOrderingChanged(int idx) { ThumbnailSequence::KEEP_SELECTION, currentPageOrderProvider() ); + + if (!focusButton->isChecked()) { + thumbView->horizontalScrollBar()->setValue(hor_scroll_bar_pos); + thumbView->verticalScrollBar()->setValue(ver_scroll_bar_pos); + } } void MainWindow::reloadRequested() { From f8edbadf7842ad76c7b32ebab9117ee12996f629 Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Sun, 25 Feb 2018 16:46:53 +0300 Subject: [PATCH 15/20] ~ changed default windows size for the adaptive binarization algorithms. --- filters/output/BlackWhiteOptions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/filters/output/BlackWhiteOptions.cpp b/filters/output/BlackWhiteOptions.cpp index a4c2766c6..233fedb9a 100644 --- a/filters/output/BlackWhiteOptions.cpp +++ b/filters/output/BlackWhiteOptions.cpp @@ -26,7 +26,7 @@ namespace output { savitzkyGolaySmoothingEnabled(true), morphologicalSmoothingEnabled(true), m_normalizeIllumination(true), - windowSize(51), + windowSize(200), sauvolaCoef(0.34), wolfLowerBound(1), wolfUpperBound(254), From e8cc636c7fc0f878d573875c4207c685ee02b7f9 Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Sun, 25 Feb 2018 18:20:56 +0300 Subject: [PATCH 16/20] ~ fix for the unused warning. --- MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MainWindow.cpp b/MainWindow.cpp index 1774ede7c..ea47e7fb0 100644 --- a/MainWindow.cpp +++ b/MainWindow.cpp @@ -1328,7 +1328,7 @@ void MainWindow::filterResult(const BackgroundTaskPtr& task, const FilterResultP if (cmd.isEmpty()) { QApplication::beep(); } else { - (void) std::system(cmd.toStdString().c_str()); + Q_UNUSED(std::system(cmd.toStdString().c_str())); } } From 1444dd04ff214dcbaa84fdb28d92b5864c851d10 Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Wed, 28 Feb 2018 18:05:28 +0300 Subject: [PATCH 17/20] Auto and original alignment modes reworked: * The original and auto alignment modes didn't work correctly due to the error in code. * Both the modes didn't work rightly after select content stage or reopening the project file, always requiring secondary batch processing of every page at margins stage to work correctly. * Reworked calculation method for the original alignment. Now it is more precise. * Original alignment mode now considers the page box from 4th stage. * Fixed behaviour of horizontal alignment, when the original mode enabled, and auto margins has been enabled/disabled. Also on applying auto-margins / original alignment to the set of pages, that is now set correctly for each page. --- CommandLine.cpp | 4 - DefaultParamsDialog.cpp | 2 +- README.md | 8 + filters/page_layout/Alignment.cpp | 56 +++--- filters/page_layout/Alignment.h | 11 +- filters/page_layout/CacheDrivenTask.cpp | 15 +- filters/page_layout/CacheDrivenTask.h | 1 + filters/page_layout/Filter.cpp | 6 +- filters/page_layout/ImageView.cpp | 14 +- filters/page_layout/OptionsWidget.cpp | 25 ++- filters/page_layout/Params.cpp | 2 +- filters/page_layout/Settings.cpp | 85 +++------ filters/page_layout/Settings.h | 11 +- filters/page_layout/Task.cpp | 5 +- filters/page_layout/Utils.cpp | 198 ++++++++------------- filters/page_layout/Utils.h | 4 +- filters/select_content/CacheDrivenTask.cpp | 2 +- 17 files changed, 187 insertions(+), 262 deletions(-) diff --git a/CommandLine.cpp b/CommandLine.cpp index cdf650899..ae0d84265 100644 --- a/CommandLine.cpp +++ b/CommandLine.cpp @@ -523,10 +523,6 @@ page_layout::Alignment CommandLine::fetchAlignment() { } } - if (m_options.contains("alignment-tolerance")) { - alignment.setTolerance(m_options["alignment-tolerance"].toFloat()); - } - if (m_options.contains("alignment")) { if (m_options["alignment"] == "original") { alignment.setVertical(page_layout::Alignment::VORIGINAL); diff --git a/DefaultParamsDialog.cpp b/DefaultParamsDialog.cpp index b281c8de3..6a22e4b01 100644 --- a/DefaultParamsDialog.cpp +++ b/DefaultParamsDialog.cpp @@ -665,7 +665,7 @@ std::unique_ptr DefaultParamsDialog::buildParams() const { switch (alignmentMode->currentIndex()) { case 0: alignment.setVertical(Alignment::VAUTO); - alignment.setHorizontal(Alignment::HCENTER); + alignment.setHorizontal(Alignment::HAUTO); break; case 1: for (auto item : alignmentByButton) { diff --git a/README.md b/README.md index 24ff554e0..5a9f7917d 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ Features bottom or center. Original mode keeps page on their vertical original position. *This feature has been improved. See [page area](#page-area) feature description.* + *Also see [Scan Tailor Advanced fixes & improvements](#scan-tailor-advanced-fixes--improvements)* * ##### Page detect \[reworked\] Page detect feature allows detect page in black margins or switch off page content @@ -185,6 +186,13 @@ Features 1. A deviation provider implemented. It supports caching and recalculates the values on demand. There isn't more any necessity to store deviation in page parameters and so in the project file, that approach caused some problems as the deviation is not actually a page parameter and depends on all the pages in the project. 2. Added sorting by decreasing deviation. + + * Auto and original alignment modes reworked: + 1. The original and auto alignment modes didn't work correctly due to the error in code. + 2. Both the modes didn't work rightly after select content stage or reopening the project file, always requiring secondary batch processing of every page at margins stage to work correctly. + 3. Reworked calculation method for the original alignment. Now it is more precise. + 4. Original alignment mode now considers the page box from 4th stage. + 5. Fixed behaviour of horizontal alignment, when the original mode enabled, and auto margins has been enabled/disabled. Also on applying auto-margins / original alignment to the set of pages, that is now set correctly for each page. * Fixed other bugs of official, Enhanced and Featured versions and made lots of other improvements. diff --git a/filters/page_layout/Alignment.cpp b/filters/page_layout/Alignment.cpp index 11bce57b3..d8f1451e9 100644 --- a/filters/page_layout/Alignment.cpp +++ b/filters/page_layout/Alignment.cpp @@ -21,16 +21,14 @@ namespace page_layout { Alignment::Alignment() - : m_vert(VCENTER), - m_hor(HCENTER), - m_tolerance(DEFAULT_TOLERANCE), + : m_vertical(VCENTER), + m_horizontal(HCENTER), m_isNull(false) { } Alignment::Alignment(Vertical vert, Horizontal hor) - : m_vert(vert), - m_hor(hor), - m_tolerance(DEFAULT_TOLERANCE), + : m_vertical(vert), + m_horizontal(hor), m_isNull(false) { } @@ -38,36 +36,35 @@ namespace page_layout { const QString vert(el.attribute("vert")); const QString hor(el.attribute("hor")); m_isNull = el.attribute("null").toInt() != 0; - m_tolerance = el.attribute("tolerance", QString::number(DEFAULT_TOLERANCE)).toDouble(); if (vert == "top") { - m_vert = TOP; + m_vertical = TOP; } else if (vert == "bottom") { - m_vert = BOTTOM; + m_vertical = BOTTOM; } else if (vert == "auto") { - m_vert = VAUTO; + m_vertical = VAUTO; } else if (vert == "original") { - m_vert = VORIGINAL; + m_vertical = VORIGINAL; } else { - m_vert = VCENTER; + m_vertical = VCENTER; } if (hor == "left") { - m_hor = LEFT; + m_horizontal = LEFT; } else if (hor == "right") { - m_hor = RIGHT; + m_horizontal = RIGHT; } else if (hor == "auto") { - m_hor = HAUTO; + m_horizontal = HAUTO; } else if (vert == "original") { - m_hor = HORIGINAL; + m_horizontal = HORIGINAL; } else { - m_hor = HCENTER; + m_horizontal = HCENTER; } } QDomElement Alignment::toXml(QDomDocument& doc, const QString& name) const { const char* vert = nullptr; - switch (m_vert) { + switch (m_vertical) { case TOP: vert = "top"; break; @@ -86,7 +83,7 @@ namespace page_layout { } const char* hor = nullptr; - switch (m_hor) { + switch (m_horizontal) { case LEFT: hor = "left"; break; @@ -108,14 +105,13 @@ namespace page_layout { el.setAttribute("vert", QString::fromLatin1(vert)); el.setAttribute("hor", QString::fromLatin1(hor)); el.setAttribute("null", m_isNull ? 1 : 0); - el.setAttribute("tolerance", QString::number(m_tolerance)); return el; } bool Alignment::operator==(const Alignment& other) const { - return (m_vert == other.m_vert) - && (m_hor == other.m_hor) + return (m_vertical == other.m_vertical) + && (m_horizontal == other.m_horizontal) && (m_isNull == other.m_isNull); } @@ -124,19 +120,19 @@ namespace page_layout { } Alignment::Vertical Alignment::vertical() const { - return m_vert; + return m_vertical; } void Alignment::setVertical(Alignment::Vertical vert) { - m_vert = vert; + m_vertical = vert; } Alignment::Horizontal Alignment::horizontal() const { - return m_hor; + return m_horizontal; } void Alignment::setHorizontal(Alignment::Horizontal hor) { - m_hor = hor; + m_horizontal = hor; } bool Alignment::isNull() const { @@ -146,12 +142,4 @@ namespace page_layout { void Alignment::setNull(bool is_null) { m_isNull = is_null; } - - double Alignment::tolerance() const { - return m_tolerance; - } - - void Alignment::setTolerance(double t) { - m_tolerance = t; - } } // namespace page_layout diff --git a/filters/page_layout/Alignment.h b/filters/page_layout/Alignment.h index 2b24e32c0..9a846af8c 100644 --- a/filters/page_layout/Alignment.h +++ b/filters/page_layout/Alignment.h @@ -28,8 +28,6 @@ class QString; class CommandLine; namespace page_layout { - const double DEFAULT_TOLERANCE = 0.2; - class Alignment { public: enum Vertical { @@ -69,10 +67,6 @@ namespace page_layout { void setNull(bool is_null); - double tolerance() const; - - void setTolerance(double t); - bool operator==(const Alignment& other) const; bool operator!=(const Alignment& other) const; @@ -80,10 +74,9 @@ namespace page_layout { QDomElement toXml(QDomDocument& doc, const QString& name) const; private: - Vertical m_vert; - Horizontal m_hor; + Vertical m_vertical; + Horizontal m_horizontal; bool m_isNull; - double m_tolerance; }; } // namespace page_layout #endif // ifndef PAGE_LAYOUT_ALIGNMENT_H_ diff --git a/filters/page_layout/CacheDrivenTask.cpp b/filters/page_layout/CacheDrivenTask.cpp index 77a2d66f2..e6e22e574 100644 --- a/filters/page_layout/CacheDrivenTask.cpp +++ b/filters/page_layout/CacheDrivenTask.cpp @@ -42,11 +42,12 @@ namespace page_layout { void CacheDrivenTask::process(const PageInfo& page_info, AbstractFilterDataCollector* collector, const ImageTransformation& xform, + const QRectF& page_rect, const QRectF& content_rect) { const std::unique_ptr params( m_ptrSettings->getPageParams(page_info.id()) ); - if (!params || !params->contentSizeMM().isValid()) { + if (!params || (params->contentSizeMM().isEmpty() && !content_rect.isEmpty())) { if (auto* thumb_col = dynamic_cast(collector)) { thumb_col->processThumbnail( std::unique_ptr( @@ -62,6 +63,12 @@ namespace page_layout { return; } + Params new_params( + m_ptrSettings->updateContentSizeAndGetParams( + page_info.id(), page_rect, content_rect, params->contentSizeMM() + ) + ); + const QRectF adapted_content_rect( Utils::adaptContentRect(xform, content_rect) ); @@ -70,8 +77,8 @@ namespace page_layout { ); const QPolygonF page_rect_phys( Utils::calcPageRectPhys( - xform, content_rect_phys, *params, - m_ptrSettings->getAggregateHardSizeMM(), m_ptrSettings->getContentRect() + xform, content_rect_phys, new_params, + m_ptrSettings->getAggregateHardSizeMM(), m_ptrSettings->getAggregateContentRect() ) ); ImageTransformation new_xform(xform); @@ -93,7 +100,7 @@ namespace page_layout { new Thumbnail( thumb_col->thumbnailCache(), thumb_col->maxLogicalThumbSize(), - page_info.imageId(), *params, + page_info.imageId(), new_params, xform, content_rect_phys, xform.transform().map(page_rect_phys).boundingRect(), m_ptrSettings->deviationProvider().isDeviant( diff --git a/filters/page_layout/CacheDrivenTask.h b/filters/page_layout/CacheDrivenTask.h index b5417dd76..846d00ab1 100644 --- a/filters/page_layout/CacheDrivenTask.h +++ b/filters/page_layout/CacheDrivenTask.h @@ -47,6 +47,7 @@ namespace page_layout { void process(const PageInfo& page_info, AbstractFilterDataCollector* collector, const ImageTransformation& xform, + const QRectF& page_rect, const QRectF& content_rect); private: diff --git a/filters/page_layout/Filter.cpp b/filters/page_layout/Filter.cpp index da6886205..ec056dca8 100644 --- a/filters/page_layout/Filter.cpp +++ b/filters/page_layout/Filter.cpp @@ -110,7 +110,7 @@ namespace page_layout { QDomElement filter_el(doc.createElement("page-layout")); XmlMarshaller marshaller(doc); - filter_el.appendChild(marshaller.rectF(m_ptrSettings->getContentRect(), "contentRect")); + filter_el.appendChild(marshaller.rectF(m_ptrSettings->getAggregateContentRect(), "aggregateContentRect")); writer.enumPages( [&](const PageId& page_id, int numeric_id) { @@ -142,9 +142,9 @@ namespace page_layout { filters_el.namedItem("page-layout").toElement() ); - const QDomElement rect_el = filter_el.namedItem("contentRect").toElement(); + const QDomElement rect_el = filter_el.namedItem("aggregateContentRect").toElement(); if (!rect_el.isNull()) { - m_ptrSettings->setContentRect(XmlUnmarshaller::rectF(rect_el)); + m_ptrSettings->setAggregateContentRect(XmlUnmarshaller::rectF(rect_el)); } const QString page_tag_name("page"); diff --git a/filters/page_layout/ImageView.cpp b/filters/page_layout/ImageView.cpp index 14c82d50a..82e692ec0 100644 --- a/filters/page_layout/ImageView.cpp +++ b/filters/page_layout/ImageView.cpp @@ -517,8 +517,6 @@ namespace page_layout { QPolygonF poly_mm(virt_to_mm.map(m_innerRect)); Utils::extendPolyRectWithMargins(poly_mm, margins_mm); - m_ptrSettings->updateContentRect(); - const QRectF middle_rect(mm_to_virt.map(poly_mm).boundingRect()); const QSizeF hard_size_mm( @@ -528,7 +526,10 @@ namespace page_layout { const Margins soft_margins_mm( Utils::calcSoftMarginsMM( hard_size_mm, m_aggregateHardSizeMM, m_alignment, - m_ptrSettings->getPageParams(m_pageId)->contentRect(), m_ptrSettings->getContentRect() + m_ptrSettings->getPageParams(m_pageId)->contentRect(), + m_ptrSettings->getPageParams(m_pageId)->contentSizeMM(), + m_ptrSettings->getAggregateContentRect(), + m_ptrSettings->getPageParams(m_pageId)->pageRect() ) ); @@ -633,8 +634,6 @@ namespace page_layout { QPolygonF poly_mm(virt_to_mm.map(m_middleRect)); - m_ptrSettings->updateContentRect(); - const QSizeF hard_size_mm( QLineF(poly_mm[0], poly_mm[1]).length(), QLineF(poly_mm[0], poly_mm[3]).length() @@ -642,7 +641,10 @@ namespace page_layout { const Margins soft_margins_mm( Utils::calcSoftMarginsMM( hard_size_mm, m_aggregateHardSizeMM, m_alignment, - m_ptrSettings->getPageParams(m_pageId)->contentRect(), m_ptrSettings->getContentRect() + m_ptrSettings->getPageParams(m_pageId)->contentRect(), + m_ptrSettings->getPageParams(m_pageId)->contentSizeMM(), + m_ptrSettings->getAggregateContentRect(), + m_ptrSettings->getPageParams(m_pageId)->pageRect() ) ); diff --git a/filters/page_layout/OptionsWidget.cpp b/filters/page_layout/OptionsWidget.cpp index ec5388c8a..fba9eac06 100644 --- a/filters/page_layout/OptionsWidget.cpp +++ b/filters/page_layout/OptionsWidget.cpp @@ -276,8 +276,11 @@ namespace page_layout { m_ptrSettings->setPageAutoMarginsEnabled(m_pageId, checked); updateMarginsControlsEnabled(); + if (m_alignment.vertical() == Alignment::VORIGINAL) { + m_alignment.setHorizontal(checked ? Alignment::HORIGINAL : Alignment::HCENTER); + } + m_ptrSettings->setPageAlignment(m_pageId, m_alignment); - m_ptrSettings->updateContentRect(); emit reloadRequested(); } @@ -285,7 +288,7 @@ namespace page_layout { switch (idx) { case 0: m_alignment.setVertical(Alignment::VAUTO); - m_alignment.setHorizontal(Alignment::HCENTER); + m_alignment.setHorizontal(Alignment::HAUTO); break; case 1: for (auto button : m_alignmentByButton) { @@ -307,7 +310,6 @@ namespace page_layout { break; } - m_ptrSettings->updateContentRect(); updateAlignmentButtonsEnabled(); emit alignmentChanged(m_alignment); } @@ -366,6 +368,12 @@ namespace page_layout { } else { m_ptrSettings->setHardMarginsMM(page_id, m_marginsMM); } + + Alignment alignment = m_ptrSettings->getPageAlignment(page_id); + if (alignment.vertical() == Alignment::VORIGINAL) { + alignment.setHorizontal(autoMarginsEnabled ? Alignment::HORIGINAL : Alignment::HCENTER); + m_ptrSettings->setPageAlignment(page_id, alignment); + } } emit aggregateHardSizeChanged(); @@ -382,7 +390,16 @@ namespace page_layout { continue; } - m_ptrSettings->setPageAlignment(page_id, m_alignment); + if (m_alignment.vertical() != Alignment::VORIGINAL) { + m_ptrSettings->setPageAlignment(page_id, m_alignment); + } else { + Alignment alignment = m_alignment; + alignment.setHorizontal(m_ptrSettings->isPageAutoMarginsEnabled(page_id) + ? Alignment::HORIGINAL + : Alignment::HCENTER); + + m_ptrSettings->setPageAlignment(page_id, alignment); + } } emit invalidateAllThumbnails(); diff --git a/filters/page_layout/Params.cpp b/filters/page_layout/Params.cpp index 994011451..462efa41b 100644 --- a/filters/page_layout/Params.cpp +++ b/filters/page_layout/Params.cpp @@ -22,8 +22,8 @@ namespace page_layout { Params::Params(const Margins& hard_margins_mm, - const QRectF& content_rect, const QRectF& page_rect, + const QRectF& content_rect, const QSizeF& content_size_mm, const Alignment& alignment, const bool auto_margins) diff --git a/filters/page_layout/Settings.cpp b/filters/page_layout/Settings.cpp index c854745e9..87eeebaa0 100644 --- a/filters/page_layout/Settings.cpp +++ b/filters/page_layout/Settings.cpp @@ -149,21 +149,16 @@ namespace page_layout { const QRectF& content_rect, const QSizeF& content_size_mm, QSizeF* agg_hard_size_before, - QSizeF* agg_hard_size_after, - bool suppress_content_rect_update); + QSizeF* agg_hard_size_after); - const QRectF& updateContentRect(); + const QRectF& updateAggregateContentRect(); - const QRectF& getContentRect() { - return m_contentRect; + const QRectF& getAggregateContentRect() { + return m_aggregateContentRect; } - void setContentRect(const QRectF& contentRect) { - m_contentRect = contentRect; - } - - const QRectF& getPageRect() { - return m_pageRect; + void setAggregateContentRect(const QRectF& aggregateContentRect) { + m_aggregateContentRect = aggregateContentRect; } Margins getHardMarginsMM(const PageId& page_id) const; @@ -244,8 +239,7 @@ namespace page_layout { const QSizeF m_invalidSize; const Margins m_defaultHardMarginsMM; const Alignment m_defaultAlignment; - QRectF m_contentRect; - QRectF m_pageRect; + QRectF m_aggregateContentRect; const bool m_autoMarginsDefault; DeviationProvider m_deviationProvider; }; @@ -289,29 +283,23 @@ namespace page_layout { const QRectF& content_rect, const QSizeF& content_size_mm, QSizeF* agg_hard_size_before, - QSizeF* agg_hard_size_after, - bool suppress_content_rect_update) { + QSizeF* agg_hard_size_after) { return m_ptrImpl->updateContentSizeAndGetParams( page_id, page_rect, content_rect, content_size_mm, - agg_hard_size_before, agg_hard_size_after, - suppress_content_rect_update + agg_hard_size_before, agg_hard_size_after ); } - const QRectF& Settings::updateContentRect() { - return m_ptrImpl->updateContentRect(); + const QRectF& Settings::updateAggregateContentRect() { + return m_ptrImpl->updateAggregateContentRect(); } - const QRectF& Settings::getContentRect() { - return m_ptrImpl->getContentRect(); + const QRectF& Settings::getAggregateContentRect() { + return m_ptrImpl->getAggregateContentRect(); } - void Settings::setContentRect(const QRectF& contentRect) { - m_ptrImpl->setContentRect(contentRect); - } - - const QRectF& Settings::getPageRect() { - return m_ptrImpl->getPageRect(); + void Settings::setAggregateContentRect(const QRectF& contentRect) { + m_ptrImpl->setAggregateContentRect(contentRect); } Margins Settings::getHardMarginsMM(const PageId& page_id) const { @@ -529,8 +517,7 @@ namespace page_layout { const QRectF& content_rect, const QSizeF& content_size_mm, QSizeF* agg_hard_size_before, - QSizeF* agg_hard_size_after, - bool suppress_content_rect_update) { + QSizeF* agg_hard_size_after) { const QMutexLocker locker(&m_mutex); if (agg_hard_size_before) { @@ -553,9 +540,7 @@ namespace page_layout { *agg_hard_size_after = getAggregateHardSizeMMLocked(); } - if (!suppress_content_rect_update) { - updateContentRect(); - } + updateAggregateContentRect(); m_deviationProvider.addOrUpdate(page_id); @@ -565,13 +550,13 @@ namespace page_layout { ); } // Settings::Impl::updateContentSizeAndGetParams - const QRectF& Settings::Impl::updateContentRect() { + const QRectF& Settings::Impl::updateAggregateContentRect() { Container::iterator it = m_items.begin(); if (it == m_items.end()) { - return m_contentRect; + return m_aggregateContentRect; } - m_contentRect = it->contentRect; + m_aggregateContentRect = it->contentRect; for (; it != m_items.end(); it++) { if (it->contentRect == m_invalidRect) { continue; @@ -580,29 +565,13 @@ namespace page_layout { continue; } - QRectF icr(it->contentRect); - - /* - std::cout << "\tupateContentRect: " << it->pageId.imageId().filePath().toLatin1().constData() << "\n"; - std::cout << "m_contentRect.left(): " << m_contentRect.left() << " right(): " << m_contentRect.right() << " top: " << m_contentRect.top() << " bottom: " << m_contentRect.bottom() << std::endl; - std::cout << "icr.left(): " << icr.left() << " right(): " << icr.right() << " top: " << icr.top() << " bottom: " << icr.bottom() << std::endl; - */ + const QRectF page_rect(it->pageRect); + QRectF content_rect(it->contentRect.translated(-page_rect.x(), -page_rect.y())); - if (icr.left() < m_contentRect.left()) { - m_contentRect.setLeft(icr.left()); - } - if (icr.right() > m_contentRect.right()) { - m_contentRect.setRight(icr.right()); - } - if (icr.top() < m_contentRect.top()) { - m_contentRect.setTop(icr.top()); - } - if (icr.bottom() > m_contentRect.bottom()) { - m_contentRect.setBottom(icr.bottom()); - } + m_aggregateContentRect |= content_rect; } - return m_contentRect; + return m_aggregateContentRect; } // Settings::Impl::updateContentRect Margins Settings::Impl::getHardMarginsMM(const PageId& page_id) const { @@ -646,7 +615,7 @@ namespace page_layout { Settings::AggregateSizeChanged Settings::Impl::setPageAlignment(const PageId& page_id, const Alignment& alignment) { const QMutexLocker locker(&m_mutex); - + const QSizeF agg_size_before(getAggregateHardSizeMMLocked()); const Container::iterator it(m_items.lower_bound(page_id)); @@ -657,6 +626,10 @@ namespace page_layout { ); m_items.insert(it, item); } else { + if (alignment.isNull() != it->alignment.isNull()) { + updateAggregateContentRect(); + } + m_items.modify(it, ModifyAlignment(alignment)); } diff --git a/filters/page_layout/Settings.h b/filters/page_layout/Settings.h index 675ce34e9..0246af96c 100644 --- a/filters/page_layout/Settings.h +++ b/filters/page_layout/Settings.h @@ -93,16 +93,13 @@ namespace page_layout { const QRectF& content_rect, const QSizeF& content_size_mm, QSizeF* agg_hard_size_before = nullptr, - QSizeF* agg_hard_size_after = nullptr, - bool suppress_content_rect_update = false); + QSizeF* agg_hard_size_after = nullptr); - const QRectF& updateContentRect(); + const QRectF& updateAggregateContentRect(); - const QRectF& getContentRect(); + const QRectF& getAggregateContentRect(); - void setContentRect(const QRectF& contentRect); - - const QRectF& getPageRect(); + void setAggregateContentRect(const QRectF& contentRect); /** * \brief Returns the hard margins for the specified page. diff --git a/filters/page_layout/Task.cpp b/filters/page_layout/Task.cpp index ea7669f00..5fa9df240 100644 --- a/filters/page_layout/Task.cpp +++ b/filters/page_layout/Task.cpp @@ -99,8 +99,7 @@ namespace page_layout { const Params params( m_ptrSettings->updateContentSizeAndGetParams( m_pageId, page_rect, content_rect, content_size_mm, - &agg_hard_size_before, &agg_hard_size_after, - (m_ptrNextTask != nullptr) + &agg_hard_size_before, &agg_hard_size_after ) ); @@ -115,7 +114,7 @@ namespace page_layout { const QPolygonF page_rect_phys( Utils::calcPageRectPhys( data.xform(), content_rect_phys, - params, agg_hard_size_after, m_ptrSettings->getContentRect() + params, agg_hard_size_after, m_ptrSettings->getAggregateContentRect() ) ); diff --git a/filters/page_layout/Utils.cpp b/filters/page_layout/Utils.cpp index ee41ff5cd..a37b7bc66 100644 --- a/filters/page_layout/Utils.cpp +++ b/filters/page_layout/Utils.cpp @@ -23,6 +23,7 @@ #include "ImageTransformation.h" #include #include +#include namespace page_layout { QRectF Utils::adaptContentRect(const ImageTransformation& xform, const QRectF& content_rect) { @@ -111,155 +112,107 @@ namespace page_layout { const QSizeF& aggregate_hard_size_mm, const Alignment& alignment, const QRectF& contentRect, - const QRectF& agg_content_rect) { + const QSizeF& contentSizeMM, + const QRectF& agg_content_rect, + const QRectF& pageRect) { if (alignment.isNull()) { -#ifdef DEBUG - std::cout << "\tskip soft margins: " << "\n"; -#endif // This means we are not aligning this page with others. return Margins(); } -#ifdef DEBUG - std::cout << "left: " << agg_content_rect.left() << " "; - std::cout << "top: " << agg_content_rect.top() << " "; - std::cout << "right: " << agg_content_rect.right() << " "; - std::cout << "bottom: " << agg_content_rect.bottom() << " "; - std::cout << "\n"; - - std::cout << "contentLeft: " << contentRect.left() << " "; - std::cout << "contentTop: " << contentRect.top() << " "; - std::cout << "contentRight: " << contentRect.right() << " "; - std::cout << "contentBottom: " << contentRect.bottom() << " "; - std::cout << "\n"; -#endif - - Alignment myAlign = alignment; - double top = 0.0; double bottom = 0.0; double left = 0.0; double right = 0.0; - const double delta_width - = aggregate_hard_size_mm.width() - hard_size_mm.width(); - const double delta_height - = aggregate_hard_size_mm.height() - hard_size_mm.height(); - - double leftBorder - = double(contentRect.left() - agg_content_rect.left() + 1) / double(agg_content_rect.width() + 1); - double rightBorder - = double(agg_content_rect.right() - contentRect.right() + 1) / double(agg_content_rect.width() + 1); - double topBorder - = double(contentRect.top() - agg_content_rect.top() + 1) / double(agg_content_rect.height() + 1); - double bottomBorder - = double(agg_content_rect.bottom() - contentRect.bottom() + 1) / double(agg_content_rect.height() + 1); + const double delta_width = aggregate_hard_size_mm.width() - hard_size_mm.width(); + const double delta_height = aggregate_hard_size_mm.height() - hard_size_mm.height(); double aggLeftBorder = 0.0; - double aggRightBorder = 0.0; + double aggRightBorder = delta_width; double aggTopBorder = 0.0; - double aggBottomBorder = 0.0; - - if (delta_width > 0.1) { - aggLeftBorder = (delta_width / (leftBorder + rightBorder)) * (leftBorder); - aggRightBorder = delta_width - aggLeftBorder; - } - if (delta_height > 0.1) { - aggTopBorder = (delta_height / (topBorder + bottomBorder)) * (topBorder); - aggBottomBorder = delta_height - aggTopBorder; - } + double aggBottomBorder = delta_height; + + Alignment correctedAlignment = alignment; + + if (!contentSizeMM.isEmpty() && !contentRect.isEmpty() && !pageRect.isEmpty() && !agg_content_rect.isEmpty()) { + const double pixelsPerMmHorizontal = contentRect.width() / contentSizeMM.width(); + const double pixelsPerMmVertical = contentRect.height() / contentSizeMM.height(); + + const QSizeF agg_content_size_mm(agg_content_rect.width() / pixelsPerMmHorizontal, + agg_content_rect.height() / pixelsPerMmVertical); + + QRectF correctedContentRect = contentRect.translated(-pageRect.x(), -pageRect.y()); + double content_rect_x_center_in_mm + = ((correctedContentRect.center().x() - agg_content_rect.left()) / agg_content_rect.width()) + * agg_content_size_mm.width(); + double content_rect_y_center_in_mm + = ((correctedContentRect.center().y() - agg_content_rect.top()) / agg_content_rect.height()) + * agg_content_size_mm.height(); + + if (delta_width > 0.1) { + aggLeftBorder = (content_rect_x_center_in_mm - (hard_size_mm.width() / 2)) + - ((agg_content_size_mm.width() - aggregate_hard_size_mm.width()) / 2); + if (aggLeftBorder < 0) { + aggLeftBorder = 0; + } else if (aggLeftBorder > delta_width) { + aggLeftBorder = delta_width; + } + aggRightBorder = delta_width - aggLeftBorder; + } + if (delta_height > 0.1) { + aggTopBorder = (content_rect_y_center_in_mm - (hard_size_mm.height() / 2)) + - ((agg_content_size_mm.height() - aggregate_hard_size_mm.height()) / 2); + if (aggTopBorder < 0) { + aggTopBorder = 0; + } else if (aggTopBorder > delta_height) { + aggTopBorder = delta_height; + } + aggBottomBorder = delta_height - aggTopBorder; + } -#ifdef DEBUG - std::cout << "delta_width: " << delta_width << " " << "delta_height: " << delta_height << "\n"; - std::cout << aggLeftBorder << " " << aggRightBorder << " " << aggTopBorder << " " << aggBottomBorder << ":" - << "\n"; - std::cout << leftBorder << " " << rightBorder << " " << topBorder << " " << bottomBorder << ":" << "\n"; -#endif - - if ((contentRect.width() > 1.0) - && ((myAlign.horizontal() == Alignment::HAUTO) || (myAlign.vertical() == Alignment::VAUTO))) { - double newLeftBorder = aggLeftBorder / aggregate_hard_size_mm.width(); - double newRightBorder = aggRightBorder / aggregate_hard_size_mm.width(); - double newTopBorder = aggTopBorder / aggregate_hard_size_mm.height(); - double newBottomBorder = aggBottomBorder / aggregate_hard_size_mm.height(); - - double cmi = double(contentRect.width() * contentRect.height()) - / double(agg_content_rect.width() * agg_content_rect.height()); - - double hTolerance = myAlign.tolerance(); - double vTolerance = myAlign.tolerance() * 0.7; - double hShift = newRightBorder - newLeftBorder; - double habsShift = std::abs(hShift); - double vShift = newBottomBorder - newTopBorder; - double vabsShift = std::abs(vShift); - -#ifdef DEBUG - std::cout << newLeftBorder << " " << newRightBorder << " " << newTopBorder << " " << newBottomBorder - << "\n"; - std::cout << vabsShift << " " << habsShift << std::endl; - std::cout << cmi << std::endl; - std::cout << hTolerance << " " << vTolerance << "\n"; -#endif - if (myAlign.horizontal() == Alignment::HAUTO) { - if ((1.0 - cmi) < alignment.tolerance()) { - myAlign.setHorizontal(Alignment::HCENTER); - } else if (habsShift < hTolerance) { - myAlign.setHorizontal(Alignment::HCENTER); - } else { - if ((hShift > 0) && (newLeftBorder > 1.4 * hTolerance)) { - myAlign.setHorizontal(Alignment::RIGHT); - } else if ((hShift <= 0) && (newRightBorder > 1.4 * hTolerance)) { - myAlign.setHorizontal(Alignment::LEFT); + if ((correctedAlignment.horizontal() == Alignment::HAUTO) + || (correctedAlignment.vertical() == Alignment::VAUTO)) { + const double goldenRatio = (1 + std::sqrt(5)) / 2; + const double rightGridLine = agg_content_size_mm.width() / goldenRatio; + const double leftGridLine = agg_content_size_mm.width() - rightGridLine; + const double bottomGridLine = agg_content_size_mm.height() / goldenRatio; + const double topGridLine = agg_content_size_mm.height() - bottomGridLine; + + if (correctedAlignment.horizontal() == Alignment::HAUTO) { + if (content_rect_x_center_in_mm < leftGridLine) { + correctedAlignment.setHorizontal(Alignment::LEFT); + } else if (content_rect_x_center_in_mm > rightGridLine) { + correctedAlignment.setHorizontal(Alignment::RIGHT); } else { - myAlign.setHorizontal(Alignment::HORIGINAL); + correctedAlignment.setHorizontal(Alignment::HCENTER); } } - } - if (myAlign.vertical() == Alignment::VAUTO) { - if ((1.0 - cmi) < alignment.tolerance()) { - myAlign.setVertical(Alignment::TOP); - } else if (vabsShift < vTolerance) { - myAlign.setVertical(Alignment::VCENTER); - } else { - if ((vShift > 0) && (newBottomBorder > 1.4 * vTolerance)) { - myAlign.setVertical(Alignment::TOP); - } else if ((vShift <= 0) && (newTopBorder > 1.4 * vTolerance)) { - myAlign.setVertical(Alignment::BOTTOM); + if (correctedAlignment.vertical() == Alignment::VAUTO) { + if (content_rect_y_center_in_mm < topGridLine) { + correctedAlignment.setVertical(Alignment::TOP); + } else if (content_rect_y_center_in_mm > bottomGridLine) { + correctedAlignment.setVertical(Alignment::BOTTOM); } else { - myAlign.setVertical(Alignment::VORIGINAL); + correctedAlignment.setVertical(Alignment::VCENTER); } } } } -#ifdef DEBUG - std::cout << "\n"; -#endif if (delta_width > 0.0) { - switch (myAlign.horizontal()) { + switch (correctedAlignment.horizontal()) { case Alignment::LEFT: -#ifdef DEBUG - std::cout << "align:left" << std::endl; -#endif right = delta_width; break; case Alignment::HCENTER: -#ifdef DEBUG - std::cout << "align:hcenter" << std::endl; -#endif left = right = 0.5 * delta_width; break; case Alignment::RIGHT: -#ifdef DEBUG - std::cout << "align:right" << std::endl; -#endif left = delta_width; break; default: -#ifdef DEBUG - std::cout << "align:horiginal" << std::endl; -#endif left = aggLeftBorder; right = aggRightBorder; break; @@ -267,29 +220,17 @@ namespace page_layout { } if (delta_height > 0.0) { - switch (myAlign.vertical()) { + switch (correctedAlignment.vertical()) { case Alignment::TOP: -#ifdef DEBUG - std::cout << "align:top" << std::endl; -#endif bottom = delta_height; break; case Alignment::VCENTER: -#ifdef DEBUG - std::cout << "align:vcenter" << std::endl; -#endif top = bottom = 0.5 * delta_height; break; case Alignment::BOTTOM: -#ifdef DEBUG - std::cout << "align:bottom" << std::endl; -#endif top = delta_height; break; default: -#ifdef DEBUG - std::cout << "align:voriginal" << std::endl; -#endif top = aggTopBorder; bottom = aggBottomBorder; break; @@ -315,7 +256,8 @@ namespace page_layout { ); Margins soft_margins_mm( calcSoftMarginsMM( - hard_size_mm, aggregate_hard_size_mm, params.alignment(), params.contentRect(), agg_content_rect + hard_size_mm, aggregate_hard_size_mm, params.alignment(), + params.contentRect(), params.contentSizeMM(), agg_content_rect, params.pageRect() ) ); diff --git a/filters/page_layout/Utils.h b/filters/page_layout/Utils.h index e89b95a0b..16403e801 100644 --- a/filters/page_layout/Utils.h +++ b/filters/page_layout/Utils.h @@ -70,7 +70,9 @@ namespace page_layout { const QSizeF& aggregate_hard_size_mm, const Alignment& alignment, const QRectF& contentRect, - const QRectF& agg_content_rect); + const QSizeF& contentSizeMM, + const QRectF& agg_content_rect, + const QRectF& pageRect); static Margins calcMarginsMM(const ImageTransformation& xform, const QRectF& page_rect, const QRectF& content_rect); diff --git a/filters/select_content/CacheDrivenTask.cpp b/filters/select_content/CacheDrivenTask.cpp index d4c836c1b..213dd6d4b 100644 --- a/filters/select_content/CacheDrivenTask.cpp +++ b/filters/select_content/CacheDrivenTask.cpp @@ -65,7 +65,7 @@ namespace select_content { } if (m_ptrNextTask) { - m_ptrNextTask->process(page_info, collector, xform, params->contentRect()); + m_ptrNextTask->process(page_info, collector, xform, params->pageRect(), params->contentRect()); return; } From 3ee69535e48614e5f778bd13d055ab698d184038 Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Wed, 28 Feb 2018 15:20:55 +0300 Subject: [PATCH 18/20] ~ => More accurate thumbnails drawing. (from ver. Universal) --- ThumbnailSequence.cpp | 165 +++++++++++++++++++++++++++++++----------- 1 file changed, 121 insertions(+), 44 deletions(-) diff --git a/ThumbnailSequence.cpp b/ThumbnailSequence.cpp index c9adf9c99..a49c9b940 100644 --- a/ThumbnailSequence.cpp +++ b/ThumbnailSequence.cpp @@ -521,7 +521,7 @@ void ThumbnailSequence::Impl::invalidateThumbnail(const PageInfo& page_info) { } void ThumbnailSequence::Impl::invalidateThumbnailImpl(const ItemsById::iterator id_it) { - std::unique_ptr composite(getCompositeItem(&* id_it, id_it->pageInfo)); + std::unique_ptr composite(getCompositeItem(&*id_it, id_it->pageInfo)); CompositeItem* const new_composite = composite.get(); CompositeItem* const old_composite = id_it->composite; @@ -573,44 +573,89 @@ void ThumbnailSequence::Impl::invalidateThumbnailImpl(const ItemsById::iterator ord_end = after_new; } - int view_width = m_graphicsScene.views().first()->width(); - - double xoffset = SPACING; - double yoffset = SPACING; + int view_width = 0; + if (!m_graphicsScene.views().isEmpty()) { + QGraphicsView* gv = m_graphicsScene.views().first(); + view_width = gv->width(); + view_width -= gv->style()->pixelMetric(QStyle::PM_ScrollBarExtent); + if (gv->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, gv)) { + view_width -= gv->frameWidth() * 2; + } + } + // look for a beginning of a row + double yoffset = -1; // undefined value if (ord_it != m_itemsInOrder.begin()) { - ItemsInOrder::iterator prev(ord_it); - --prev; - xoffset = prev->composite->pos().x() + prev->composite->boundingRect().width() + SPACING; - if (xoffset <= view_width) { - yoffset = prev->composite->pos().y() + SPACING; - } else { - xoffset = SPACING; - yoffset = prev->composite->pos().y() + prev->composite->boundingRect().height() + SPACING; + // can't use ord_it->composite->pos() here + ItemsInOrder::iterator it(ord_it); + --it; + if (it->composite->pos().x() + it->composite->boundingRect().width() + + SPACING + ord_it->composite->boundingRect().width() <= view_width) { + // not first in a row + yoffset = it->composite->pos().y(); // take ordinate of any prev page + ord_it = it; + if (it != m_itemsInOrder.begin()) { + while ((--it)->composite->pos().y() == yoffset) { + ord_it = it; + if (it == m_itemsInOrder.begin()) { + break; + } + } + } } } - - // Reposition items between the old and the new position of our item, - // including the item itself. - for (; ord_it != ord_end; ++ord_it) { - ord_it->composite->setPos(xoffset, yoffset); - xoffset += ord_it->composite->boundingRect().width() + SPACING; - if (xoffset > view_width) { - xoffset = SPACING; - yoffset += ord_it->composite->boundingRect().height() + SPACING; + // now ord_it is at beginning ot a row + if (yoffset < 0) { + // but it's ordinate is unknown as it's singe page or was first page in row + if (ord_it == m_itemsInOrder.begin()) { + // it's a first row + yoffset = SPACING; + } else { + // there are rows before and we'll find max height of prev one + ItemsInOrder::iterator it(ord_it); + --it; //we at end of the prev row + double next_yoffset = 0; + double row_y = it->composite->pos().y(); + do { + next_yoffset = std::max(it->composite->pos().y() + it->composite->boundingRect().height() + SPACING, + next_yoffset); + } while (it != m_itemsInOrder.begin() && (--it)->composite->pos().y() == row_y); + yoffset = next_yoffset; } } - // Reposition the items following both the new and the old position - // of the item, if the item size has changed. - if (old_size != new_size) { - for (; ord_it != m_itemsInOrder.end(); ++ord_it) { - ord_it->composite->setPos(xoffset, yoffset); - xoffset += ord_it->composite->boundingRect().width() + SPACING; + ord_end = m_itemsInOrder.end(); + while (ord_it != ord_end) { + int items_in_row = 0; + double sum_item_widths = 0; + double xoffset = SPACING; + for (ItemsInOrder::iterator row_it = ord_it; row_it != ord_end; ++row_it) { + const double item_width = row_it->composite->boundingRect().width(); + xoffset += item_width; if (xoffset > view_width) { - xoffset = SPACING; - yoffset += ord_it->composite->boundingRect().height() + SPACING; + if (items_in_row == 0) { + items_in_row = 1; // at least one page must be in a row + sum_item_widths = item_width; + } + break; } + items_in_row++; + sum_item_widths += item_width; + xoffset += SPACING; + } + + // split exceding width between margins of pages in a row + xoffset = SPACING; + double next_yoffset = 0; + for (; items_in_row > 0; --items_in_row, ++ord_it) { + CompositeItem* composite = ord_it->composite; + composite->setPos(xoffset, yoffset); + xoffset += composite->boundingRect().width() + SPACING; + next_yoffset = std::max(ord_it->composite->boundingRect().height() + SPACING, next_yoffset); + } + + if (ord_it != ord_end) { + yoffset += next_yoffset; } } // Update scene rect. @@ -655,28 +700,60 @@ void ThumbnailSequence::Impl::invalidateAllThumbnails() { } m_sceneRect = QRectF(0.0, 0.0, 0.0, 0.0); - double xoffset = SPACING; + + int view_width = 0; + if (!m_graphicsScene.views().isEmpty()) { + QGraphicsView* gv = m_graphicsScene.views().first(); + view_width = gv->width(); + view_width -= gv->style()->pixelMetric(QStyle::PM_ScrollBarExtent); + if (gv->style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, gv)) { + view_width -= gv->frameWidth() * 2; + } + } + double yoffset = SPACING; + ord_it = m_itemsInOrder.begin(); + while (ord_it != ord_end) { + int items_in_row = 0; + double sum_item_widths = 0; + double xoffset = SPACING; + for (ItemsInOrder::iterator row_it = ord_it; row_it != ord_end; ++row_it) { + const double item_width = row_it->composite->boundingRect().width(); + xoffset += item_width; + if (xoffset > view_width) { + if (items_in_row == 0) { + items_in_row = 1; // at least one page must be in a row + sum_item_widths = item_width; + } + break; + } + items_in_row++; + sum_item_widths += item_width; + xoffset += SPACING; + } - int num_items = 0; - int view_width = m_graphicsScene.views().first()->width(); - for (ord_it = m_itemsInOrder.begin(); ord_it != ord_end; ++ord_it, ++num_items) { - CompositeItem* composite = ord_it->composite; - composite->setPos(xoffset, yoffset); - composite->updateSceneRect(m_sceneRect); - composite->updateAppearence(ord_it->isSelected(), ord_it->isSelectionLeader()); - - xoffset += composite->boundingRect().width() + SPACING; - if (xoffset > view_width) { - xoffset = SPACING; - yoffset += composite->boundingRect().height() + SPACING; + // split exceding width between margins of pages in a row + xoffset = SPACING; + double next_yoffset = 0; + for (; items_in_row > 0; --items_in_row, ++ord_it) { + CompositeItem* composite = ord_it->composite; + composite->setPos(xoffset, yoffset); + composite->updateSceneRect(m_sceneRect); + composite->updateAppearence(ord_it->isSelected(), ord_it->isSelectionLeader()); + m_graphicsScene.addItem(composite); + xoffset += composite->boundingRect().width() + SPACING; + next_yoffset = std::max(composite->boundingRect().height() + SPACING, next_yoffset); + } + + if (ord_it != ord_end) { + yoffset += next_yoffset; } - m_graphicsScene.addItem(composite); } commitSceneRect(); } // ThumbnailSequence::Impl::invalidateAllThumbnails + bool ThumbnailSequence::Impl::setSelection(const PageId& page_id) { const ItemsById::iterator id_it(m_itemsById.find(page_id)); if (id_it == m_itemsById.end()) { From 3f69fdcdc0ed72946c7ff583bf53ccb51e13ada9 Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Fri, 2 Mar 2018 06:16:47 +0300 Subject: [PATCH 19/20] Added ability to separately control vertical and horizontal automatic alignment when auto or original alignment mode enabled. --- DefaultParamsDialog.cpp | 164 +- DefaultParamsDialog.h | 13 +- README.md | 3 +- filters/page_layout/Alignment.cpp | 30 +- filters/page_layout/Alignment.h | 14 +- filters/page_layout/OptionsWidget.cpp | 212 ++- filters/page_layout/OptionsWidget.h | 13 +- .../page_layout/ui/PageLayoutOptionsWidget.ui | 1418 +++++++++-------- ui/DefaultParamsDialog.ui | 605 ++++--- 9 files changed, 1483 insertions(+), 989 deletions(-) diff --git a/DefaultParamsDialog.cpp b/DefaultParamsDialog.cpp index 6a22e4b01..697ef5d22 100644 --- a/DefaultParamsDialog.cpp +++ b/DefaultParamsDialog.cpp @@ -123,6 +123,11 @@ DefaultParamsDialog::DefaultParamsDialog(QWidget* parent) Alignment(Alignment::BOTTOM, Alignment::RIGHT) ); + alignmentButtonGroup = std::make_unique(this); + for (const auto& buttonAndAlignment : alignmentByButton) { + alignmentButtonGroup->addButton(buttonAndAlignment.first); + } + darkerThresholdLink->setText( Utils::richTextForLink(darkerThresholdLink->text()) ); @@ -239,21 +244,40 @@ void DefaultParamsDialog::updatePageLayoutDisplay(const DefaultParams::PageLayou setLinkButtonLinked(leftRightLink, leftRightLinkEnabled); const Alignment& alignment = params.getAlignment(); - if (alignment.vertical() == Alignment::VAUTO) { + if (alignment.isAuto()) { alignmentMode->setCurrentIndex(0); - alignButtonsWidget->setEnabled(false); - } else if (alignment.vertical() == Alignment::VORIGINAL) { + autoAlignSettingsGroup->setVisible(true); + autoVerticalAligningCB->setChecked(alignment.isAutoVertical()); + autoHorizontalAligningCB->setChecked(alignment.isAutoHorizontal()); + } else if (alignment.isOriginal()) { alignmentMode->setCurrentIndex(2); - alignButtonsWidget->setEnabled(false); + autoAlignSettingsGroup->setVisible(true); + autoVerticalAligningCB->setChecked(alignment.isAutoVertical()); + autoHorizontalAligningCB->setChecked(alignment.isAutoHorizontal()); } else { alignmentMode->setCurrentIndex(1); - alignButtonsWidget->setEnabled(!alignment.isNull()); + autoAlignSettingsGroup->setVisible(false); } + updateAlignmentButtonsEnabled(); + updateAutoModeButtons(); + alignWithOthersCB->setChecked(!alignment.isNull()); - for (const auto& value : alignmentByButton) { - if (value.second == alignment) { - value.first->setChecked(true); + for (const auto& kv : alignmentByButton) { + if (alignment.isAuto() || alignment.isOriginal()) { + if (!alignment.isAutoHorizontal() + && (kv.second.vertical() == Alignment::VCENTER) + && (kv.second.horizontal() == alignment.horizontal())) { + kv.first->setChecked(true); + break; + } else if (!alignment.isAutoVertical() + && (kv.second.horizontal() == Alignment::HCENTER) + && (kv.second.vertical() == alignment.vertical())) { + kv.first->setChecked(true); + break; + } + } else if (kv.second == alignment) { + kv.first->setChecked(true); break; } } @@ -393,6 +417,8 @@ void DefaultParamsDialog::setupUiConnections() { connect(profileDeleteButton, SIGNAL(pressed()), this, SLOT(profileDeletePressed())); connect(colorSegmentationCB, SIGNAL(clicked(bool)), this, SLOT(colorSegmentationToggled(bool))); connect(posterizeCB, SIGNAL(clicked(bool)), this, SLOT(posterizeToggled(bool))); + connect(autoHorizontalAligningCB, SIGNAL(toggled(bool)), this, SLOT(autoHorizontalAligningToggled(bool))); + connect(autoVerticalAligningCB, SIGNAL(toggled(bool)), this, SLOT(autoVerticalAligningToggled(bool))); } void DefaultParamsDialog::removeUiConnections() { @@ -432,6 +458,8 @@ void DefaultParamsDialog::removeUiConnections() { disconnect(profileDeleteButton, SIGNAL(pressed()), this, SLOT(profileDeletePressed())); disconnect(colorSegmentationCB, SIGNAL(clicked(bool)), this, SLOT(colorSegmentationToggled(bool))); disconnect(posterizeCB, SIGNAL(clicked(bool)), this, SLOT(posterizeToggled(bool))); + disconnect(autoHorizontalAligningCB, SIGNAL(toggled(bool)), this, SLOT(autoHorizontalAligningToggled(bool))); + disconnect(autoVerticalAligningCB, SIGNAL(toggled(bool)), this, SLOT(autoVerticalAligningToggled(bool))); } void DefaultParamsDialog::rotateLeft() { @@ -522,13 +550,13 @@ void DefaultParamsDialog::autoMarginsToggled(const bool checked) { } void DefaultParamsDialog::alignmentModeChanged(const int idx) { - const bool enabled = alignWithOthersCB->isChecked() && (idx == 1); - alignButtonsWidget->setEnabled(enabled); + autoAlignSettingsGroup->setVisible((idx == 0) || (idx == 2)); + updateAlignmentButtonsEnabled(); + updateAutoModeButtons(); } -void DefaultParamsDialog::alignWithOthersToggled(const bool checked) { - const bool enabled = checked && (alignmentMode->currentIndex() == 1); - alignButtonsWidget->setEnabled(enabled); +void DefaultParamsDialog::alignWithOthersToggled(const bool) { + updateAlignmentButtonsEnabled(); } void DefaultParamsDialog::colorModeChanged(const int idx) { @@ -664,23 +692,30 @@ std::unique_ptr DefaultParamsDialog::buildParams() const { Alignment alignment; switch (alignmentMode->currentIndex()) { case 0: - alignment.setVertical(Alignment::VAUTO); - alignment.setHorizontal(Alignment::HAUTO); + if (autoVerticalAligningCB->isChecked()) { + alignment.setVertical(Alignment::VAUTO); + } else { + alignment.setVertical(alignmentByButton.at(getCheckedAlignmentButton()).vertical()); + } + if (autoHorizontalAligningCB->isChecked()) { + alignment.setHorizontal(Alignment::HAUTO); + } else { + alignment.setHorizontal(alignmentByButton.at(getCheckedAlignmentButton()).horizontal()); + } break; case 1: - for (auto item : alignmentByButton) { - if (item.first->isChecked()) { - alignment = item.second; - break; - } - } + alignment = alignmentByButton.at(getCheckedAlignmentButton()); break; case 2: - alignment.setVertical(Alignment::VORIGINAL); - if (autoMargins->isChecked()) { + if (autoVerticalAligningCB->isChecked()) { + alignment.setVertical(Alignment::VORIGINAL); + } else { + alignment.setVertical(alignmentByButton.at(getCheckedAlignmentButton()).vertical()); + } + if (autoHorizontalAligningCB->isChecked()) { alignment.setHorizontal(Alignment::HORIGINAL); } else { - alignment.setHorizontal(Alignment::HCENTER); + alignment.setHorizontal(alignmentByButton.at(getCheckedAlignmentButton()).horizontal()); } break; default: @@ -1089,3 +1124,84 @@ void DefaultParamsDialog::colorSegmentationToggled(bool checked) { void DefaultParamsDialog::posterizeToggled(bool checked) { posterizeOptionsWidget->setEnabled(checked); } + +void DefaultParamsDialog::updateAlignmentButtonsEnabled() { + bool enableHorizontalButtons; + bool enableVerticalButtons; + if ((alignmentMode->currentIndex() == 0) || (alignmentMode->currentIndex() == 2)) { + enableHorizontalButtons = !autoHorizontalAligningCB->isChecked() ? alignWithOthersCB->isChecked() + : false; + enableVerticalButtons = !autoVerticalAligningCB->isChecked() ? alignWithOthersCB->isChecked() + : false; + } else { + enableHorizontalButtons = enableVerticalButtons = alignWithOthersCB->isChecked(); + } + + alignTopLeftBtn->setEnabled(enableHorizontalButtons && enableVerticalButtons); + alignTopBtn->setEnabled(enableVerticalButtons); + alignTopRightBtn->setEnabled(enableHorizontalButtons && enableVerticalButtons); + alignLeftBtn->setEnabled(enableHorizontalButtons); + alignCenterBtn->setEnabled(enableHorizontalButtons || enableVerticalButtons); + alignRightBtn->setEnabled(enableHorizontalButtons); + alignBottomLeftBtn->setEnabled(enableHorizontalButtons && enableVerticalButtons); + alignBottomBtn->setEnabled(enableVerticalButtons); + alignBottomRightBtn->setEnabled(enableHorizontalButtons && enableVerticalButtons); +} + +void DefaultParamsDialog::updateAutoModeButtons() { + if ((alignmentMode->currentIndex() == 0) || (alignmentMode->currentIndex() == 2)) { + if (autoVerticalAligningCB->isChecked() && !autoHorizontalAligningCB->isChecked()) { + autoVerticalAligningCB->setEnabled(false); + } else if (autoHorizontalAligningCB->isChecked() && !autoVerticalAligningCB->isChecked()) { + autoHorizontalAligningCB->setEnabled(false); + } else { + autoVerticalAligningCB->setEnabled(true); + autoHorizontalAligningCB->setEnabled(true); + } + } + + if (autoVerticalAligningCB->isChecked() && !autoHorizontalAligningCB->isChecked()) { + switch (alignmentByButton.at(getCheckedAlignmentButton()).horizontal()) { + case Alignment::LEFT: + alignLeftBtn->setChecked(true); + break; + case Alignment::RIGHT: + alignRightBtn->setChecked(true); + break; + default: + alignCenterBtn->setChecked(true); + break; + } + } else if (autoHorizontalAligningCB->isChecked() && !autoVerticalAligningCB->isChecked()) { + switch (alignmentByButton.at(getCheckedAlignmentButton()).vertical()) { + case Alignment::TOP: + alignTopBtn->setChecked(true); + break; + case Alignment::BOTTOM: + alignBottomBtn->setChecked(true); + break; + default: + alignCenterBtn->setChecked(true); + break; + } + } +} + +QToolButton* DefaultParamsDialog::getCheckedAlignmentButton() const { + auto* checkedButton = dynamic_cast(alignmentButtonGroup->checkedButton()); + if (!checkedButton) { + checkedButton = alignCenterBtn; + } + + return checkedButton; +} + +void DefaultParamsDialog::autoHorizontalAligningToggled(bool) { + updateAlignmentButtonsEnabled(); + updateAutoModeButtons(); +} + +void DefaultParamsDialog::autoVerticalAligningToggled(bool) { + updateAlignmentButtonsEnabled(); + updateAutoModeButtons(); +} diff --git a/DefaultParamsDialog.h b/DefaultParamsDialog.h index bd8ba90ee..bc2c3db0b 100644 --- a/DefaultParamsDialog.h +++ b/DefaultParamsDialog.h @@ -20,6 +20,7 @@ Q_OBJECT int ignoreMarginChanges; OrthogonalRotation orthogonalRotation; std::unordered_map alignmentByButton; + std::unique_ptr alignmentButtonGroup; DefaultParamsProfileManager profileManager; int customDpiItemIdx; QString customDpiValue; @@ -55,7 +56,11 @@ private slots: void alignmentModeChanged(int idx); - void alignWithOthersToggled(bool checked); + void alignWithOthersToggled(bool); + + void autoHorizontalAligningToggled(bool); + + void autoVerticalAligningToggled(bool); void topBottomLinkClicked(); @@ -128,6 +133,12 @@ private slots: void setRotationPixmap(); + void updateAlignmentButtonsEnabled(); + + void updateAutoModeButtons(); + + QToolButton* getCheckedAlignmentButton() const; + void setLinkButtonLinked(QToolButton* button, bool linked); void loadParams(const DefaultParams& params); diff --git a/README.md b/README.md index 5a9f7917d..5d957d5c7 100644 --- a/README.md +++ b/README.md @@ -193,7 +193,8 @@ Features 3. Reworked calculation method for the original alignment. Now it is more precise. 4. Original alignment mode now considers the page box from 4th stage. 5. Fixed behaviour of horizontal alignment, when the original mode enabled, and auto margins has been enabled/disabled. Also on applying auto-margins / original alignment to the set of pages, that is now set correctly for each page. - + 6. Added ability to separately control vertical and horizontal automatic alignment when auto or original alignment mode enabled. + * Fixed other bugs of official, Enhanced and Featured versions and made lots of other improvements. * ##### Light and Dark color schemes diff --git a/filters/page_layout/Alignment.cpp b/filters/page_layout/Alignment.cpp index d8f1451e9..b61738ebb 100644 --- a/filters/page_layout/Alignment.cpp +++ b/filters/page_layout/Alignment.cpp @@ -26,9 +26,9 @@ namespace page_layout { m_isNull(false) { } - Alignment::Alignment(Vertical vert, Horizontal hor) - : m_vertical(vert), - m_horizontal(hor), + Alignment::Alignment(Vertical vertical, Horizontal horizontal) + : m_vertical(vertical), + m_horizontal(horizontal), m_isNull(false) { } @@ -123,16 +123,16 @@ namespace page_layout { return m_vertical; } - void Alignment::setVertical(Alignment::Vertical vert) { - m_vertical = vert; + void Alignment::setVertical(Alignment::Vertical vertical) { + m_vertical = vertical; } Alignment::Horizontal Alignment::horizontal() const { return m_horizontal; } - void Alignment::setHorizontal(Alignment::Horizontal hor) { - m_horizontal = hor; + void Alignment::setHorizontal(Alignment::Horizontal horizontal) { + m_horizontal = horizontal; } bool Alignment::isNull() const { @@ -142,4 +142,20 @@ namespace page_layout { void Alignment::setNull(bool is_null) { m_isNull = is_null; } + + bool Alignment::isAutoVertical() const { + return (m_vertical == VAUTO) || (m_vertical == VORIGINAL); + } + + bool Alignment::isAutoHorizontal() const { + return (m_horizontal == HAUTO) || (m_horizontal == HORIGINAL); + } + + bool Alignment::isOriginal() const { + return (m_vertical == VORIGINAL) || (m_horizontal == HORIGINAL); + } + + bool Alignment::isAuto() const { + return (m_vertical == VAUTO) || (m_horizontal == HAUTO); + } } // namespace page_layout diff --git a/filters/page_layout/Alignment.h b/filters/page_layout/Alignment.h index 9a846af8c..0ab82760b 100644 --- a/filters/page_layout/Alignment.h +++ b/filters/page_layout/Alignment.h @@ -51,22 +51,30 @@ namespace page_layout { */ Alignment(); - Alignment(Vertical vert, Horizontal hor); + Alignment(Vertical vertical, Horizontal horizontal); explicit Alignment(const QDomElement& el); Vertical vertical() const; - void setVertical(Vertical vert); + void setVertical(Vertical vertical); Horizontal horizontal() const; - void setHorizontal(Horizontal hor); + void setHorizontal(Horizontal horizontal); bool isNull() const; void setNull(bool is_null); + bool isAutoVertical() const; + + bool isAutoHorizontal() const; + + bool isOriginal() const; + + bool isAuto() const; + bool operator==(const Alignment& other) const; bool operator!=(const Alignment& other) const; diff --git a/filters/page_layout/OptionsWidget.cpp b/filters/page_layout/OptionsWidget.cpp index fba9eac06..e213bd7b4 100644 --- a/filters/page_layout/OptionsWidget.cpp +++ b/filters/page_layout/OptionsWidget.cpp @@ -33,7 +33,6 @@ namespace page_layout { const PageSelectionAccessor& page_selection_accessor) : m_ptrSettings(std::move(settings)), m_pageSelectionAccessor(page_selection_accessor), - m_ignoreMarginChanges(0), m_leftRightLinked(true), m_topBottomLinked(true) { { @@ -91,6 +90,11 @@ namespace page_layout { Alignment(Alignment::BOTTOM, Alignment::RIGHT) ); + m_alignmentButtonGroup = std::make_unique(this); + for (const auto& buttonAndAlignment : m_alignmentByButton) { + m_alignmentButtonGroup->addButton(buttonAndAlignment.first); + } + setupUiConnections(); } @@ -107,10 +111,22 @@ namespace page_layout { auto old_ignore = static_cast(m_ignoreMarginChanges); m_ignoreMarginChanges = true; - typedef AlignmentByButton::value_type KeyVal; - for (const KeyVal& kv : m_alignmentByButton) { - if (kv.second == m_alignment) { + for (const auto& kv : m_alignmentByButton) { + if (m_alignment.isAuto() || m_alignment.isOriginal()) { + if (!m_alignment.isAutoHorizontal() + && (kv.second.vertical() == Alignment::VCENTER) + && (kv.second.horizontal() == m_alignment.horizontal())) { + kv.first->setChecked(true); + break; + } else if (!m_alignment.isAutoVertical() + && (kv.second.horizontal() == Alignment::HCENTER) + && (kv.second.vertical() == m_alignment.vertical())) { + kv.first->setChecked(true); + break; + } + } else if (kv.second == m_alignment) { kv.first->setChecked(true); + break; } } @@ -121,15 +137,19 @@ namespace page_layout { alignWithOthersCB->blockSignals(false); alignmentMode->blockSignals(true); - if (alignment.vertical() == Alignment::VAUTO) { + if (alignment.isAuto()) { alignmentMode->setCurrentIndex(0); - } else if (alignment.vertical() == Alignment::VORIGINAL) { + autoAlignSettingsGroup->setVisible(true); + } else if (alignment.isOriginal()) { alignmentMode->setCurrentIndex(2); + autoAlignSettingsGroup->setVisible(true); } else { alignmentMode->setCurrentIndex(1); + autoAlignSettingsGroup->setVisible(false); } alignmentMode->blockSignals(false); updateAlignmentButtonsEnabled(); + updateAutoModeButtons(); autoMargins->setChecked(m_ptrSettings->isPageAutoMarginsEnabled(m_pageId)); updateMarginsControlsEnabled(); @@ -208,7 +228,7 @@ namespace page_layout { } if (m_leftRightLinked) { - const ScopedIncDec ingore_scope(m_ignoreMarginChanges); + const ScopedIncDec ignore_scope(m_ignoreMarginChanges); leftMarginSpinBox->setValue(val); rightMarginSpinBox->setValue(val); } @@ -231,7 +251,7 @@ namespace page_layout { } if (m_topBottomLinked) { - const ScopedIncDec ingore_scope(m_ignoreMarginChanges); + const ScopedIncDec ignore_scope(m_ignoreMarginChanges); topMarginSpinBox->setValue(val); bottomMarginSpinBox->setValue(val); } @@ -276,11 +296,6 @@ namespace page_layout { m_ptrSettings->setPageAutoMarginsEnabled(m_pageId, checked); updateMarginsControlsEnabled(); - if (m_alignment.vertical() == Alignment::VORIGINAL) { - m_alignment.setHorizontal(checked ? Alignment::HORIGINAL : Alignment::HCENTER); - } - - m_ptrSettings->setPageAlignment(m_pageId, m_alignment); emit reloadRequested(); } @@ -289,22 +304,22 @@ namespace page_layout { case 0: m_alignment.setVertical(Alignment::VAUTO); m_alignment.setHorizontal(Alignment::HAUTO); + autoAlignSettingsGroup->setVisible(true); + updateAutoModeButtons(); break; case 1: - for (auto button : m_alignmentByButton) { - if (button.first->isChecked()) { - m_alignment = button.second; - break; - } - } + m_alignment = m_alignmentByButton.at(getCheckedAlignmentButton()); + autoAlignSettingsGroup->setVisible(false); break; case 2: m_alignment.setVertical(Alignment::VORIGINAL); if (m_ptrSettings->isPageAutoMarginsEnabled(m_pageId)) { m_alignment.setHorizontal(Alignment::HORIGINAL); } else { - m_alignment.setHorizontal(Alignment::HCENTER); + m_alignment.setHorizontal(m_alignmentByButton.at(getCheckedAlignmentButton()).horizontal()); } + autoAlignSettingsGroup->setVisible(true); + updateAutoModeButtons(); break; default: break; @@ -315,13 +330,23 @@ namespace page_layout { } void OptionsWidget::alignmentButtonClicked() { + if (m_ignoreAlignmentButtonsChanges) { + return; + } + auto* const button = dynamic_cast(sender()); assert(button); - const auto it(m_alignmentByButton.find(button)); - assert(it != m_alignmentByButton.end()); + const Alignment& alignment = m_alignmentByButton.at(button); + + if (m_alignment.isAutoVertical()) { + m_alignment.setHorizontal(alignment.horizontal()); + } else if (m_alignment.isAutoHorizontal()) { + m_alignment.setVertical(alignment.vertical()); + } else { + m_alignment = alignment; + } - m_alignment = it->second; emit alignmentChanged(m_alignment); } @@ -368,12 +393,6 @@ namespace page_layout { } else { m_ptrSettings->setHardMarginsMM(page_id, m_marginsMM); } - - Alignment alignment = m_ptrSettings->getPageAlignment(page_id); - if (alignment.vertical() == Alignment::VORIGINAL) { - alignment.setHorizontal(autoMarginsEnabled ? Alignment::HORIGINAL : Alignment::HCENTER); - m_ptrSettings->setPageAlignment(page_id, alignment); - } } emit aggregateHardSizeChanged(); @@ -390,16 +409,7 @@ namespace page_layout { continue; } - if (m_alignment.vertical() != Alignment::VORIGINAL) { - m_ptrSettings->setPageAlignment(page_id, m_alignment); - } else { - Alignment alignment = m_alignment; - alignment.setHorizontal(m_ptrSettings->isPageAutoMarginsEnabled(page_id) - ? Alignment::HORIGINAL - : Alignment::HCENTER); - - m_ptrSettings->setPageAlignment(page_id, alignment); - } + m_ptrSettings->setPageAlignment(page_id, m_alignment); } emit invalidateAllThumbnails(); @@ -431,17 +441,20 @@ namespace page_layout { } void OptionsWidget::updateAlignmentButtonsEnabled() { - const bool enabled = alignWithOthersCB->isChecked() && (alignmentMode->currentIndex() == 1); - - alignTopLeftBtn->setEnabled(enabled); - alignTopBtn->setEnabled(enabled); - alignTopRightBtn->setEnabled(enabled); - alignLeftBtn->setEnabled(enabled); - alignCenterBtn->setEnabled(enabled); - alignRightBtn->setEnabled(enabled); - alignBottomLeftBtn->setEnabled(enabled); - alignBottomBtn->setEnabled(enabled); - alignBottomRightBtn->setEnabled(enabled); + bool enableHorizontalButtons = !m_alignment.isAutoHorizontal() ? alignWithOthersCB->isChecked() + : false; + bool enableVerticalButtons = !m_alignment.isAutoVertical() ? alignWithOthersCB->isChecked() + : false; + + alignTopLeftBtn->setEnabled(enableHorizontalButtons && enableVerticalButtons); + alignTopBtn->setEnabled(enableVerticalButtons); + alignTopRightBtn->setEnabled(enableHorizontalButtons && enableVerticalButtons); + alignLeftBtn->setEnabled(enableHorizontalButtons); + alignCenterBtn->setEnabled(enableHorizontalButtons || enableVerticalButtons); + alignRightBtn->setEnabled(enableHorizontalButtons); + alignBottomLeftBtn->setEnabled(enableHorizontalButtons && enableVerticalButtons); + alignBottomBtn->setEnabled(enableVerticalButtons); + alignBottomRightBtn->setEnabled(enableHorizontalButtons && enableVerticalButtons); } void OptionsWidget::updateMarginsControlsEnabled() { @@ -500,9 +513,16 @@ namespace page_layout { applyAlignmentBtn, SIGNAL(clicked()), this, SLOT(showApplyAlignmentDialog()) ); + connect( + autoHorizontalAligningCB, SIGNAL(toggled(bool)), + this, SLOT(autoHorizontalAligningToggled(bool)) + ); + connect( + autoVerticalAligningCB, SIGNAL(toggled(bool)), + this, SLOT(autoVerticalAligningToggled(bool)) + ); - typedef AlignmentByButton::value_type KeyVal; - for (const KeyVal& kv : m_alignmentByButton) { + for (const auto& kv : m_alignmentByButton) { connect( kv.first, SIGNAL(clicked()), this, SLOT(alignmentButtonClicked()) @@ -555,9 +575,16 @@ namespace page_layout { applyAlignmentBtn, SIGNAL(clicked()), this, SLOT(showApplyAlignmentDialog()) ); + disconnect( + autoHorizontalAligningCB, SIGNAL(toggled(bool)), + this, SLOT(autoHorizontalAligningToggled(bool)) + ); + disconnect( + autoVerticalAligningCB, SIGNAL(toggled(bool)), + this, SLOT(autoVerticalAligningToggled(bool)) + ); - typedef AlignmentByButton::value_type KeyVal; - for (const KeyVal& kv : m_alignmentByButton) { + for (const auto& kv : m_alignmentByButton) { disconnect( kv.first, SIGNAL(clicked()), this, SLOT(alignmentButtonClicked()) @@ -580,4 +607,81 @@ namespace page_layout { const Alignment& OptionsWidget::alignment() const { return m_alignment; } + + void OptionsWidget::autoHorizontalAligningToggled(const bool checked) { + if (checked) { + m_alignment.setHorizontal((alignmentMode->currentIndex() == 0) ? Alignment::HAUTO : Alignment::HORIGINAL); + } else { + m_alignment.setHorizontal(m_alignmentByButton.at(getCheckedAlignmentButton()).horizontal()); + } + + updateAlignmentButtonsEnabled(); + updateAutoModeButtons(); + emit alignmentChanged(m_alignment); + } + + void OptionsWidget::autoVerticalAligningToggled(const bool checked) { + if (checked) { + m_alignment.setVertical((alignmentMode->currentIndex() == 0) ? Alignment::VAUTO : Alignment::VORIGINAL); + } else { + m_alignment.setVertical(m_alignmentByButton.at(getCheckedAlignmentButton()).vertical()); + } + + updateAlignmentButtonsEnabled(); + updateAutoModeButtons(); + emit alignmentChanged(m_alignment); + } + + void OptionsWidget::updateAutoModeButtons() { + const ScopedIncDec scope_guard(m_ignoreAlignmentButtonsChanges); + + if (m_alignment.isAuto() || m_alignment.isOriginal()) { + autoVerticalAligningCB->setChecked(m_alignment.isAutoVertical()); + autoHorizontalAligningCB->setChecked(m_alignment.isAutoHorizontal()); + + if (autoVerticalAligningCB->isChecked() && !autoHorizontalAligningCB->isChecked()) { + autoVerticalAligningCB->setEnabled(false); + } else if (autoHorizontalAligningCB->isChecked() && !autoVerticalAligningCB->isChecked()) { + autoHorizontalAligningCB->setEnabled(false); + } else { + autoVerticalAligningCB->setEnabled(true); + autoHorizontalAligningCB->setEnabled(true); + } + } + + if (m_alignment.isAutoVertical() && !m_alignment.isAutoHorizontal()) { + switch (m_alignmentByButton.at(getCheckedAlignmentButton()).horizontal()) { + case Alignment::LEFT: + alignLeftBtn->setChecked(true); + break; + case Alignment::RIGHT: + alignRightBtn->setChecked(true); + break; + default: + alignCenterBtn->setChecked(true); + break; + } + } else if (m_alignment.isAutoHorizontal() && !m_alignment.isAutoVertical()) { + switch (m_alignmentByButton.at(getCheckedAlignmentButton()).vertical()) { + case Alignment::TOP: + alignTopBtn->setChecked(true); + break; + case Alignment::BOTTOM: + alignBottomBtn->setChecked(true); + break; + default: + alignCenterBtn->setChecked(true); + break; + } + } + } + + QToolButton* OptionsWidget::getCheckedAlignmentButton() const { + auto* checkedButton = dynamic_cast(m_alignmentButtonGroup->checkedButton()); + if (!checkedButton) { + checkedButton = alignCenterBtn; + } + + return checkedButton; + } } // namespace page_layout diff --git a/filters/page_layout/OptionsWidget.h b/filters/page_layout/OptionsWidget.h index 48c24e20a..498f1b5d0 100644 --- a/filters/page_layout/OptionsWidget.h +++ b/filters/page_layout/OptionsWidget.h @@ -93,6 +93,10 @@ namespace page_layout { void alignmentButtonClicked(); + void autoHorizontalAligningToggled(bool checked); + + void autoVerticalAligningToggled(bool checked); + void showApplyMarginsDialog(); void showApplyAlignmentDialog(); @@ -112,6 +116,10 @@ namespace page_layout { void updateMarginsControlsEnabled(); + void updateAutoModeButtons(); + + QToolButton* getCheckedAlignmentButton() const; + void setupUiConnections(); void removeUiConnections(); @@ -125,9 +133,12 @@ namespace page_layout { Dpi m_dpi; Margins m_marginsMM; Alignment m_alignment; - int m_ignoreMarginChanges; bool m_leftRightLinked; bool m_topBottomLinked; + std::unique_ptr m_alignmentButtonGroup; + + int m_ignoreMarginChanges = 0; + int m_ignoreAlignmentButtonsChanges = 0; }; } // namespace page_layout #endif // ifndef PAGE_LAYOUT_OPTIONSWIDGET_H_ diff --git a/filters/page_layout/ui/PageLayoutOptionsWidget.ui b/filters/page_layout/ui/PageLayoutOptionsWidget.ui index 7738187c6..301bd6b2e 100644 --- a/filters/page_layout/ui/PageLayoutOptionsWidget.ui +++ b/filters/page_layout/ui/PageLayoutOptionsWidget.ui @@ -6,657 +6,804 @@ 0 0 - 235 - 496 + 217 + 553 Form + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + - - - Margins + + + QFrame::NoFrame - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - Auto Margins - - - false - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - - - - 24 - 48 - - - - ... - - - - :/icons/stock-vchain-broken-24.png - :/icons/stock-vchain-24.png:/icons/stock-vchain-broken-24.png - - - - 9 - 24 - - - - true - - - - - - - Top - - - - - - - Right - - - - - - - Left - - - - - - - - 24 - 48 - - - - ... - - - - :/icons/stock-vchain-broken-24.png - :/icons/stock-vchain-24.png:/icons/stock-vchain-broken-24.png - - - - 9 - 24 - - - - false - - - true - - - - - - - 1 - - - 9999.000000000000000 - - - - - - - 1 - - - 9999.000000000000000 - - - - - - - 1 - - - 9999.000000000000000 - - - - - - - Bottom - - - - - - - 1 - - - 9999.000000000000000 - - - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - Apply To ... - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - - - - - - Alignment + + Qt::ScrollBarAlwaysOff - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - 1 - + + true + + + + + 0 + 0 + 217 + 553 + + + + + + + Margins + + - - Auto - + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + Auto Margins + + + false + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + - - Manual - + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + + + + 24 + 48 + + + + ... + + + + :/icons/stock-vchain-broken-24.png + :/icons/stock-vchain-24.png:/icons/stock-vchain-broken-24.png + + + + 9 + 24 + + + + true + + + + + + + Top + + + + + + + Right + + + + + + + Left + + + + + + + + 24 + 48 + + + + ... + + + + :/icons/stock-vchain-broken-24.png + :/icons/stock-vchain-24.png:/icons/stock-vchain-broken-24.png + + + + 9 + 24 + + + + false + + + true + + + + + + + 1 + + + 9999.000000000000000 + + + + + + + 1 + + + 9999.000000000000000 + + + + + + + 1 + + + 9999.000000000000000 + + + + + + + Bottom + + + + + + + 1 + + + 9999.000000000000000 + + + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + - - Original - + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + Apply To ... + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - Match size with other pages - - - true - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - 16 + + + + + + + Alignment + + + + 9 + + + 9 - - - - ... - - - - :/icons/stock-gravity-north-west-24.png:/icons/stock-gravity-north-west-24.png - - - - 24 - 24 - - - - true - - - true - - - - - - - ... - - - - :/icons/stock-gravity-north-24.png:/icons/stock-gravity-north-24.png - - - - 24 - 24 - - - - true - - - true - - - - - - - ... - - - - :/icons/stock-gravity-north-east-24.png:/icons/stock-gravity-north-east-24.png - - - - 24 - 24 - - - - true - - - true - - - - - - - ... - - - - :/icons/stock-gravity-west-24.png:/icons/stock-gravity-west-24.png - - - - 24 - 24 - - - - true - - - true - - - - - - - ... - - - - :/icons/stock-center-24.png:/icons/stock-center-24.png - - - - 24 - 24 - - - - true - - - true - - - true - - + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + 1 + + + + Auto + + + + + Manual + + + + + Original + + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + - - - - ... - - - - :/icons/stock-gravity-east-24.png:/icons/stock-gravity-east-24.png - - - - 24 - 24 - - - - true - - - true - + + + + Auto aligning + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + Enable horizontal + + + true + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + Enable vertical + + + true + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + - - - - ... - - - - :/icons/stock-gravity-south-west-24.png:/icons/stock-gravity-south-west-24.png - - - - 24 - 24 - - - - true - - - true - - + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + Match size with other pages + + + true + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + - - - - ... - - - - :/icons/stock-gravity-south-24.png:/icons/stock-gravity-south-24.png - - - - 24 - 24 - - - - true - - - true - - + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + 16 + + + + + ... + + + + :/icons/stock-gravity-north-west-24.png:/icons/stock-gravity-north-west-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-north-24.png:/icons/stock-gravity-north-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-north-east-24.png:/icons/stock-gravity-north-east-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-west-24.png:/icons/stock-gravity-west-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-center-24.png:/icons/stock-center-24.png + + + + 24 + 24 + + + + true + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-east-24.png:/icons/stock-gravity-east-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-south-west-24.png:/icons/stock-gravity-south-west-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-south-24.png:/icons/stock-gravity-south-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-south-east-24.png:/icons/stock-gravity-south-east-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + - - - - ... - - - - :/icons/stock-gravity-south-east-24.png:/icons/stock-gravity-south-east-24.png - - - - 24 - 24 - - - - true - - - true - - + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + Apply To ... + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - Apply To ... - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - + + + + + + Qt::Vertical + + + + 188 + 11 + + + + + + - - - - Qt::Vertical - - - - 1 - 1 - - - - @@ -667,25 +814,6 @@ 1 - - topBottomLink - topMarginSpinBox - bottomMarginSpinBox - leftRightLink - leftMarginSpinBox - rightMarginSpinBox - applyMarginsBtn - alignTopLeftBtn - alignTopBtn - alignTopRightBtn - alignLeftBtn - alignCenterBtn - alignRightBtn - alignBottomLeftBtn - alignBottomBtn - alignBottomRightBtn - applyAlignmentBtn - diff --git a/ui/DefaultParamsDialog.ui b/ui/DefaultParamsDialog.ui index dc4f8ef96..500a0316b 100644 --- a/ui/DefaultParamsDialog.ui +++ b/ui/DefaultParamsDialog.ui @@ -390,8 +390,8 @@ 0 0 - 637 - 442 + 193 + 162 @@ -629,8 +629,8 @@ 0 0 - 637 - 442 + 208 + 116 @@ -798,8 +798,8 @@ 0 0 - 637 - 442 + 208 + 314 @@ -1441,6 +1441,107 @@ + + + + Auto aligning + + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + Enable horizontal + + + true + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + Enable vertical + + + true + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + + @@ -1482,253 +1583,251 @@ - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - - - 16 - - - - - ... - - - - :/icons/stock-gravity-north-west-24.png:/icons/stock-gravity-north-west-24.png - - - - 24 - 24 - - - - true - - - true - - - - - - - ... - - - - :/icons/stock-gravity-north-24.png:/icons/stock-gravity-north-24.png - - - - 24 - 24 - - - - true - - - true - - - - - - - ... - - - - :/icons/stock-gravity-north-east-24.png:/icons/stock-gravity-north-east-24.png - - - - 24 - 24 - - - - true - - - true - - - - - - - ... - - - - :/icons/stock-gravity-west-24.png:/icons/stock-gravity-west-24.png - - - - 24 - 24 - - - - true - - - true - - - - - - - ... - - - - :/icons/stock-center-24.png:/icons/stock-center-24.png - - - - 24 - 24 - - - - true - - - true - - - true - - - - - - - ... - - - - :/icons/stock-gravity-east-24.png:/icons/stock-gravity-east-24.png - - - - 24 - 24 - - - - true - - - true - - - - - - - ... - - - - :/icons/stock-gravity-south-west-24.png:/icons/stock-gravity-south-west-24.png - - - - 24 - 24 - - - - true - - - true - - - - - - - ... - - - - :/icons/stock-gravity-south-24.png:/icons/stock-gravity-south-24.png - - - - 24 - 24 - - - - true - - - true - - - - - - - ... - - - - :/icons/stock-gravity-south-east-24.png:/icons/stock-gravity-south-east-24.png - - - - 24 - 24 - - - - true - - - true - - - - - - - - - Qt::Horizontal - - - - 1 - 1 - - - - - - + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + + + + 16 + + + + + ... + + + + :/icons/stock-gravity-north-west-24.png:/icons/stock-gravity-north-west-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-north-24.png:/icons/stock-gravity-north-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-north-east-24.png:/icons/stock-gravity-north-east-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-west-24.png:/icons/stock-gravity-west-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-center-24.png:/icons/stock-center-24.png + + + + 24 + 24 + + + + true + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-east-24.png:/icons/stock-gravity-east-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-south-west-24.png:/icons/stock-gravity-south-west-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-south-24.png:/icons/stock-gravity-south-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + ... + + + + :/icons/stock-gravity-south-east-24.png:/icons/stock-gravity-south-east-24.png + + + + 24 + 24 + + + + true + + + true + + + + + + + + + Qt::Horizontal + + + + 1 + 1 + + + + + From 755e3154192374e08ec0ceb6a5e19b1ca4274120 Mon Sep 17 00:00:00 2001 From: Alex <4lex49@zoho.com> Date: Fri, 2 Mar 2018 06:39:09 +0300 Subject: [PATCH 20/20] ~ Update VERSION and translations. --- translations/scantailor_ru.ts | 153 +++++++++++++++++------- translations/scantailor_untranslated.ts | 151 ++++++++++++++++------- version.h | 2 +- 3 files changed, 222 insertions(+), 84 deletions(-) diff --git a/translations/scantailor_ru.ts b/translations/scantailor_ru.ts index 6af2cdb9d..dd7a06b02 100644 --- a/translations/scantailor_ru.ts +++ b/translations/scantailor_ru.ts @@ -142,7 +142,7 @@ - + @@ -151,14 +151,14 @@ - + ... - + Reset Сбросить @@ -169,12 +169,12 @@ - + Mode Режим - + Page Layout Тип разреза @@ -219,12 +219,12 @@ - + Options Настройки - + Shift with corners while they are in black. Скорректировать края по черной области. @@ -303,12 +303,27 @@ Оригинал - + + Auto aligning + Авто выравнивание + + + + Enable horizontal + Вкл. горизонтальное + + + + Enable vertical + Вкл. вертикальное + + + Match size with other pages Выровнять размер с остальн. стр. - + Output Вывод @@ -668,12 +683,12 @@ - + Custom Выборочный - + Marginal По краям @@ -688,10 +703,10 @@ Источник - - + + - + Error Ошибка @@ -701,7 +716,7 @@ Ошибка при загрузке профиля. - + The name conflicts with a default profile name. Please enter a different name. Это имя конфликтует со стандартным именем профиля. Введите другое имя. @@ -711,7 +726,7 @@ Ошибка при сохранении профиля. - + Error deleting the profile. Ошибка при удалении профиля. @@ -889,7 +904,7 @@ ImageViewBase - + Use the mouse wheel or +/- to zoom. When zoomed, dragging is possible. Используйте колесо мыши для увеличения. В увеличенном виде доступно перетаскивание. @@ -1003,7 +1018,7 @@ - + Save Project Сохранить проект @@ -1245,7 +1260,7 @@ Отмена - + Insert before ... Вставить перед ... @@ -1265,7 +1280,7 @@ Вставить сюда ... - + Scan Tailor Projects Проекты Scan Tailor @@ -1278,13 +1293,13 @@ - + Error Ошибка - + Unable to open the project file. Не удалось открыть файл проекта. @@ -1294,7 +1309,7 @@ Файл проекта поврежден. - + version версия @@ -2077,7 +2092,7 @@ To determine it, run batch processing at "Select Content" or "Mar - + Margins Поля @@ -2089,7 +2104,7 @@ To determine it, run batch processing at "Select Content" or "Mar - + @@ -2102,7 +2117,7 @@ To determine it, run batch processing at "Select Content" or "Mar - + Bottom Снизу @@ -2118,17 +2133,17 @@ To determine it, run batch processing at "Select Content" or "Mar - + Apply To ... Применить... - + Alignment Выравнивание - + Auto auto Автоматически @@ -2146,12 +2161,27 @@ To determine it, run batch processing at "Select Content" or "Mar Оригинал - + Auto Margins Автоматические поля - + + Auto aligning + Авто выравнивание + + + + Enable horizontal + Вкл. горизонтальное + + + + Enable vertical + Вкл. вертикальное + + + Match size with other pages Выровнять размер с остальн. стр. @@ -2462,7 +2492,7 @@ You should remove them from the project. QObject - + px @@ -2732,12 +2762,51 @@ You should remove them from the project. Автосохранение текущего проекта - + + Deviation + Отклонение + + + Highlight the thumbnails of pages with high deviation Подсвечивать страницы с большим отклонением - + + Params + Параметры + + + + Deksew: + Комп. поворота: + + + + Select content: + Полезн. обл.: + + + + + + Deviation multiplier: a higher value means lower sensivity. + Множитель отклонения: большее значение обозначает меньшую чувствительность. + + + + Margins: + Поля: + + + + + + The minimum deviation to be highlighted. + Минимальное отклонение, которое будет подсвечено. + + + Color Scheme: Цветовая схема: @@ -2747,7 +2816,7 @@ You should remove them from the project. Язык: - + Saving Сохранение @@ -2805,7 +2874,7 @@ You should remove them from the project. - + Information Информация @@ -2908,7 +2977,7 @@ You should remove them from the project. ThumbnailSequence - + %1 (page %2) %1 (стр. %2) @@ -3305,7 +3374,7 @@ You should remove them from the project. page_layout::ImageView - + Resize margins by dragging any of the solid lines. Меняйте размеры полей, перетаскивая хоть внешние, хоть внутренние сплошные линии. @@ -3313,7 +3382,7 @@ You should remove them from the project. page_layout::OptionsWidget - + Apply Margins Применить поля @@ -3404,9 +3473,9 @@ You should remove them from the project. select_content::ImageView - - Use the context menu to enable / disable the content box. Hold Shift to drag a box. - Используйте контекстное меню для включения / выключения полезной области. Удерживайте Shift для перетаскивания области. + + Use the context menu to enable / disable the content box. Hold Shift to drag a box. Use double-click on content to automatically adjust the content area. + Используйте контекстное меню для включения / выключения полезной области. Удерживайте Shift для перетаскивания области. Используйте двойной клик по контенту, чтобы автоматически настроить полезную область. diff --git a/translations/scantailor_untranslated.ts b/translations/scantailor_untranslated.ts index 45714aea6..7fbb6b8e6 100644 --- a/translations/scantailor_untranslated.ts +++ b/translations/scantailor_untranslated.ts @@ -142,7 +142,7 @@ - + @@ -151,14 +151,14 @@ - + ... - + Reset @@ -169,12 +169,12 @@ - + Mode - + Page Layout @@ -219,12 +219,12 @@ - + Options - + Shift with corners while they are in black. @@ -303,12 +303,27 @@ - + + Auto aligning + + + + + Enable horizontal + + + + + Enable vertical + + + + Match size with other pages - + Output @@ -668,12 +683,12 @@ - + Custom - + Marginal @@ -688,10 +703,10 @@ - - + + - + Error @@ -701,7 +716,7 @@ - + The name conflicts with a default profile name. Please enter a different name. @@ -711,7 +726,7 @@ - + Error deleting the profile. @@ -887,7 +902,7 @@ ImageViewBase - + Use the mouse wheel or +/- to zoom. When zoomed, dragging is possible. @@ -1001,7 +1016,7 @@ - + Save Project @@ -1243,7 +1258,7 @@ - + Insert before ... @@ -1263,7 +1278,7 @@ - + Scan Tailor Projects @@ -1276,13 +1291,13 @@ - + Error - + Unable to open the project file. @@ -1292,7 +1307,7 @@ - + version @@ -2069,7 +2084,7 @@ To determine it, run batch processing at "Select Content" or "Mar - + Margins @@ -2081,7 +2096,7 @@ To determine it, run batch processing at "Select Content" or "Mar - + @@ -2094,7 +2109,7 @@ To determine it, run batch processing at "Select Content" or "Mar - + Bottom @@ -2110,17 +2125,17 @@ To determine it, run batch processing at "Select Content" or "Mar - + Apply To ... - + Alignment - + Auto auto @@ -2138,12 +2153,27 @@ To determine it, run batch processing at "Select Content" or "Mar - + Auto Margins - + + Auto aligning + + + + + Enable horizontal + + + + + Enable vertical + + + + Match size with other pages @@ -2444,7 +2474,7 @@ You should remove them from the project. QObject - + px @@ -2712,12 +2742,51 @@ You should remove them from the project. - + + Deviation + + + + Highlight the thumbnails of pages with high deviation - + + Params + + + + + Deksew: + + + + + Select content: + + + + + + + Deviation multiplier: a higher value means lower sensivity. + + + + + Margins: + + + + + + + The minimum deviation to be highlighted. + + + + Color Scheme: @@ -2727,7 +2796,7 @@ You should remove them from the project. - + Saving @@ -2785,7 +2854,7 @@ You should remove them from the project. - + Information @@ -2888,7 +2957,7 @@ You should remove them from the project. ThumbnailSequence - + %1 (page %2) @@ -3285,7 +3354,7 @@ You should remove them from the project. page_layout::ImageView - + Resize margins by dragging any of the solid lines. @@ -3293,7 +3362,7 @@ You should remove them from the project. page_layout::OptionsWidget - + Apply Margins @@ -3384,8 +3453,8 @@ You should remove them from the project. select_content::ImageView - - Use the context menu to enable / disable the content box. Hold Shift to drag a box. + + Use the context menu to enable / disable the content box. Hold Shift to drag a box. Use double-click on content to automatically adjust the content area. diff --git a/version.h b/version.h index 1b3c5fb11..21e3d8c9a 100644 --- a/version.h +++ b/version.h @@ -19,7 +19,7 @@ #ifndef SCANTAILOR_VERSION_H_ #define SCANTAILOR_VERSION_H_ -#define VERSION "1.0.11" +#define VERSION "1.0.12" #define VERSION_QUAD "" // Must be "x.x.x.x" or an empty string. #define PROJECT_VERSION 2