contrek 1.2.6 → 1.2.7

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca0c4f7e37692b2d2e5b17556ed67bee4b624511ddf1dc3865ecf910e8f46aeb
4
- data.tar.gz: 66b9af71020dc6a86da1abace1d0467807b9212e207b71a7f6337b2257a34192
3
+ metadata.gz: ae46fa52ddce3383ef534142814ed28ddc5cae45042e677c8f445140bee67e82
4
+ data.tar.gz: 57cbaf53a0d6e8c7d31bdfcef0718c94654ceaf0fd7b2be84325751dc29f6224
5
5
  SHA512:
6
- metadata.gz: 63ba135c86c7849fda12e542af23a2746681f8aade888daa9269438c1601e8184215b3fe5081ee9caabce923e7dfafd8bcc3613fb06cf2ec9997193ff831e5c7
7
- data.tar.gz: dd691e542a8722be9532d3c0f206d4b2a2499874f0be52786c99822036d3e0e463ffb6d301bceae44e8f487f434eeff98c9a931cffe27eab3ed5d249daf060e5
6
+ metadata.gz: ee922b6b787ac0f91b98a2e7d608c351499ea5405e325a0eb6d23f751a29075b390c08d757824132c7fbef7d64cef9f3af7dbb11709506e84777ff652f9f15fc
7
+ data.tar.gz: 848102a6980857b1f4d3914e60de04408d0f7a4cc4c950a20b3fa8ef7231e31db029220eb6e3fb71847b6986a09c0d7b1fedae70f8e30e8ef758a3adeabeddcd
data/CHANGELOG.md CHANGED
@@ -112,3 +112,7 @@ All notable changes to this project will be documented in this file.
112
112
  - **Refactored `spng.c` function `rgb8_row_to_rgba8`:** Extended a loop counter to `size_t` (previously limited to `uint32_t`), which was causing segmentation faults when reading massive images (e.g., 81920x81920).
113
113
  - **Refactored `RawBitmap.define` function:** Updated area and size calculations to use full 64-bit integers.
114
114
  - **Refactored `PolygonFinder.to_svg_stream()` function:** Optimized performance to efficiently handle massive SVG streams of 2 GB and beyond.
115
+
116
+ ## [1.2.7] - 2026-06-02
117
+ ### Changed
118
+ - **Refactored `bounds` option:** Starting from this release, precalculated bounds for each polygon can now be requested in concurrent mode as well, in addition to single-threaded mode.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- contrek (1.2.6)
4
+ contrek (1.2.7)
5
5
  chunky_png (~> 1.4)
6
6
  concurrent-ruby (~> 1.3.5)
7
7
  rice (= 4.5.0)
data/README.md CHANGED
@@ -286,6 +286,18 @@ result.points
286
286
  For pure Ruby implementations (`{ native: false }`), coordinates are always expressed as points.
287
287
  In this case, both `polygons` and `points` return the same data, represented as hashes with `x` and `y` keys.
288
288
 
289
+ For each returned polygon, it is possible to get its bounding box. You just need to request it as an option (`bounds`), for example:
290
+ ```ruby
291
+ {named_sequences: true, bounds: true, compress: {uniq: true, linear: true}}
292
+ ```
293
+ Each entry will contain the precalculated bounds key:
294
+ ```ruby
295
+ [{:bounds=>{:min_x=>3, :max_x=>11, :min_y=>1, :max_y=>3},
296
+ :outer=>[{:x=>3, :y=>1}, {:x=>3, :y=>3}, {:x=>11, :y=>3}, {:x=>11, :y=>1}],
297
+ :inner=>[]}]
298
+ ```
299
+
300
+
289
301
  ## Metadata
290
302
 
291
303
  Metadata associated with the result can be accessed via:
@@ -108,12 +108,13 @@ void FinderUtils::sanitize_options(pf_Options& options, std::vector<std::string>
108
108
  break;
109
109
  }
110
110
  }
111
- /*std::cout << "-----------" << std::endl;
111
+ /* std::cout << "-----------" << std::endl;
112
112
  std::cout << "versus " << options.versus << std::endl;
113
+ std::cout << "bounds " << options.bounds << std::endl;
113
114
  std::cout << "number_of_tiles " << options.number_of_tiles << std::endl;
114
115
  std::cout << "uniq " << options.compress_uniq << std::endl;
115
116
  std::cout << "linear " << options.compress_linear << std::endl;
116
117
  std::cout << "visvalingam " << options.compress_visvalingam << std::endl;
117
- std::cout << options.compress_visvalingam_tolerance << std::endl;
118
- std::cout << "-----------" << std::endl;*/
118
+ std::cout << "visvalingam tolernace " << options.compress_visvalingam_tolerance << std::endl;
119
+ std::cout << "-----------" << std::endl; */
119
120
  }
@@ -107,6 +107,7 @@ ProcessResult* PolygonFinder::process_info() {
107
107
  pr->treemap = this->node_cluster->treemap;
108
108
  pr->width = this->source_bitmap->w();
109
109
  pr->height = this->source_bitmap->h();
110
+ pr->has_bounds = this->node_cluster->options->bounds;
110
111
 
111
112
  if (this->node_cluster->options->named_sequences && typeid(*this->source_bitmap) == typeid(Bitmap))
112
113
  { std::string sequence;
@@ -59,6 +59,7 @@ struct pf_Options {
59
59
  struct ProcessResult {
60
60
  int groups;
61
61
  int width, height;
62
+ bool has_bounds = false;
62
63
  std::map<std::string, double> benchmarks;
63
64
  std::list<Polygon> polygons;
64
65
  std::string named_sequence;
@@ -60,7 +60,7 @@ Finder::Finder(int number_of_threads, Bitmap *bitmap, Matcher *matcher, std::vec
60
60
  Tile* tile = new Tile(this, payload.tile_start_x, payload.tile_end_x,
61
61
  std::to_string(payload.tile_index), Benchmarks {0, 0});
62
62
  tile->initial_process(finder);
63
- tiles.queue_push(tile);
63
+ tiles_.queue_push(tile);
64
64
  });
65
65
 
66
66
  x = tile_end_x - 1;
@@ -79,7 +79,7 @@ void Finder::process_tiles() {
79
79
  std::vector<Tile*> arriving_tiles;
80
80
 
81
81
  while (true) {
82
- Tile* tile = tiles.queue_pop();
82
+ Tile* tile = tiles_.queue_pop();
83
83
 
84
84
  if (tile->whole()) {
85
85
  this->whole_tile = tile;
@@ -116,7 +116,7 @@ void Finder::process_tiles() {
116
116
  arriving_tiles.erase(it);
117
117
  enqueue(cluster, [this](Cluster* c) {
118
118
  Tile* merged_tile = c->merge_tiles();
119
- tiles.queue_push(merged_tile);
119
+ tiles_.queue_push(merged_tile);
120
120
  delete c;
121
121
  });
122
122
  } else {
@@ -146,6 +146,7 @@ ProcessResult* Finder::process_info() {
146
146
  pr->groups = pr->polygons.size();
147
147
  pr->width = this->maximum_width_;
148
148
  pr->height = this->height;
149
+ pr->has_bounds = this->options_.bounds;
149
150
  FakeCluster fake_cluster(pr->polygons, this->options_);
150
151
  cpu_timer.start();
151
152
  fake_cluster.compress_coords(pr->polygons, this->options_);
@@ -42,7 +42,7 @@ class Finder : public Poolable {
42
42
  CpuTimer cpu_timer;
43
43
 
44
44
  protected:
45
- Queue<Tile*> tiles;
45
+ Queue<Tile*> tiles_;
46
46
  int maximum_width_;
47
47
  int height = 0;
48
48
  void process_tiles();
@@ -55,4 +55,5 @@ class Finder : public Poolable {
55
55
  int maximum_width() const { return maximum_width_; }
56
56
  virtual ProcessResult* process_info();
57
57
  const pf_Options& options() const { return options_; }
58
+ Queue<Tile*>& tiles() { return tiles_; }
58
59
  };
@@ -21,9 +21,9 @@ void Merger::add_tile(ProcessResult& result)
21
21
  this->height = result.height;
22
22
  }
23
23
  int end_x = this->current_x + result.width;
24
- Tile* tile = new Tile(this, this->current_x, end_x, std::to_string(tiles.size()), Benchmarks {0, 0});
24
+ Tile* tile = new Tile(this, this->current_x, end_x, std::to_string(tiles_.size()), Benchmarks {0, 0});
25
25
  tile->assign_raw_polygons(result.polygons, result.treemap);
26
- tiles.queue_push(tile);
26
+ tiles_.queue_push(tile);
27
27
 
28
28
  this->maximum_width_ = end_x;
29
29
  this->current_x = end_x - 1;
@@ -95,3 +95,10 @@ std::string Polyline::named() {
95
95
  return this->named_;
96
96
  }
97
97
  }
98
+
99
+ void Polyline::fill_bounds(RectBounds& target_bounds) const {
100
+ target_bounds.min_x = this->min_x;
101
+ target_bounds.max_x = this->max_x;
102
+ target_bounds.min_y = this->min_y_;
103
+ target_bounds.max_y = this->max_y_;
104
+ }
@@ -52,6 +52,7 @@ class Polyline : public Partitionable {
52
52
  InnerPolyline* inside_inner_polyline = nullptr;
53
53
  std::string named();
54
54
  void set_named(std::string force_named) { this->named_ = force_named; }
55
+ void fill_bounds(RectBounds& target_bounds) const;
55
56
 
56
57
  private:
57
58
  std::vector<Point*> raw_;
@@ -107,10 +107,14 @@ std::string Tile::toString() {
107
107
 
108
108
  std::list<Polygon> Tile::to_raw_polygons()
109
109
  { std::list<Polygon> retme;
110
+ bool bounds = this->finder->options().bounds;
110
111
  for (Shape* s : shapes_)
111
112
  { if (s->outer_polyline && !s->outer_polyline->is_empty())
112
113
  { Polygon poly;
113
114
  poly.outer = s->outer_polyline->raw();
115
+ if (bounds) {
116
+ s->outer_polyline->fill_bounds(poly.bounds);
117
+ }
114
118
  if (!s->inner_polylines.empty()) {
115
119
  for (auto inner : s->inner_polylines) {
116
120
  poly.inner.push_back(inner->raw());
@@ -21,7 +21,7 @@ VerticalMerger::VerticalMerger(int number_of_threads, std::vector<std::string> *
21
21
 
22
22
  void VerticalMerger::add_tile(ProcessResult& result)
23
23
  { transpose(result);
24
- if (this->tiles.size() > 0) {
24
+ if (this->tiles_.size() > 0) {
25
25
  translate(result, this->current_x);
26
26
  }
27
27
  adjust(result);
@@ -172,6 +172,7 @@ class To_Ruby<ProcessResult*>
172
172
  }
173
173
  RubyResult* rr = new RubyResult();
174
174
  Rice::Data_Object<RubyResult> rb_result(rr);
175
+ bool inject_bounds = pr->has_bounds;
175
176
 
176
177
  Rice::Hash return_me = Rice::Hash();
177
178
  Rice::Hash benchmarks_rb;
@@ -206,12 +207,14 @@ class To_Ruby<ProcessResult*>
206
207
  }
207
208
  poly_hash[Symbol("inner")] = inner_collection;
208
209
  // BOUNDS
209
- Rice::Hash bounds_hash = Rice::Hash();
210
- bounds_hash[Symbol("min_x")] = x.bounds.min_x;
211
- bounds_hash[Symbol("max_x")] = x.bounds.max_x;
212
- bounds_hash[Symbol("min_y")] = x.bounds.min_y;
213
- bounds_hash[Symbol("max_y")] = x.bounds.max_y;
214
- poly_hash[Symbol("bounds")] = bounds_hash;
210
+ if (inject_bounds) {
211
+ Rice::Hash bounds_hash = Rice::Hash();
212
+ bounds_hash[Symbol("min_x")] = x.bounds.min_x;
213
+ bounds_hash[Symbol("max_x")] = x.bounds.max_x;
214
+ bounds_hash[Symbol("min_y")] = x.bounds.min_y;
215
+ bounds_hash[Symbol("max_y")] = x.bounds.max_y;
216
+ poly_hash[Symbol("bounds")] = bounds_hash;
217
+ }
215
218
 
216
219
  out.push(poly_hash);
217
220
  }
@@ -19,8 +19,9 @@ module Contrek
19
19
  def points
20
20
  raw_list = polygons.to_a
21
21
  @to_points ||= raw_list.map do |polygon|
22
- {outer: self.class.to_points(polygon[:outer]),
23
- inner: polygon[:inner].map { |s| self.class.to_points(s) }}
22
+ {bounds: (polygon[:bounds] if polygon.key?(:bounds)),
23
+ outer: self.class.to_points(polygon[:outer]),
24
+ inner: polygon[:inner].map { |s| self.class.to_points(s) }}.compact
24
25
  end
25
26
  end
26
27
 
@@ -54,8 +54,9 @@ module Contrek
54
54
  def to_raw_polygons
55
55
  @shapes.filter_map do |shape|
56
56
  unless shape.outer_polyline.empty?
57
- {outer: shape.outer_polyline.raw,
58
- inner: shape.inner_polylines.map(&:raw)}
57
+ {bounds: (shape.outer_polyline.get_bounds if @finder.options[:bounds]),
58
+ outer: shape.outer_polyline.raw,
59
+ inner: shape.inner_polylines.map(&:raw)}.compact
59
60
  end
60
61
  end
61
62
  end
@@ -1,3 +1,3 @@
1
1
  module Contrek
2
- VERSION = "1.2.6"
2
+ VERSION = "1.2.7"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contrek
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.6
4
+ version: 1.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emanuele Cesaroni
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-05-31 00:00:00.000000000 Z
11
+ date: 2026-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec