contrek 1.4.1 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +3 -0
- data/Gemfile.lock +4 -1
- data/README.md +207 -36
- data/contrek.gemspec +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/ContrekApi.h +2 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/Tests.cpp +53 -144
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RawBitmap.cpp +14 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/RawBitmap.h +1 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/AsciiSource.cpp +69 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/AsciiSource.h +34 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/PngSource.cpp +108 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/PngSource.h +40 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/RasterSource.h +22 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/bitmaps/streaming/RasterStreamer.h +92 -0
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/FinderUtils.cpp +6 -8
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.cpp +7 -2
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/PolygonFinder.h +3 -1
- data/ext/cpp_polygon_finder/PolygonFinder/src/polygon/finder/concurrent/Finder.cpp +6 -0
- data/ext/cpp_polygon_finder/cpp_polygon_finder.cpp +46 -0
- data/lib/contrek/bitmaps/bitmap.rb +2 -2
- data/lib/contrek/bitmaps/chunky_bitmap.rb +23 -8
- data/lib/contrek/bitmaps/png_bitmap.rb +4 -0
- data/lib/contrek/bitmaps/rgba_bitmap.rb +50 -0
- data/lib/contrek/bitmaps/streaming/raster_streamer.rb +66 -0
- data/lib/contrek/bitmaps/streaming/sources/ascii.rb +33 -0
- data/lib/contrek/bitmaps/streaming/sources/base.rb +27 -0
- data/lib/contrek/bitmaps/streaming/sources/png.rb +105 -0
- data/lib/contrek/finder/concurrent/finder.rb +3 -2
- data/lib/contrek/finder/polygon_finder.rb +6 -3
- data/lib/contrek/version.rb +1 -1
- data/lib/contrek.rb +5 -0
- metadata +26 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* AsciiSource.cpp
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025-2026 Emanuele Cesaroni
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the GNU Affero General Public License v3 (AGPLv3).
|
|
7
|
+
* See the LICENSE file in this directory for the full license text.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include "AsciiSource.h"
|
|
11
|
+
#include <cstring>
|
|
12
|
+
#include <stdexcept>
|
|
13
|
+
|
|
14
|
+
AsciiSource::AsciiSource(Bitmap& bitmap)
|
|
15
|
+
: bitmap_(bitmap),
|
|
16
|
+
current_row_(0) {
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
uint32_t AsciiSource::width() const {
|
|
20
|
+
return static_cast<uint32_t>(
|
|
21
|
+
bitmap_.w()
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
uint32_t AsciiSource::height() const {
|
|
26
|
+
return static_cast<uint32_t>(
|
|
27
|
+
bitmap_.h()
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
uint32_t AsciiSource::get_bytes_per_pixel() const {
|
|
32
|
+
return static_cast<uint32_t>(
|
|
33
|
+
bitmap_.get_bytes_per_pixel()
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
bool AsciiSource::read_next_row(
|
|
38
|
+
unsigned char* destination,
|
|
39
|
+
std::size_t row_size
|
|
40
|
+
) {
|
|
41
|
+
if (current_row_ >= height()) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const unsigned char* row =
|
|
46
|
+
bitmap_.get_row_ptr(current_row_);
|
|
47
|
+
|
|
48
|
+
const std::size_t expected_row_size =
|
|
49
|
+
static_cast<std::size_t>(width()) *
|
|
50
|
+
static_cast<std::size_t>(
|
|
51
|
+
get_bytes_per_pixel()
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
if (expected_row_size != row_size) {
|
|
55
|
+
throw std::runtime_error(
|
|
56
|
+
"Invalid row size"
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
std::memcpy(
|
|
61
|
+
destination,
|
|
62
|
+
row,
|
|
63
|
+
row_size
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
++current_row_;
|
|
67
|
+
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* AsciiSource.h
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025-2026 Emanuele Cesaroni
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the GNU Affero General Public License v3 (AGPLv3).
|
|
7
|
+
* See the LICENSE file in this directory for the full license text.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
|
|
12
|
+
#include <cstddef>
|
|
13
|
+
#include <cstdint>
|
|
14
|
+
|
|
15
|
+
#include "RasterSource.h"
|
|
16
|
+
#include "../Bitmap.h"
|
|
17
|
+
|
|
18
|
+
class AsciiSource : public RasterSource {
|
|
19
|
+
public:
|
|
20
|
+
explicit AsciiSource(Bitmap& bitmap);
|
|
21
|
+
|
|
22
|
+
uint32_t width() const override;
|
|
23
|
+
uint32_t height() const override;
|
|
24
|
+
uint32_t get_bytes_per_pixel() const override;
|
|
25
|
+
|
|
26
|
+
bool read_next_row(
|
|
27
|
+
unsigned char* destination,
|
|
28
|
+
std::size_t row_size
|
|
29
|
+
) override;
|
|
30
|
+
|
|
31
|
+
private:
|
|
32
|
+
Bitmap& bitmap_;
|
|
33
|
+
uint32_t current_row_;
|
|
34
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* PngSource.cpp
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025-2026 Emanuele Cesaroni
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the GNU Affero General Public License v3 (AGPLv3).
|
|
7
|
+
* See the LICENSE file in this directory for the full license text.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#include "PngSource.h"
|
|
11
|
+
|
|
12
|
+
#include <stdexcept>
|
|
13
|
+
#include <string>
|
|
14
|
+
|
|
15
|
+
PngSource::PngSource(const std::string& filepath)
|
|
16
|
+
: fp_(nullptr),
|
|
17
|
+
ctx_(nullptr),
|
|
18
|
+
width_(0),
|
|
19
|
+
height_(0),
|
|
20
|
+
current_row_(0) {
|
|
21
|
+
fp_ = std::fopen(filepath.c_str(),"rb");
|
|
22
|
+
if (!fp_) {
|
|
23
|
+
throw std::runtime_error("Unable to open PNG file");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
ctx_ = spng_ctx_new(0);
|
|
27
|
+
if (!ctx_) {
|
|
28
|
+
std::fclose(fp_);
|
|
29
|
+
fp_ = nullptr;
|
|
30
|
+
throw std::runtime_error("Unable to create spng context");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
int ret = spng_set_png_file(ctx_,fp_);
|
|
34
|
+
if (ret != 0) {
|
|
35
|
+
spng_ctx_free(ctx_);
|
|
36
|
+
ctx_ = nullptr;
|
|
37
|
+
std::fclose(fp_);
|
|
38
|
+
fp_ = nullptr;
|
|
39
|
+
throw std::runtime_error(std::string("spng_set_png_file failed: ") + spng_strerror(ret));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
spng_ihdr ihdr{};
|
|
43
|
+
ret = spng_get_ihdr(ctx_, &ihdr);
|
|
44
|
+
|
|
45
|
+
if (ret != 0) {
|
|
46
|
+
spng_ctx_free(ctx_);
|
|
47
|
+
ctx_ = nullptr;
|
|
48
|
+
std::fclose(fp_);
|
|
49
|
+
fp_ = nullptr;
|
|
50
|
+
throw std::runtime_error(std::string("spng_get_ihdr failed: ") + spng_strerror(ret));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
width_ = static_cast<uint32_t>(ihdr.width);
|
|
54
|
+
height_ = static_cast<uint32_t>(ihdr.height);
|
|
55
|
+
ret = spng_decode_image(
|
|
56
|
+
ctx_,
|
|
57
|
+
nullptr,
|
|
58
|
+
0,
|
|
59
|
+
SPNG_FMT_RGBA8,
|
|
60
|
+
SPNG_DECODE_PROGRESSIVE
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
if (ret != 0) {
|
|
64
|
+
spng_ctx_free(ctx_);
|
|
65
|
+
ctx_ = nullptr;
|
|
66
|
+
std::fclose(fp_);
|
|
67
|
+
fp_ = nullptr;
|
|
68
|
+
throw std::runtime_error(std::string("spng_decode_image failed: ") + spng_strerror(ret));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
PngSource::~PngSource()
|
|
73
|
+
{ if (ctx_) {
|
|
74
|
+
spng_ctx_free(ctx_);
|
|
75
|
+
}
|
|
76
|
+
if (fp_) {
|
|
77
|
+
std::fclose(fp_);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
uint32_t PngSource::width() const {
|
|
82
|
+
return width_;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
uint32_t PngSource::height() const {
|
|
86
|
+
return height_;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
uint32_t PngSource::get_bytes_per_pixel() const {
|
|
90
|
+
return 4;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
bool PngSource::read_next_row(unsigned char* destination, std::size_t row_size) {
|
|
94
|
+
if (current_row_ >= height_) {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
const std::size_t expected_row_size = static_cast<std::size_t>(width_) * 4;
|
|
98
|
+
if (row_size != expected_row_size) {
|
|
99
|
+
throw std::runtime_error("Invalid row size");
|
|
100
|
+
}
|
|
101
|
+
const int ret = spng_decode_row(ctx_,destination,row_size);
|
|
102
|
+
|
|
103
|
+
if (ret != 0 && ret != SPNG_EOI) {
|
|
104
|
+
throw std::runtime_error(std::string("spng_decode_row failed: ") + spng_strerror(ret));
|
|
105
|
+
}
|
|
106
|
+
++current_row_;
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* PngSource.h
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025-2026 Emanuele Cesaroni
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the GNU Affero General Public License v3 (AGPLv3).
|
|
7
|
+
* See the LICENSE file in this directory for the full license text.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
|
|
12
|
+
#include <cstddef>
|
|
13
|
+
#include <cstdint>
|
|
14
|
+
#include <cstdio>
|
|
15
|
+
#include <string>
|
|
16
|
+
|
|
17
|
+
extern "C" {
|
|
18
|
+
#include "../spng.h"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
#include "RasterSource.h"
|
|
22
|
+
|
|
23
|
+
class PngSource : public RasterSource {
|
|
24
|
+
public:
|
|
25
|
+
explicit PngSource(const std::string& filepath);
|
|
26
|
+
~PngSource() override;
|
|
27
|
+
|
|
28
|
+
uint32_t width() const override;
|
|
29
|
+
uint32_t height() const override;
|
|
30
|
+
uint32_t get_bytes_per_pixel() const override;
|
|
31
|
+
bool read_next_row(unsigned char* destination, std::size_t row_size) override;
|
|
32
|
+
|
|
33
|
+
private:
|
|
34
|
+
FILE* fp_;
|
|
35
|
+
spng_ctx* ctx_;
|
|
36
|
+
|
|
37
|
+
uint32_t width_;
|
|
38
|
+
uint32_t height_;
|
|
39
|
+
uint32_t current_row_;
|
|
40
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* RasterSource.cpp
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025-2026 Emanuele Cesaroni
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the GNU Affero General Public License v3 (AGPLv3).
|
|
7
|
+
* See the LICENSE file in this directory for the full license text.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
|
|
12
|
+
#include <cstddef>
|
|
13
|
+
#include <cstdint>
|
|
14
|
+
|
|
15
|
+
class RasterSource {
|
|
16
|
+
public:
|
|
17
|
+
virtual ~RasterSource() = default;
|
|
18
|
+
virtual uint32_t width() const = 0;
|
|
19
|
+
virtual uint32_t height() const = 0;
|
|
20
|
+
virtual uint32_t get_bytes_per_pixel() const = 0;
|
|
21
|
+
virtual bool read_next_row(unsigned char* destination, std::size_t row_size) = 0;
|
|
22
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* RasterStreamer.h
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025-2026 Emanuele Cesaroni
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the GNU Affero General Public License v3 (AGPLv3).
|
|
7
|
+
* See the LICENSE file in this directory for the full license text.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
#pragma once
|
|
11
|
+
|
|
12
|
+
#include <algorithm>
|
|
13
|
+
#include <cstddef>
|
|
14
|
+
#include <cstdint>
|
|
15
|
+
#include <cstring>
|
|
16
|
+
#include <stdexcept>
|
|
17
|
+
#include <utility>
|
|
18
|
+
#include <vector>
|
|
19
|
+
|
|
20
|
+
#include "RasterSource.h"
|
|
21
|
+
#include "../RawBitmap.h"
|
|
22
|
+
|
|
23
|
+
class RasterStreamer {
|
|
24
|
+
public:
|
|
25
|
+
static constexpr uint32_t OVERLAP = 1;
|
|
26
|
+
|
|
27
|
+
RasterStreamer(RasterSource& source, uint32_t stripe_height)
|
|
28
|
+
: source_(source),
|
|
29
|
+
stripe_height_(stripe_height) {
|
|
30
|
+
if (stripe_height_ <= OVERLAP) {
|
|
31
|
+
throw std::invalid_argument("stripe_height must be greater than 1");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
uint32_t stripe_height() const { return stripe_height_; }
|
|
35
|
+
|
|
36
|
+
template <typename Callback>
|
|
37
|
+
void each(Bitmap& buffer, Callback&& callback)
|
|
38
|
+
{ const uint32_t width = source_.width();
|
|
39
|
+
const uint32_t height = source_.height();
|
|
40
|
+
const uint32_t bytes_per_pixel = source_.get_bytes_per_pixel();
|
|
41
|
+
const std::size_t row_size = static_cast<std::size_t>(width) * static_cast<std::size_t>(bytes_per_pixel);
|
|
42
|
+
uint32_t source_row = 0;
|
|
43
|
+
uint32_t previous_buffer_rows = 0;
|
|
44
|
+
bool first_stripe = true;
|
|
45
|
+
|
|
46
|
+
while (source_row < height) {
|
|
47
|
+
std::vector<unsigned char> overlap_row;
|
|
48
|
+
if (!first_stripe) {
|
|
49
|
+
overlap_row.resize(row_size);
|
|
50
|
+
const unsigned char* previous_last_row = buffer.get_row_ptr(previous_buffer_rows - 1);
|
|
51
|
+
std::memcpy(overlap_row.data(), previous_last_row, row_size);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const uint32_t overlap_rows = first_stripe ? 0 : OVERLAP;
|
|
55
|
+
const uint32_t available_rows = stripe_height_ - overlap_rows;
|
|
56
|
+
const uint32_t remaining_rows = height - source_row;
|
|
57
|
+
const uint32_t rows_to_read = std::min(available_rows, remaining_rows);
|
|
58
|
+
const uint32_t buffer_rows = overlap_rows + rows_to_read;
|
|
59
|
+
|
|
60
|
+
if (!first_stripe) {
|
|
61
|
+
unsigned char* first_row = const_cast<unsigned char*>(buffer.get_row_ptr(0));
|
|
62
|
+
std::memcpy(first_row, overlap_row.data(), row_size);
|
|
63
|
+
}
|
|
64
|
+
uint32_t rows_read = 0;
|
|
65
|
+
for (uint32_t i = 0; i < rows_to_read; ++i) {
|
|
66
|
+
const uint32_t buffer_y = overlap_rows + i;
|
|
67
|
+
unsigned char* destination = const_cast<unsigned char*>(buffer.get_row_ptr(buffer_y));
|
|
68
|
+
if (!source_.read_next_row(destination, row_size)) {
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
++source_row;
|
|
72
|
+
++rows_read;
|
|
73
|
+
}
|
|
74
|
+
if (rows_read == 0) {
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
const uint32_t actual_buffer_rows = overlap_rows + rows_read;
|
|
78
|
+
if (actual_buffer_rows != buffer_rows) {
|
|
79
|
+
throw std::runtime_error("Raster source ended before expected image height!");
|
|
80
|
+
}
|
|
81
|
+
const std::size_t buffer_size = static_cast<std::size_t>(buffer_rows) * row_size;
|
|
82
|
+
|
|
83
|
+
std::forward<Callback>(callback)(buffer, buffer_rows, buffer_size);
|
|
84
|
+
previous_buffer_rows = buffer_rows;
|
|
85
|
+
first_stripe = false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private:
|
|
90
|
+
RasterSource& source_;
|
|
91
|
+
uint32_t stripe_height_;
|
|
92
|
+
};
|
|
@@ -17,18 +17,17 @@ void FinderUtils::sanitize_options(pf_Options& options, const Options& incoming_
|
|
|
17
17
|
const Identifier versus = incoming_options.get<Identifier>("versus", options.versus == Node::A ? "a" : "o");
|
|
18
18
|
options.versus = versus == "a" ? Node::A : Node::O;
|
|
19
19
|
options.number_of_tiles = std::max(1, static_cast<int>(incoming_options.get<std::int64_t>(
|
|
20
|
-
"number_of_tiles",
|
|
21
|
-
options.number_of_tiles)));
|
|
20
|
+
"number_of_tiles", options.number_of_tiles)));
|
|
22
21
|
options.connectivity_offset = incoming_options.get<std::int64_t>(
|
|
23
|
-
"connectivity",
|
|
24
|
-
options.connectivity_offset == 1 ? 8 : 4) == 8;
|
|
22
|
+
"connectivity", options.connectivity_offset == 1 ? 8 : 4) == 8;
|
|
25
23
|
options.treemap = incoming_options.get<bool>("treemap", options.treemap);
|
|
26
24
|
options.named_sequences = incoming_options.get<bool>(
|
|
27
|
-
"named_sequences",
|
|
28
|
-
options.named_sequences);
|
|
25
|
+
"named_sequences", options.named_sequences);
|
|
29
26
|
options.bounds = incoming_options.get<bool>("bounds", options.bounds);
|
|
30
27
|
options.unsafe_mode = incoming_options.get<bool>("unsafe_mode", options.unsafe_mode);
|
|
31
28
|
options.deterministic = incoming_options.get<bool>("deterministic", options.deterministic);
|
|
29
|
+
options.processing_height = static_cast<int>(incoming_options.get<std::int64_t>(
|
|
30
|
+
"processing_height", options.processing_height));
|
|
32
31
|
|
|
33
32
|
if (const Options* compress = incoming_options.get_options("compress")) {
|
|
34
33
|
options.compress_uniq = compress->get<bool>("uniq", options.compress_uniq);
|
|
@@ -39,8 +38,7 @@ void FinderUtils::sanitize_options(pf_Options& options, const Options& incoming_
|
|
|
39
38
|
if (compress->contains("visvalingam_tolerance")) {
|
|
40
39
|
options.compress_visvalingam = true;
|
|
41
40
|
options.compress_visvalingam_tolerance = static_cast<float>(compress->get<double>(
|
|
42
|
-
"visvalingam_tolerance",
|
|
43
|
-
options.compress_visvalingam_tolerance));
|
|
41
|
+
"visvalingam_tolerance", options.compress_visvalingam_tolerance));
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
44
|
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#include <list>
|
|
12
12
|
#include <map>
|
|
13
13
|
#include <ctime>
|
|
14
|
+
#include <cmath>
|
|
14
15
|
#include <typeinfo>
|
|
15
16
|
#include <string>
|
|
16
17
|
#include <vector>
|
|
@@ -40,7 +41,11 @@ PolygonFinder::PolygonFinder(Bitmap *bitmap,
|
|
|
40
41
|
{ this->rgb_matcher = dynamic_cast<RGBMatcher*>(matcher);
|
|
41
42
|
FinderUtils::sanitize_options(this->options, options);
|
|
42
43
|
|
|
43
|
-
this->
|
|
44
|
+
this->processing_height = std::abs(this->options.processing_height == 0 ? source_bitmap->h() : this->options.processing_height);
|
|
45
|
+
if (this->processing_height > source_bitmap->h()) {
|
|
46
|
+
throw std::invalid_argument("Option processing_height must be less or equal than image height!");
|
|
47
|
+
}
|
|
48
|
+
this->node_cluster = new NodeCluster(this->processing_height, source_bitmap->w(), &this->options);
|
|
44
49
|
|
|
45
50
|
//= SCAN ==============//
|
|
46
51
|
cpu_timer.start();
|
|
@@ -106,7 +111,7 @@ ProcessResult* PolygonFinder::process_info() {
|
|
|
106
111
|
pr->benchmarks = std::move(this->reports);
|
|
107
112
|
pr->treemap = this->node_cluster->treemap;
|
|
108
113
|
pr->width = this->source_bitmap->w();
|
|
109
|
-
pr->height = this->
|
|
114
|
+
pr->height = this->processing_height;
|
|
110
115
|
pr->has_bounds = this->node_cluster->options->bounds;
|
|
111
116
|
pr->versus = this->options.versus;
|
|
112
117
|
pr->options = this->incoming_options_;
|
|
@@ -54,6 +54,7 @@ struct pf_Options {
|
|
|
54
54
|
bool unsafe_mode = false;
|
|
55
55
|
bool bounds = false;
|
|
56
56
|
bool deterministic = false;
|
|
57
|
+
int processing_height = 0;
|
|
57
58
|
int connectivity_offset = 0;
|
|
58
59
|
float compress_visvalingam_tolerance = 10.0;
|
|
59
60
|
int number_of_tiles = 1;
|
|
@@ -159,6 +160,7 @@ class PolygonFinder {
|
|
|
159
160
|
protected:
|
|
160
161
|
int start_x;
|
|
161
162
|
int end_x;
|
|
163
|
+
int processing_height;
|
|
162
164
|
Options incoming_options_;
|
|
163
165
|
|
|
164
166
|
private:
|
|
@@ -173,7 +175,7 @@ class PolygonFinder {
|
|
|
173
175
|
|
|
174
176
|
template <typename M, typename F>
|
|
175
177
|
void run_loop(M* specific_matcher, F&& fetch_color, int offset) {
|
|
176
|
-
int img_h = this->
|
|
178
|
+
int img_h = this->processing_height;
|
|
177
179
|
int bpp = this->source_bitmap->get_bytes_per_pixel();
|
|
178
180
|
|
|
179
181
|
for (int y = 0; y < img_h; y++) {
|
|
@@ -32,6 +32,9 @@ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, const Op
|
|
|
32
32
|
{ cpu_timer.start();
|
|
33
33
|
FinderUtils::sanitize_options(this->options_, options);
|
|
34
34
|
|
|
35
|
+
if (this->options_.processing_height != 0) {
|
|
36
|
+
this->height = std::abs(this->options_.processing_height);
|
|
37
|
+
}
|
|
35
38
|
double cw = static_cast<double>(this->maximum_width_) / this->options_.number_of_tiles;
|
|
36
39
|
if (cw < 1.0) {
|
|
37
40
|
throw std::runtime_error("One pixel tile width minimum!");
|
|
@@ -54,6 +57,9 @@ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, const Op
|
|
|
54
57
|
if (this->options_.treemap) {
|
|
55
58
|
base_arguments["treemap"] = true;
|
|
56
59
|
}
|
|
60
|
+
if (this->options_.processing_height != 0) {
|
|
61
|
+
base_arguments["processing_height"] = this->options_.processing_height;
|
|
62
|
+
}
|
|
57
63
|
|
|
58
64
|
CpuTimer t;
|
|
59
65
|
t.start();
|
|
@@ -37,6 +37,12 @@
|
|
|
37
37
|
#include "PolygonFinder/src/polygon/bitmaps/FastPngBitmap.cpp"
|
|
38
38
|
#include "PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.h"
|
|
39
39
|
#include "PolygonFinder/src/polygon/bitmaps/RemoteFastPngBitmap.cpp"
|
|
40
|
+
#include "PolygonFinder/src/polygon/bitmaps/streaming/RasterSource.h"
|
|
41
|
+
#include "PolygonFinder/src/polygon/bitmaps/streaming/AsciiSource.h"
|
|
42
|
+
#include "PolygonFinder/src/polygon/bitmaps/streaming/AsciiSource.cpp"
|
|
43
|
+
#include "PolygonFinder/src/polygon/bitmaps/streaming/PngSource.h"
|
|
44
|
+
#include "PolygonFinder/src/polygon/bitmaps/streaming/PngSource.cpp"
|
|
45
|
+
#include "PolygonFinder/src/polygon/bitmaps/streaming/RasterStreamer.h"
|
|
40
46
|
#include "PolygonFinder/src/polygon/matchers/Matcher.h"
|
|
41
47
|
#include "PolygonFinder/src/polygon/matchers/Matcher.cpp"
|
|
42
48
|
#include "PolygonFinder/src/polygon/matchers/ValueNotMatcher.h"
|
|
@@ -395,6 +401,7 @@ void Init_cpp_polygon_finder() {
|
|
|
395
401
|
.define_method("value_at", &Bitmap::value_at)
|
|
396
402
|
.define_method("w", &Bitmap::w)
|
|
397
403
|
.define_method("h", &Bitmap::h)
|
|
404
|
+
.define_method("get_bytes_per_pixel", &Bitmap::get_bytes_per_pixel)
|
|
398
405
|
.define_method("error", &Bitmap::error)
|
|
399
406
|
.define_method("clear", &Bitmap::clear)
|
|
400
407
|
.define_method("print", &Bitmap::print);
|
|
@@ -402,6 +409,7 @@ void Init_cpp_polygon_finder() {
|
|
|
402
409
|
Data_Type<RawBitmap> rb_cRawBitmap =
|
|
403
410
|
define_class<RawBitmap, Bitmap>("CPPRawBitMap")
|
|
404
411
|
.define_constructor(Constructor<RawBitmap>())
|
|
412
|
+
.define_constructor(Constructor<RawBitmap, uint, uint>())
|
|
405
413
|
.define_method("rgb_value_at", &RawBitmap::rgb_value_at)
|
|
406
414
|
.define_method("w", &RawBitmap::w)
|
|
407
415
|
.define_method("h", &RawBitmap::h)
|
|
@@ -430,6 +438,44 @@ void Init_cpp_polygon_finder() {
|
|
|
430
438
|
.define_method("error", &FastPngBitmap::error)
|
|
431
439
|
.define_method("print", &FastPngBitmap::print);
|
|
432
440
|
|
|
441
|
+
Data_Type<RasterSource> rb_cRasterSource =
|
|
442
|
+
define_class<RasterSource>("CPPRasterSource");
|
|
443
|
+
|
|
444
|
+
Data_Type<AsciiSource> rb_cAsciiSource =
|
|
445
|
+
define_class<AsciiSource, RasterSource>("CPPAsciiSource")
|
|
446
|
+
.define_constructor(Constructor<AsciiSource, Bitmap&>(),Arg("bitmap"))
|
|
447
|
+
.define_method("width",&AsciiSource::width)
|
|
448
|
+
.define_method("height",&AsciiSource::height)
|
|
449
|
+
.define_method("get_bytes_per_pixel",&AsciiSource::get_bytes_per_pixel);
|
|
450
|
+
|
|
451
|
+
Data_Type<PngSource> rb_cPngSource =
|
|
452
|
+
define_class<PngSource, RasterSource>("CPPPngSource")
|
|
453
|
+
.define_constructor(Constructor<PngSource, std::string>(),Arg("filepath"))
|
|
454
|
+
.define_method("width",&PngSource::width)
|
|
455
|
+
.define_method("height",&PngSource::height)
|
|
456
|
+
.define_method("get_bytes_per_pixel",&PngSource::get_bytes_per_pixel);
|
|
457
|
+
|
|
458
|
+
Data_Type<RasterStreamer> rb_cRasterStreamer =
|
|
459
|
+
define_class<RasterStreamer>("CPPRasterStreamer")
|
|
460
|
+
.define_constructor(Constructor<RasterStreamer, RasterSource&, uint32_t>(),Arg("source"),Arg("stripe_height"))
|
|
461
|
+
.define_method("stripe_height",&RasterStreamer::stripe_height)
|
|
462
|
+
.define_method("each",[](RasterStreamer& self, Bitmap& buffer) {
|
|
463
|
+
VALUE block = rb_block_proc();
|
|
464
|
+
self.each(
|
|
465
|
+
buffer,
|
|
466
|
+
[block](Bitmap& bitmap,uint32_t buffer_rows,std::size_t buffer_size) {
|
|
467
|
+
Rice::Data_Object<Bitmap> rb_bitmap(&bitmap);
|
|
468
|
+
Rice::Object(block).call(
|
|
469
|
+
"call",
|
|
470
|
+
rb_bitmap,
|
|
471
|
+
buffer_rows,
|
|
472
|
+
buffer_size
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
);
|
|
478
|
+
|
|
433
479
|
Data_Type<Matcher> rb_cMatcher =
|
|
434
480
|
define_class<Matcher>("CPPMatcher")
|
|
435
481
|
.define_constructor(Constructor<Matcher, char>())
|
|
@@ -5,7 +5,7 @@ module Contrek
|
|
|
5
5
|
class Bitmap
|
|
6
6
|
include Painting
|
|
7
7
|
|
|
8
|
-
def scan(start_x: 0, end_x: w)
|
|
8
|
+
def scan(start_x: 0, end_x: w, end_y: h)
|
|
9
9
|
x = start_x
|
|
10
10
|
y = 0
|
|
11
11
|
loop do
|
|
@@ -14,7 +14,7 @@ module Contrek
|
|
|
14
14
|
if x == end_x
|
|
15
15
|
x = start_x
|
|
16
16
|
y += 1
|
|
17
|
-
break if y ==
|
|
17
|
+
break if y == end_y
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
end
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "ffi"
|
|
4
|
+
|
|
3
5
|
module Contrek
|
|
4
6
|
module Bitmaps
|
|
5
7
|
class ChunkyBitmap < Bitmap
|
|
6
8
|
def initialize(data, mod)
|
|
7
|
-
@raw = data.dup
|
|
8
9
|
@module = mod
|
|
10
|
+
@height = data.bytesize / @module
|
|
11
|
+
@raw = FFI::MemoryPointer.new(:uint8, data.bytesize)
|
|
12
|
+
@raw.put_bytes(0, data)
|
|
9
13
|
end
|
|
10
14
|
|
|
11
15
|
def clear(val = "0")
|
|
12
|
-
@raw
|
|
16
|
+
@raw.put_bytes(0, val * @module * h)
|
|
13
17
|
end
|
|
14
18
|
|
|
15
19
|
def w
|
|
@@ -17,22 +21,30 @@ module Contrek
|
|
|
17
21
|
end
|
|
18
22
|
|
|
19
23
|
def h
|
|
20
|
-
@
|
|
24
|
+
@height
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def get_bytes_per_pixel
|
|
28
|
+
1
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def get_row_ptr(y)
|
|
32
|
+
@raw + (@module * y)
|
|
21
33
|
end
|
|
22
34
|
|
|
23
35
|
def value_at(x, y)
|
|
24
|
-
@raw
|
|
36
|
+
@raw.get_uint8(y * @module + x).chr
|
|
25
37
|
end
|
|
26
38
|
|
|
27
39
|
def value_set(x, y, value)
|
|
28
40
|
return if y >= h
|
|
29
41
|
return if x >= w
|
|
30
42
|
|
|
31
|
-
@raw
|
|
43
|
+
@raw.put_uint8(y * @module + x, value.ord)
|
|
32
44
|
end
|
|
33
45
|
|
|
34
46
|
def dup!
|
|
35
|
-
ChunkyBitmap.new(@raw, @module)
|
|
47
|
+
ChunkyBitmap.new(@raw.read_bytes(@module * h), @module)
|
|
36
48
|
end
|
|
37
49
|
|
|
38
50
|
def draw_rect(x:, y:, width:, height:, color: "o", filled: true)
|
|
@@ -80,7 +92,7 @@ module Contrek
|
|
|
80
92
|
puts label if label
|
|
81
93
|
puts " " + (0...@module).map { |i| (i % 10).to_s }.join
|
|
82
94
|
n = 0
|
|
83
|
-
@raw.scan(/.{1,#{@module}}/).each do |line|
|
|
95
|
+
@raw.read_bytes(@module * h).scan(/.{1,#{@module}}/).each do |line|
|
|
84
96
|
colored_line = line.chars.map { |c| colorize_char(c) }.join
|
|
85
97
|
puts "#{n} #{colored_line}"
|
|
86
98
|
n += 1
|
|
@@ -96,8 +108,11 @@ module Contrek
|
|
|
96
108
|
transposed += value_at(x, y)
|
|
97
109
|
end
|
|
98
110
|
end
|
|
99
|
-
|
|
111
|
+
old_width = w
|
|
100
112
|
@module = h
|
|
113
|
+
@height = old_width
|
|
114
|
+
@raw = FFI::MemoryPointer.new(:uint8, transposed.bytesize)
|
|
115
|
+
@raw.put_bytes(0, transposed)
|
|
101
116
|
end
|
|
102
117
|
|
|
103
118
|
private
|