Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: CMake

on:
push:
branches: [ "master" ]
branches: [master, main]
pull_request:
branches: [ "master" ]
branches: [master, main]

env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
Expand All @@ -24,10 +24,10 @@ jobs:
run: |
sudo apt-get update
sudo apt-get install -y --fix-missing \
gcc g++ cmake \
build-essential gcc g++ cmake \
libjpeg-dev libpng-dev \
libtiff6 libtiff5-dev \
libboost-test-dev \
libtiff6 libtiff-dev zlib1g-dev \
libboost-test-dev libboost-dev \
qtbase5-dev libqt5svg5-dev \
qttools5-dev qttools5-dev-tools \
libqt5opengl5-dev \
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ Go to [this repository](https://github.com/ScanTailor-Advanced/scantailor-libs-b

**Linux – Wayland (issue #97):** If you see rendering issues (blank or corrupted windows) when running under Wayland, try starting the application with `QT_QPA_PLATFORM=xcb` to use the X11 compatibility layer.

**Linux – Flatpak / Flathub (issue #105):** A Flatpak manifest is provided in `flatpak/org.scantailor.Advanced.json`. To build locally: `flatpak-builder --user --force-clean build flatpak/org.scantailor.Advanced.json` (requires `flatpak` and `flatpak-builder`). To publish on Flathub, use a distinct application ID (e.g. `org.scantailor.Advanced`) so it does not conflict with the original ScanTailor package.
**Linux – Flatpak / Flathub (issue #105):** End users should prefer **pre-built** binaries from [GitHub Releases](https://github.com/ScanTailor-Advanced/scantailor-advanced/releases) when available (`.deb` / AppImage on tagged releases). A Flatpak manifest for **maintainers** is in `flatpak/org.scantailor.Advanced.json` (`flatpak-builder --user --force-clean build flatpak/org.scantailor.Advanced.json`). Publishing on Flathub needs a **new** application ID (e.g. `org.scantailor.Advanced`) so it does not replace the legacy `com.github._4lex4.*` app.

**Community examples / test data:** See also [scantailor-testing](https://github.com/ImageProcessing-ElectronicPublications/scantailor-testing) (community repository; issue [#43](https://github.com/ScanTailor-Advanced/scantailor-advanced/issues/43)).

## About this fork

Expand Down
354 changes: 354 additions & 0 deletions scripts/post_issue_followups.py

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/app/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,8 @@ void MainWindow::goPrevSelectedPage() {
}

void MainWindow::goToPage(const PageId& pageId, const ThumbnailSequence::SelectionAction selectionAction) {
focusButton->setChecked(true);
// Do not toggle Follow page here (issue #51): keyboard navigation used to force it on while mouse
// selection did not. Batch processing and similar flows set focus explicitly where needed.

m_thumbSequence->setSelection(pageId, selectionAction);

Expand Down
44 changes: 44 additions & 0 deletions src/core/PageSequence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include "PageSequence.h"

#include <vector>

void PageSequence::append(const PageInfo& pageInfo) {
m_pages.push_back(pageInfo);
}
Expand Down Expand Up @@ -78,6 +80,48 @@ std::set<PageId> PageSequence::selectEveryOther(const PageId& base) const {
return selection;
}

std::set<PageId> PageSequence::selectThisPageAndFollowingEveryOther(const PageId& page) const {
std::set<PageId> selection;
const int baseIdx = pageNo(page);
if (baseIdx < 0) {
return selection;
}
for (size_t i = static_cast<size_t>(baseIdx); i < m_pages.size(); i += 2) {
selection.insert(m_pages[i].id());
}
return selection;
}

std::set<PageId> PageSequence::selectEveryOtherInSubsetFromPage(const PageId& base,
const std::set<PageId>& subset) const {
std::set<PageId> selection;
if (subset.empty()) {
return selection;
}
std::vector<PageId> ordered;
ordered.reserve(subset.size());
for (size_t i = 0; i < m_pages.size(); ++i) {
const PageId id = m_pages[i].id();
if (subset.count(id) != 0) {
ordered.push_back(id);
}
}
int start = -1;
for (size_t i = 0; i < ordered.size(); ++i) {
if (ordered[i] == base) {
start = static_cast<int>(i);
break;
}
}
if (start < 0) {
return selection;
}
for (int i = start; i < static_cast<int>(ordered.size()); i += 2) {
selection.insert(ordered[i]);
}
return selection;
}

std::vector<PageInfo>::iterator PageSequence::begin() {
return m_pages.begin();
}
Expand Down
9 changes: 9 additions & 0 deletions src/core/PageSequence.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ class PageSequence {

std::set<PageId> selectEveryOther(const PageId& base) const;

/** Current page and every second page after it in thumbnail/document order (issue #84). */
std::set<PageId> selectThisPageAndFollowingEveryOther(const PageId& page) const;

/**
* Among pages in \p subset, in document order, take \p base and every second page after it
* within that ordered subset (issue #84; fixes std::set iteration order in some Apply dialogs).
*/
std::set<PageId> selectEveryOtherInSubsetFromPage(const PageId& base, const std::set<PageId>& subset) const;

std::vector<PageInfo>::iterator begin();

std::vector<PageInfo>::iterator end();
Expand Down
18 changes: 2 additions & 16 deletions src/core/filters/deskew/ApplyDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

#include "ApplyDialog.h"

#include <iostream>

#include "PageSelectionAccessor.h"

namespace deskew {
Expand Down Expand Up @@ -49,22 +47,10 @@ void ApplyDialog::onSubmit() {
m_pages.selectEveryOther(m_curPage).swap(pages);
emit appliedTo(pages);
} else if (thisEveryOtherRB->isChecked()) {
std::set<PageId> tmp;
m_pages.selectPagePlusFollowers(m_curPage).swap(tmp);
auto it = tmp.begin();
for (int i = 0; it != tmp.end(); ++it, ++i) {
if (i % 2 == 0) {
pages.insert(*it);
}
}
m_pages.selectThisPageAndFollowingEveryOther(m_curPage).swap(pages);
emit appliedTo(pages);
} else if (everyOtherSelectedRB->isChecked()) {
auto it = m_selectedPages.begin();
for (int i = 0; it != m_selectedPages.end(); ++it, ++i) {
if (i % 2 == 0) {
pages.insert(*it);
}
}
m_pages.selectEveryOtherInSubsetFromPage(m_curPage, m_selectedPages).swap(pages);
emit appliedTo(pages);
}
accept();
Expand Down
9 changes: 1 addition & 8 deletions src/core/filters/fix_orientation/ApplyDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,7 @@ void ApplyDialog::onSubmit() {
} else if (everyOtherRB->isChecked()) {
m_pages.selectEveryOther(m_curPage).swap(pages);
} else if (thisEveryOtherRB->isChecked()) {
std::set<PageId> tmp;
m_pages.selectPagePlusFollowers(m_curPage).swap(tmp);
auto it = tmp.begin();
for (int i = 0; it != tmp.end(); ++it, ++i) {
if (i % 2 == 0) {
pages.insert(*it);
}
}
m_pages.selectThisPageAndFollowingEveryOther(m_curPage).swap(pages);
} else if (everyOtherSelectedRB->isChecked()) {
assert(m_selectedRanges.size() == 1);
const PageRange& range = m_selectedRanges.front();
Expand Down
9 changes: 1 addition & 8 deletions src/core/filters/page_layout/ApplyDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,7 @@ void ApplyDialog::onSubmit() {
} else if (everyOtherRB->isChecked()) {
m_pages.selectEveryOther(m_curPage).swap(pages);
} else if (thisEveryOtherRB->isChecked()) {
std::set<PageId> tmp;
m_pages.selectPagePlusFollowers(m_curPage).swap(tmp);
auto it = tmp.begin();
for (int i = 0; it != tmp.end(); ++it, ++i) {
if (i % 2 == 0) {
pages.insert(*it);
}
}
m_pages.selectThisPageAndFollowingEveryOther(m_curPage).swap(pages);
} else if (everyOtherSelectedRB->isChecked()) {
assert(m_selectedRanges.size() == 1);
const PageRange& range = m_selectedRanges.front();
Expand Down
9 changes: 1 addition & 8 deletions src/core/filters/page_layout/ApplyMarginsDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,7 @@ void ApplyMarginsDialog::onSubmit() {
} else if (everyOtherRB->isChecked()) {
m_pages.selectEveryOther(m_curPage).swap(pages);
} else if (thisEveryOtherRB->isChecked()) {
std::set<PageId> tmp;
m_pages.selectPagePlusFollowers(m_curPage).swap(tmp);
auto it = tmp.begin();
for (int i = 0; it != tmp.end(); ++it, ++i) {
if (i % 2 == 0) {
pages.insert(*it);
}
}
m_pages.selectThisPageAndFollowingEveryOther(m_curPage).swap(pages);
} else if (everyOtherSelectedRB->isChecked()) {
assert(m_selectedRanges.size() == 1);
const PageRange& range = m_selectedRanges.front();
Expand Down
16 changes: 2 additions & 14 deletions src/core/filters/page_split/SplitModeDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,9 @@ void SplitModeDialog::onSubmit() {
} else if (everyOtherRB->isChecked()) {
m_pages.selectEveryOther(m_curPage).swap(pages);
} else if (thisEveryOtherRB->isChecked()) {
std::set<PageId> tmp;
m_pages.selectPagePlusFollowers(m_curPage).swap(tmp);
auto it = tmp.begin();
for (int i = 0; it != tmp.end(); ++it, ++i) {
if (i % 2 == 0) {
pages.insert(*it);
}
}
m_pages.selectThisPageAndFollowingEveryOther(m_curPage).swap(pages);
} else if (everyOtherSelectedRB->isChecked()) {
auto it = m_selectedPages.begin();
for (int i = 0; it != m_selectedPages.end(); ++it, ++i) {
if (i % 2 == 0) {
pages.insert(*it);
}
}
m_pages.selectEveryOtherInSubsetFromPage(m_curPage, m_selectedPages).swap(pages);
}

emit accepted(pages, layoutType, applyCutOption->isChecked());
Expand Down
8 changes: 1 addition & 7 deletions src/core/filters/select_content/ApplyDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,7 @@ void ApplyDialog::onSubmit() {
} else if (everyOtherRB->isChecked()) {
m_pages.selectEveryOther(m_curPage).swap(pages);
} else if (thisEveryOtherRB->isChecked()) {
// "This page and the following every other" in document order (issue #84).
const int baseIdx = m_pages.pageNo(m_curPage);
if (baseIdx >= 0) {
for (size_t i = static_cast<size_t>(baseIdx); i < m_pages.numPages(); i += 2) {
pages.insert(m_pages.pageAt(i).id());
}
}
m_pages.selectThisPageAndFollowingEveryOther(m_curPage).swap(pages);
} else if (everyOtherSelectedRB->isChecked()) {
assert(m_selectedRanges.size() == 1);
const PageRange& range = m_selectedRanges.front();
Expand Down
1 change: 1 addition & 0 deletions src/resources/unix/scantailor.desktop.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[Desktop Entry]
Version=1.0
X-ScanTailor-Advanced-Version=@VERSION@
Name=ScanTailor Advanced
Comment=Interactive post-processing tool for scanned pages
Exec=scantailor %f
Expand Down