Skip to content

Commit 8a0b2cd

Browse files
authored
Make pre-processing options like rotate/scale/splitting/flipping available 4 python binding decode_files method (#50)
* Prepare python binding 2 take those options * Make decodeImageFilesToJson returning a json list instead of a list of tuples of origin/json * Fix version no * Make decodeImageFilesToJson returning a dict of origin/json-string; Use temp preProcessor options given on method call overruling defaults
1 parent 683c99b commit 8a0b2cd

17 files changed

Lines changed: 248 additions & 141 deletions

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"name": "pythoncpp launch python debugger",
1616
"type": "debugpy",
1717
"request": "launch",
18-
"program": "source/python/run.py",
18+
"program": "source/python/filter_keys.py",
1919
"console": "integratedTerminal",
2020
"env": {
2121
"PYTHONPATH": "${workspaceFolder}/build/Debug/bin"

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,8 @@ to execute the following minimal Python script:
5656
```
5757
from ticket_decoder import DecoderFacade
5858
59-
decoder_facade = DecoderFacade(fail_on_interpreter_error = False)
60-
for result in decoder_facade.decode_files('path/2/your/ticket.pdf'):
61-
print(result[1])
59+
decoder_facade = DecoderFacade()
60+
print(decoder_facade.decode_files('path/2/your/ticket.pdf'))
6261
```
6362

6463
## ticket-analyzer

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
[project]
55
name = "ticket-decoder"
6-
version = "v0.19.1"
6+
version = "v0.19.3"
77
description = "Train ticket barcode to json decoding library, using zxing-cpp decoding in combination with record interpreter, to transform content into json structure"
88
license = "GPL-3.0-or-later"
99
authors = [ { name = "user4223" } ]

source/lib/api/include/DecoderFacade.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#include <lib/infrastructure/include/ParameterCollector.h>
88
#include <lib/infrastructure/include/ContextFwd.h>
99

10+
#include <lib/dip/include/PreProcessorOptions.h>
11+
1012
#include <lib/input/api/include/InputElement.h>
1113
#include <lib/input/api/include/LoadResult.h>
1214

@@ -100,10 +102,16 @@ namespace api
100102
DecoderFacadeBuilder::Options const &options;
101103

102104
template <typename T>
103-
void decodeImage(input::api::InputElement image, std::function<void(T &&, std::string)> transformer);
105+
void decodeImage(
106+
input::api::InputElement image,
107+
std::optional<dip::PreProcessorOptions> preProcessorOptions,
108+
std::function<void(T &&, std::string)> transformer);
104109

105110
template <typename T>
106-
void decodeImageFiles(std::filesystem::path path, std::function<void(T &&, std::string)> transformer);
111+
void decodeImageFiles(
112+
std::filesystem::path path,
113+
std::optional<dip::PreProcessorOptions> preProcessorOptions,
114+
std::function<void(T &&, std::string)> transformer);
107115

108116
std::string interpretRawBytes(std::vector<std::uint8_t> bytes, std::string origin);
109117

@@ -144,11 +152,17 @@ namespace api
144152

145153
/* Barcodes from image or PDF input file/directory to json, raw byte-array or raw base64-string
146154
*/
147-
std::vector<std::pair<std::string, std::string>> decodeImageFilesToJson(std::filesystem::path path);
155+
std::vector<std::pair<std::string, std::string>> decodeImageFilesToJson(
156+
std::filesystem::path path,
157+
std::optional<dip::PreProcessorOptions> preProcessorOptions = std::nullopt);
148158

149-
std::vector<std::pair<std::string, std::vector<std::uint8_t>>> decodeImageFilesToRawBytes(std::filesystem::path path);
159+
std::vector<std::pair<std::string, std::vector<std::uint8_t>>> decodeImageFilesToRawBytes(
160+
std::filesystem::path path,
161+
std::optional<dip::PreProcessorOptions> preProcessorOptions = std::nullopt);
150162

151-
std::vector<std::pair<std::string, std::string>> decodeImageFilesToRawBase64(std::filesystem::path path);
163+
std::vector<std::pair<std::string, std::string>> decodeImageFilesToRawBase64(
164+
std::filesystem::path path,
165+
std::optional<dip::PreProcessorOptions> preProcessorOptions = std::nullopt);
152166

153167
/* Pre-loaded image data as input-element to json
154168
*/

source/lib/api/source/DecoderFacade.cpp

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ namespace api
4343
std::optional<unsigned int> loadOptionDpi;
4444
std::optional<int> imageRotation;
4545
std::optional<unsigned int> imageScale;
46-
std::optional<std::string> imageSplit;
46+
std::optional<std::string> imageSplitting;
4747
std::optional<unsigned int> imageFlipping;
4848
std::optional<detector::api::DetectorType> detectorType;
4949
std::optional<bool> pureBarcode;
@@ -62,7 +62,7 @@ namespace api
6262

6363
unsigned int getImageScale() const { return imageScale.value_or(dip::PreProcessorOptions::DEFAULT.scalePercent); }
6464

65-
std::string getImageSplit() const { return imageSplit.value_or(dip::PreProcessorOptions::DEFAULT.split); }
65+
std::string getImageSplit() const { return imageSplitting.value_or(dip::PreProcessorOptions::DEFAULT.splittingMode); }
6666

6767
unsigned int getImageFlipping() const { return imageFlipping.value_or(dip::PreProcessorOptions::DEFAULT.flippingMode); }
6868

@@ -199,7 +199,7 @@ namespace api
199199

200200
DecoderFacadeBuilder &DecoderFacadeBuilder::withImageSplit(std::string split)
201201
{
202-
options->imageSplit = std::make_optional(split);
202+
options->imageSplitting = std::make_optional(split);
203203
return *this;
204204
}
205205

@@ -316,9 +316,12 @@ namespace api
316316
}
317317

318318
template <typename T>
319-
void DecoderFacade::decodeImage(input::api::InputElement inputElement, std::function<void(T &&, std::string)> transformer)
319+
void DecoderFacade::decodeImage(
320+
input::api::InputElement inputElement,
321+
std::optional<dip::PreProcessorOptions> preProcessorOptions,
322+
std::function<void(T &&, std::string)> transformer)
320323
{
321-
auto source = internal->preProcessor.get(std::move(inputElement));
324+
auto source = internal->preProcessor.get(std::move(inputElement), preProcessorOptions);
322325
options.visitPreProcessorResult(source);
323326
if (!source.isValid())
324327
{
@@ -345,10 +348,13 @@ namespace api
345348
}
346349

347350
template <typename T>
348-
void DecoderFacade::decodeImageFiles(std::filesystem::path path, std::function<void(T &&, std::string)> transformer)
351+
void DecoderFacade::decodeImageFiles(
352+
std::filesystem::path path,
353+
std::optional<dip::PreProcessorOptions> preProcessorOptions,
354+
std::function<void(T &&, std::string)> transformer)
349355
{
350356
auto loadHandler = [&, this](auto &&inputElement)
351-
{ decodeImage(std::move(inputElement), transformer); };
357+
{ decodeImage(std::move(inputElement), preProcessorOptions, transformer); };
352358

353359
if (options.getAsynchronousLoad())
354360
{
@@ -463,34 +469,40 @@ namespace api
463469
return decodeRawBytesToJson(utility::base64::decode(base64RawData), origin);
464470
}
465471

466-
std::vector<std::pair<std::string, std::string>> DecoderFacade::decodeImageFilesToJson(std::filesystem::path path)
472+
std::vector<std::pair<std::string, std::string>> DecoderFacade::decodeImageFilesToJson(
473+
std::filesystem::path path,
474+
std::optional<dip::PreProcessorOptions> preProcessorOptions)
467475
{
468476
auto result = std::vector<std::pair<std::string, std::string>>{};
469-
decodeImageFiles<decoder::api::Result>(path, [&](auto &&decoderResult, auto origin)
477+
decodeImageFiles<decoder::api::Result>(path, preProcessorOptions, [&](auto &&decoderResult, auto origin)
470478
{ result.emplace_back(std::make_pair(std::move(origin), interpretRawBytes(std::move(decoderResult.payload), origin))); });
471479
return result;
472480
}
473481

474-
std::vector<std::pair<std::string, std::vector<std::uint8_t>>> DecoderFacade::decodeImageFilesToRawBytes(std::filesystem::path path)
482+
std::vector<std::pair<std::string, std::vector<std::uint8_t>>> DecoderFacade::decodeImageFilesToRawBytes(
483+
std::filesystem::path path,
484+
std::optional<dip::PreProcessorOptions> preProcessorOptions)
475485
{
476486
auto result = std::vector<std::pair<std::string, std::vector<std::uint8_t>>>{};
477-
decodeImageFiles<decoder::api::Result>(path, [&](auto &&decoderResult, auto origin)
487+
decodeImageFiles<decoder::api::Result>(path, preProcessorOptions, [&](auto &&decoderResult, auto origin)
478488
{ result.emplace_back(std::make_pair(std::move(origin), std::move(decoderResult.payload))); });
479489
return result;
480490
}
481491

482-
std::vector<std::pair<std::string, std::string>> DecoderFacade::decodeImageFilesToRawBase64(std::filesystem::path path)
492+
std::vector<std::pair<std::string, std::string>> DecoderFacade::decodeImageFilesToRawBase64(
493+
std::filesystem::path path,
494+
std::optional<dip::PreProcessorOptions> preProcessorOptions)
483495
{
484496
auto result = std::vector<std::pair<std::string, std::string>>{};
485-
decodeImageFiles<decoder::api::Result>(path, [&](auto &&decoderResult, auto origin)
497+
decodeImageFiles<decoder::api::Result>(path, preProcessorOptions, [&](auto &&decoderResult, auto origin)
486498
{ result.emplace_back(std::make_pair(origin, toMinimalJson(origin, decoderResult.payload, options.getJsonIndent()))); });
487499
return result;
488500
}
489501

490502
std::vector<std::string> DecoderFacade::decodeImageToJson(input::api::InputElement inputElement)
491503
{
492504
auto result = std::vector<std::string>{};
493-
decodeImage<decoder::api::Result>(std::move(inputElement), [&](auto &&decoderResult, auto origin)
505+
decodeImage<decoder::api::Result>(std::move(inputElement), std::nullopt, [&](auto &&decoderResult, auto origin)
494506
{ result.emplace_back(interpretRawBytes(std::move(decoderResult.payload), origin)); });
495507
return result;
496508
}

source/lib/dip/include/PreProcessor.h

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
#pragma once
55

6+
#include "PreProcessorOptions.h"
7+
68
#include "lib/input/api/include/InputElement.h"
79

810
#include "lib/infrastructure/include/ParameterSupplier.h"
@@ -12,19 +14,10 @@
1214
#include <opencv2/core.hpp>
1315

1416
#include <map>
17+
#include <optional>
1518

1619
namespace dip
1720
{
18-
struct PreProcessorOptions
19-
{
20-
int rotationDegree = 0;
21-
unsigned int scalePercent = 100u;
22-
std::string split = "11";
23-
unsigned int flippingMode = 0; // 0 nothing, 1 flip around X, 2 flip around Y, 3 flip around X and Y
24-
25-
static PreProcessorOptions const DEFAULT;
26-
};
27-
2821
std::pair<unsigned int, unsigned int> splitStringToPair(std::string input);
2922

3023
std::map<unsigned int, unsigned int> splitPairToMap(std::pair<unsigned int, unsigned int> input);
@@ -39,8 +32,6 @@ namespace dip
3932

4033
PreProcessor(infrastructure::Context &context, PreProcessorOptions options);
4134

42-
void updatePartMap();
43-
4435
public:
4536
void enable(bool enabled);
4637

@@ -60,7 +51,7 @@ namespace dip
6051

6152
std::string reset();
6253

63-
input::api::InputElement get(input::api::InputElement &&element) const;
54+
input::api::InputElement get(input::api::InputElement &&element, std::optional<dip::PreProcessorOptions> options = std::nullopt) const;
6455

6556
ParameterTypeList supplyParameters() const;
6657

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// SPDX-FileCopyrightText: (C) 2026 user4223 and (other) contributors to ticket-decoder <https://github.com/user4223/ticket-decoder>
2+
// SPDX-License-Identifier: GPL-3.0-or-later
3+
4+
#pragma once
5+
6+
#include <string>
7+
8+
namespace dip
9+
{
10+
class OptionsBuilder;
11+
12+
struct PreProcessorOptions
13+
{
14+
int rotationDegree = 0;
15+
unsigned int scalePercent = 100u;
16+
std::string splittingMode = "11"; // 11 first of one part, 2x x of two parts, 4x x of four parts
17+
unsigned int flippingMode = 0; // 0 nothing, 1 flip around X, 2 flip around Y, 3 flip around X and Y
18+
19+
static PreProcessorOptions const DEFAULT;
20+
21+
OptionsBuilder create();
22+
};
23+
24+
class OptionsBuilder
25+
{
26+
PreProcessorOptions options;
27+
28+
OptionsBuilder(PreProcessorOptions o);
29+
30+
public:
31+
friend PreProcessorOptions;
32+
33+
PreProcessorOptions build();
34+
};
35+
}

source/lib/dip/source/PreProcessor.cpp

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111

1212
namespace dip
1313
{
14-
PreProcessorOptions const PreProcessorOptions::DEFAULT = PreProcessorOptions{};
15-
1614
std::pair<unsigned int, unsigned int> splitStringToPair(std::string input)
1715
{
1816
if (input.size() != 2)
@@ -65,21 +63,20 @@ namespace dip
6563
return result;
6664
}
6765

66+
std::tuple<unsigned int, unsigned int> updatePartMap(std::map<unsigned int, unsigned int> const &partMap)
67+
{
68+
return *std::max_element(partMap.begin(), partMap.end(),
69+
[](auto const &a, auto const &b)
70+
{ return (std::min(1u, a.second) * a.first) < (std::min(1u, b.second) * b.first); });
71+
}
72+
6873
PreProcessor::PreProcessor(infrastructure::Context &context, PreProcessorOptions o)
6974
: logger(CREATE_LOGGER(context.getLoggerFactory())),
7075
options(std::move(o)),
7176
isEnabled(true),
72-
partMap(splitPairToMap(splitStringToPair(options.split))),
73-
parts()
74-
{
75-
updatePartMap();
76-
}
77-
78-
void PreProcessor::updatePartMap()
77+
partMap(splitPairToMap(splitStringToPair(options.splittingMode))),
78+
parts(updatePartMap(partMap))
7979
{
80-
parts = *std::max_element(partMap.begin(), partMap.end(),
81-
[](auto const &a, auto const &b)
82-
{ return (std::min(1u, a.second) * a.first) < (std::min(1u, b.second) * b.first); });
8380
}
8481

8582
void PreProcessor::enable(bool e)
@@ -101,14 +98,14 @@ namespace dip
10198
std::string PreProcessor::toggleSplit2()
10299
{
103100
::utility::rotate(partMap.at(2), 2);
104-
updatePartMap();
101+
parts = updatePartMap(partMap);
105102
return std::to_string(std::get<0>(parts)) + "/" + std::to_string(std::get<1>(parts));
106103
}
107104

108105
std::string PreProcessor::toggleSplit4()
109106
{
110107
::utility::rotate(partMap.at(4), 4);
111-
updatePartMap();
108+
parts = updatePartMap(partMap);
112109
return std::to_string(std::get<0>(parts)) + "/" + std::to_string(std::get<1>(parts));
113110
}
114111

@@ -130,29 +127,36 @@ namespace dip
130127
std::string PreProcessor::reset()
131128
{
132129
auto const defaultOptions = PreProcessorOptions{};
133-
partMap = splitPairToMap(splitStringToPair(defaultOptions.split));
130+
partMap = splitPairToMap(splitStringToPair(defaultOptions.splittingMode));
131+
parts = updatePartMap(partMap);
134132
options.rotationDegree = defaultOptions.rotationDegree;
135133
options.scalePercent = defaultOptions.scalePercent;
136134
options.flippingMode = defaultOptions.flippingMode;
137-
updatePartMap();
138135
return "";
139136
}
140137

141-
input::api::InputElement PreProcessor::get(input::api::InputElement &&element) const
138+
input::api::InputElement PreProcessor::get(input::api::InputElement &&element, std::optional<dip::PreProcessorOptions> tempOptions) const
142139
{
143140
if (!isEnabled || !element.isValid())
144141
{
145142
return std::move(element);
146143
}
147144

145+
auto const effectiveOptions = tempOptions.value_or(this->options);
146+
auto effectiveParts = std::tuple<unsigned int, unsigned int>(parts);
147+
if (tempOptions)
148+
{
149+
effectiveParts = updatePartMap(splitPairToMap(splitStringToPair(tempOptions->splittingMode)));
150+
}
151+
148152
auto image = element.getImage();
149-
if (std::get<1>(parts) != 0)
153+
if (std::get<1>(effectiveParts) != 0)
150154
{
151-
image = dip::split(image, std::get<0>(parts), std::get<1>(parts));
155+
image = dip::split(image, std::get<0>(effectiveParts), std::get<1>(effectiveParts));
152156
}
153-
if (options.flippingMode != 0)
157+
if (effectiveOptions.flippingMode != 0)
154158
{
155-
switch (options.flippingMode)
159+
switch (effectiveOptions.flippingMode)
156160
{
157161
case 1:
158162
image = dip::flipX(image);
@@ -165,13 +169,13 @@ namespace dip
165169
break;
166170
}
167171
}
168-
if (options.rotationDegree != 0)
172+
if (effectiveOptions.rotationDegree != 0)
169173
{
170-
image = dip::rotate(image, (float)options.rotationDegree);
174+
image = dip::rotate(image, (float)effectiveOptions.rotationDegree);
171175
}
172-
if (options.scalePercent != 100)
176+
if (effectiveOptions.scalePercent != 100)
173177
{
174-
image = dip::scale(image, options.scalePercent * 0.01f);
178+
image = dip::scale(image, effectiveOptions.scalePercent * 0.01f);
175179
}
176180

177181
return std::move(element.replaceImage(std::move(image)));

0 commit comments

Comments
 (0)