contrek 1.2.5 → 1.2.6

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: 32d1d662c0c6c0c1dc6ffcde36090b188e7d3abd39fc5dd7ba0887aa62526b27
4
- data.tar.gz: df8b75836abf466043587f22995f12e13c3ed908b60a4fcda97216e803458540
3
+ metadata.gz: ca0c4f7e37692b2d2e5b17556ed67bee4b624511ddf1dc3865ecf910e8f46aeb
4
+ data.tar.gz: 66b9af71020dc6a86da1abace1d0467807b9212e207b71a7f6337b2257a34192
5
5
  SHA512:
6
- metadata.gz: 33c9e4906109bcd7cee694401b3946b0fe2e5800c551bc20a4ea428bdb7cbe7eb456a2e7cadd57327ca93bf65491284e4566b2caaa9e0ea28a5c771c8e50510b
7
- data.tar.gz: ede6984f06ebef2b9672e1f1c0569428b25332e9bb14249a8341fdc1e4f11c493a066015a496bd9d19baec57a97bf98d4d99d23262a4a7dac93757c129e8c441
6
+ metadata.gz: 63ba135c86c7849fda12e542af23a2746681f8aade888daa9269438c1601e8184215b3fe5081ee9caabce923e7dfafd8bcc3613fb06cf2ec9997193ff831e5c7
7
+ data.tar.gz: dd691e542a8722be9532d3c0f206d4b2a2499874f0be52786c99822036d3e0e463ffb6d301bceae44e8f487f434eeff98c9a931cffe27eab3ed5d249daf060e5
data/CHANGELOG.md CHANGED
@@ -106,3 +106,9 @@ All notable changes to this project will be documented in this file.
106
106
  ## [1.2.5] - 2026-05-27
107
107
  ### Changed
108
108
  - **Refactored `ProcessResult.clone()`:** Switched from fragmented dynamic allocation to a contiguous `std::vector` with explicit `.reserve()`. Eliminates heap fragmentation during high-res streaming.
109
+
110
+ ## [1.2.6] - 2026-05-31
111
+ ### Changed
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
+ - **Refactored `RawBitmap.define` function:** Updated area and size calculations to use full 64-bit integers.
114
+ - **Refactored `PolygonFinder.to_svg_stream()` function:** Optimized performance to efficiently handle massive SVG streams of 2 GB and beyond.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- contrek (1.2.4)
4
+ contrek (1.2.6)
5
5
  chunky_png (~> 1.4)
6
6
  concurrent-ruby (~> 1.3.5)
7
7
  rice (= 4.5.0)
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  #include "Tests.h"
11
+ #include <sys/resource.h>
11
12
  #include <string.h>
12
13
  #include <iostream>
13
14
  #include <list>
@@ -17,7 +18,6 @@
17
18
  #include <cstring>
18
19
  #include <algorithm>
19
20
  #include <cstdio>
20
- #include <sys/resource.h>
21
21
 
22
22
  #include "polygon/finder/PolygonFinder.h"
23
23
  #include "polygon/finder/concurrent/ClippedPolygonFinder.h"
@@ -279,7 +279,7 @@ double get_peak_rss() {
279
279
  This approach allows for processing large PNG files on systems where memory
280
280
  would otherwise be insufficient.
281
281
  */
282
- void stream_png_image(const std::string& filepath, uint32_t stripe_height) {
282
+ void stream_png_image(const std::string& filepath, uint32_t stripe_height, bool generate_svg = false, bool generate_png = false) {
283
283
  std::vector<ProcessResult*> result_clones;
284
284
  std::vector<std::string> varguments = {};
285
285
  VerticalMerger vmerger(0, &varguments);
@@ -305,6 +305,7 @@ void stream_png_image(const std::string& filepath, uint32_t stripe_height) {
305
305
 
306
306
  // allocates stripe buffer
307
307
  RawBitmap stripe_bitmap;
308
+ std::cout << total_width << " " << stripe_height << std::endl;
308
309
  stripe_bitmap.define(total_width, stripe_height, 4, true);
309
310
  RGBNotMatcher not_matcher(-1);
310
311
 
@@ -315,6 +316,7 @@ void stream_png_image(const std::string& filepath, uint32_t stripe_height) {
315
316
  }
316
317
 
317
318
  size_t row_size = static_cast<size_t>(total_width) * 4;
319
+ int stripe_count = 0;
318
320
  // main stripes loop
319
321
  for (uint32_t current_y_offset = 0; current_y_offset < total_height; current_y_offset += stripe_height) {
320
322
  int uncovered_height = total_height - current_y_offset;
@@ -344,12 +346,13 @@ void stream_png_image(const std::string& filepath, uint32_t stripe_height) {
344
346
  PolygonFinder polygon_finder(&stripe_bitmap, &not_matcher, nullptr, &finder_arguments);
345
347
  ProcessResult *result = polygon_finder.process_info();
346
348
  if (result) {
347
- std::cout << "Founds polygons: " << result->groups << std::endl;
349
+ std::cout << "stripe " << stripe_count << ": found polygons " << result->groups << std::endl;
348
350
  ProcessResult* safe_result = result->clone();
349
351
  result_clones.push_back(safe_result);
350
352
  vmerger.add_tile(*safe_result);
351
353
  delete result;
352
354
  }
355
+ stripe_count++;
353
356
  }
354
357
 
355
358
  std::cout << "Merging polygons ..." << std::endl;
@@ -357,15 +360,20 @@ void stream_png_image(const std::string& filepath, uint32_t stripe_height) {
357
360
 
358
361
  if (merged_result) {
359
362
  std::cout << "Founds total polygons: " << merged_result->groups << std::endl;
360
- /*RawBitmap full_bitmap;
361
- full_bitmap.define(total_width, total_height, 4, true);
362
- full_bitmap.fill(255, 255, 255);
363
- merged_result->draw_on_bitmap(full_bitmap);
364
- std::cout << "Saving whole png ..." << std::endl;
365
- if (full_bitmap.save_to_png("whole.png")) {
366
- std::cout << "Png saved!" << std::endl;
367
- }*/
368
- merged_result->save_svg("whole.svg");
363
+ if (generate_png) {
364
+ RawBitmap full_bitmap;
365
+ full_bitmap.define(total_width, total_height, 4, true);
366
+ full_bitmap.fill(255, 255, 255);
367
+ merged_result->draw_on_bitmap(full_bitmap);
368
+ std::cout << "Saving whole png ..." << std::endl;
369
+ if (full_bitmap.save_to_png("whole.png")) {
370
+ std::cout << "Png saved!" << std::endl;
371
+ }
372
+ }
373
+ if (generate_svg) {
374
+ merged_result->save_svg("whole.svg");
375
+ std::cout << "Svg saved!" << std::endl;
376
+ }
369
377
  }
370
378
  delete merged_result;
371
379
  // frees memory
@@ -56,16 +56,16 @@ void RawBitmap::draw_pixel(int x, int y, unsigned char r, unsigned char g, unsig
56
56
  if (bpp > 3) p[3] = a;
57
57
  }
58
58
 
59
- uint32_t RawBitmap::define(uint width, uint height, int bytes_per_pixel, bool clear)
60
- { this->width = width;
59
+ size_t RawBitmap::define(uint width, uint height, int bytes_per_pixel, bool clear)
60
+ { this->width = width;
61
61
  this->height = height;
62
62
  this->bpp = bytes_per_pixel;
63
- uint32_t dimension = (static_cast<uint32_t>(width) * static_cast<uint32_t>(height)) * bytes_per_pixel;
63
+ size_t dimension = static_cast<size_t>(width) * static_cast<size_t>(height) * static_cast<size_t>(bytes_per_pixel);
64
64
  this->image = std::make_unique<unsigned char[]>(dimension);
65
65
  if (clear) {
66
66
  std::fill(image.get(), image.get() + dimension, 0);
67
67
  }
68
- return dimension;
68
+ return static_cast<uint32_t>(dimension);
69
69
  }
70
70
 
71
71
  void RawBitmap::fill(unsigned char r, unsigned char g, unsigned char b, unsigned char a) {
@@ -25,7 +25,7 @@ class RawBitmap : public Bitmap {
25
25
  unsigned int rgb_value_at(int x, int y);
26
26
  const unsigned char* get_row_ptr(int y) const;
27
27
  int get_bytes_per_pixel() const;
28
- uint32_t define(uint width, uint height, int bytes_per_pixel, bool clear = false);
28
+ size_t define(uint width, uint height, int bytes_per_pixel, bool clear = false);
29
29
  void draw_pixel(int x, int y, unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255);
30
30
  bool save_to_png(const std::string& filename);
31
31
  void fill(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255);
@@ -534,7 +534,7 @@ static void u16_row_to_bigendian(void *row, size_t size)
534
534
  write_u16(&px[i], px[i]);
535
535
  }
536
536
  }
537
-
537
+ /*
538
538
  static void rgb8_row_to_rgba8(const unsigned char *row, unsigned char *out, uint32_t n)
539
539
  {
540
540
  uint32_t i;
@@ -543,6 +543,22 @@ static void rgb8_row_to_rgba8(const unsigned char *row, unsigned char *out, uint
543
543
  memcpy(out + i * 4, row + i * 3, 3);
544
544
  out[i*4+3] = 255;
545
545
  }
546
+ }*/
547
+
548
+ /* Fix overflow Gigapixel images */
549
+ static void rgb8_row_to_rgba8(const unsigned char *row, unsigned char *out, uint32_t n)
550
+ {
551
+ size_t i;
552
+ for(i=0; i < n; i++)
553
+ {
554
+ out[0] = row[0];
555
+ out[1] = row[1];
556
+ out[2] = row[2];
557
+ out[3] = 255;
558
+
559
+ out += 4;
560
+ row += 3;
561
+ }
546
562
  }
547
563
 
548
564
  static unsigned num_channels(const struct spng_ihdr *ihdr)
@@ -147,50 +147,37 @@ struct ProcessResult {
147
147
  return new_res;
148
148
  }
149
149
 
150
- std::string to_svg() const {
151
- std::vector<std::string> lines;
152
- lines.push_back(
153
- "<svg xmlns=\"http://www.w3.org/2000/svg\" "
154
- "width=\"" + std::to_string(width) +
155
- "\" height=\"" + std::to_string(height) + "\">");
150
+ void to_svg_stream(std::ostream& os) const {
151
+ os << "<svg xmlns=\"http://www.w3.org/2000/svg\" "
152
+ << "width=\"" << width << "\" height=\"" << height << "\">\n";
156
153
  for (const auto& poly : polygons) {
157
- { // outer
158
- std::ostringstream pts;
154
+ // --- OUTER (Red) ---
155
+ if (!poly.outer.empty()) {
156
+ os << "<polygon points=\"";
159
157
  bool first = true;
160
158
  for (const Point* p : poly.outer) {
161
159
  if (!p) continue;
162
- if (!first)
163
- pts << " ";
160
+ if (!first) os << " ";
164
161
  first = false;
165
- pts << p->x << "," << p->y;
162
+ os << p->x << "," << p->y;
166
163
  }
167
- lines.push_back(
168
- "<polygon points=\"" + pts.str() +
169
- "\" fill=\"none\" stroke=\"red\" stroke-width=\"1\"/>");
164
+ os << "\" fill=\"none\" stroke=\"red\" stroke-width=\"1\"/>\n";
170
165
  }
171
- // inner
166
+ // --- INNER (Green) ---
172
167
  for (const auto& sequence : poly.inner) {
173
168
  if (sequence.empty()) continue;
174
- std::ostringstream pts;
169
+ os << "<polygon points=\"";
175
170
  bool first = true;
176
171
  for (const Point* p : sequence) {
177
172
  if (!p) continue;
178
- if (!first) pts << " ";
173
+ if (!first) os << " ";
179
174
  first = false;
180
- pts << p->x << "," << p->y;
175
+ os << p->x << "," << p->y;
181
176
  }
182
- lines.push_back(
183
- "<polygon points=\"" + pts.str() +
184
- "\" fill=\"none\" stroke=\"green\" stroke-width=\"1\"/>");
177
+ os << "\" fill=\"none\" stroke=\"green\" stroke-width=\"1\"/>\n";
185
178
  }
186
179
  }
187
- lines.push_back("</svg>");
188
- std::ostringstream result;
189
- for (size_t i = 0; i < lines.size(); ++i) {
190
- result << lines[i];
191
- if (i + 1 < lines.size()) result << "\n";
192
- }
193
- return result.str();
180
+ os << "</svg>";
194
181
  }
195
182
 
196
183
  void save_svg(const std::string& filename) const {
@@ -198,7 +185,7 @@ struct ProcessResult {
198
185
  if (!file.is_open()) {
199
186
  throw std::runtime_error("Unable to open SVG file: " + filename);
200
187
  }
201
- file << to_svg();
188
+ to_svg_stream(file);
202
189
  file.close();
203
190
  }
204
191
  };
@@ -1,3 +1,3 @@
1
1
  module Contrek
2
- VERSION = "1.2.5"
2
+ VERSION = "1.2.6"
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.5
4
+ version: 1.2.6
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-27 00:00:00.000000000 Z
11
+ date: 2026-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec