autotrace 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: dce37787636a8564e56fc6694fea1bbc27b2a484ff3f1ae0bf6bba498e1e76e0
4
+ data.tar.gz: dce6102e09ddcfa1f46187a8935b118ea9a2094cbfbb1f7375caebe2fc14b349
5
+ SHA512:
6
+ metadata.gz: b78ce717031ce4189cfd0ad409f948da4be9747d53d585b8c0726fa81d300d0fbd1493b2ed65e210b4a2cee1e91bc3977449bd4306fc0e0833c270f64cc6ed5a
7
+ data.tar.gz: 83553a622e9900f3ad94b5d0594a7763a3c5278619c126d13d45680deeea04390a91bafe258f452f38cf3ebd1737c45b50e32fab88aeb935094f9a69e722ffde
data/.rubocop.yml ADDED
@@ -0,0 +1,29 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+
4
+ Style/StringLiterals:
5
+ EnforcedStyle: double_quotes
6
+
7
+ Style/StringLiteralsInInterpolation:
8
+ EnforcedStyle: double_quotes
9
+
10
+ Metrics/MethodLength:
11
+ Enabled: false
12
+
13
+ Metrics/ClassLength:
14
+ Enabled: false
15
+
16
+ Metrics/ModuleLength:
17
+ Enabled: false
18
+
19
+ Metrics/CyclomaticComplexity:
20
+ Enabled: false
21
+
22
+ Metrics/AbcSize:
23
+ Enabled: false
24
+
25
+ Metrics/ParameterLists:
26
+ Enabled: false
27
+
28
+ Metrics/PerceivedComplexity:
29
+ Enabled: false
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.3.5
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2025-04-10
4
+
5
+ - Initial release
@@ -0,0 +1,132 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our
6
+ community a harassment-free experience for everyone, regardless of age, body
7
+ size, visible or invisible disability, ethnicity, sex characteristics, gender
8
+ identity and expression, level of experience, education, socio-economic status,
9
+ nationality, personal appearance, race, caste, color, religion, or sexual
10
+ identity and orientation.
11
+
12
+ We pledge to act and interact in ways that contribute to an open, welcoming,
13
+ diverse, inclusive, and healthy community.
14
+
15
+ ## Our Standards
16
+
17
+ Examples of behavior that contributes to a positive environment for our
18
+ community include:
19
+
20
+ * Demonstrating empathy and kindness toward other people
21
+ * Being respectful of differing opinions, viewpoints, and experiences
22
+ * Giving and gracefully accepting constructive feedback
23
+ * Accepting responsibility and apologizing to those affected by our mistakes,
24
+ and learning from the experience
25
+ * Focusing on what is best not just for us as individuals, but for the overall
26
+ community
27
+
28
+ Examples of unacceptable behavior include:
29
+
30
+ * The use of sexualized language or imagery, and sexual attention or advances of
31
+ any kind
32
+ * Trolling, insulting or derogatory comments, and personal or political attacks
33
+ * Public or private harassment
34
+ * Publishing others' private information, such as a physical or email address,
35
+ without their explicit permission
36
+ * Other conduct which could reasonably be considered inappropriate in a
37
+ professional setting
38
+
39
+ ## Enforcement Responsibilities
40
+
41
+ Community leaders are responsible for clarifying and enforcing our standards of
42
+ acceptable behavior and will take appropriate and fair corrective action in
43
+ response to any behavior that they deem inappropriate, threatening, offensive,
44
+ or harmful.
45
+
46
+ Community leaders have the right and responsibility to remove, edit, or reject
47
+ comments, commits, code, wiki edits, issues, and other contributions that are
48
+ not aligned to this Code of Conduct, and will communicate reasons for moderation
49
+ decisions when appropriate.
50
+
51
+ ## Scope
52
+
53
+ This Code of Conduct applies within all community spaces, and also applies when
54
+ an individual is officially representing the community in public spaces.
55
+ Examples of representing our community include using an official email address,
56
+ posting via an official social media account, or acting as an appointed
57
+ representative at an online or offline event.
58
+
59
+ ## Enforcement
60
+
61
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
62
+ reported to the community leaders responsible for enforcement at
63
+ [INSERT CONTACT METHOD].
64
+ All complaints will be reviewed and investigated promptly and fairly.
65
+
66
+ All community leaders are obligated to respect the privacy and security of the
67
+ reporter of any incident.
68
+
69
+ ## Enforcement Guidelines
70
+
71
+ Community leaders will follow these Community Impact Guidelines in determining
72
+ the consequences for any action they deem in violation of this Code of Conduct:
73
+
74
+ ### 1. Correction
75
+
76
+ **Community Impact**: Use of inappropriate language or other behavior deemed
77
+ unprofessional or unwelcome in the community.
78
+
79
+ **Consequence**: A private, written warning from community leaders, providing
80
+ clarity around the nature of the violation and an explanation of why the
81
+ behavior was inappropriate. A public apology may be requested.
82
+
83
+ ### 2. Warning
84
+
85
+ **Community Impact**: A violation through a single incident or series of
86
+ actions.
87
+
88
+ **Consequence**: A warning with consequences for continued behavior. No
89
+ interaction with the people involved, including unsolicited interaction with
90
+ those enforcing the Code of Conduct, for a specified period of time. This
91
+ includes avoiding interactions in community spaces as well as external channels
92
+ like social media. Violating these terms may lead to a temporary or permanent
93
+ ban.
94
+
95
+ ### 3. Temporary Ban
96
+
97
+ **Community Impact**: A serious violation of community standards, including
98
+ sustained inappropriate behavior.
99
+
100
+ **Consequence**: A temporary ban from any sort of interaction or public
101
+ communication with the community for a specified period of time. No public or
102
+ private interaction with the people involved, including unsolicited interaction
103
+ with those enforcing the Code of Conduct, is allowed during this period.
104
+ Violating these terms may lead to a permanent ban.
105
+
106
+ ### 4. Permanent Ban
107
+
108
+ **Community Impact**: Demonstrating a pattern of violation of community
109
+ standards, including sustained inappropriate behavior, harassment of an
110
+ individual, or aggression toward or disparagement of classes of individuals.
111
+
112
+ **Consequence**: A permanent ban from any sort of public interaction within the
113
+ community.
114
+
115
+ ## Attribution
116
+
117
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118
+ version 2.1, available at
119
+ [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
120
+
121
+ Community Impact Guidelines were inspired by
122
+ [Mozilla's code of conduct enforcement ladder][Mozilla CoC].
123
+
124
+ For answers to common questions about this code of conduct, see the FAQ at
125
+ [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
126
+ [https://www.contributor-covenant.org/translations][translations].
127
+
128
+ [homepage]: https://www.contributor-covenant.org
129
+ [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
130
+ [Mozilla CoC]: https://github.com/mozilla/diversity
131
+ [FAQ]: https://www.contributor-covenant.org/faq
132
+ [translations]: https://www.contributor-covenant.org/translations
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Dylan Player
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,238 @@
1
+ # 🎨 Autotrace
2
+
3
+ Ruby bindings for the Autotrace library, which converts raster images (like PNG) into vector graphics (like SVG). This gem provides a Ruby interface to the powerful Autotrace library, allowing for easy conversion of bitmap images to vector formats with extensive configuration options.
4
+
5
+ ## 📦 Installation
6
+
7
+ ### Prerequisites
8
+
9
+ Before installing the gem, you need to install the Autotrace library and its dependencies on your system.
10
+
11
+ #### 🍎 macOS
12
+
13
+ ```bash
14
+ brew install libffi
15
+ brew install autotrace
16
+ ```
17
+
18
+ #### 🐧 Ubuntu
19
+
20
+ Since Autotrace is not available in the default Ubuntu repositories, you'll need to compile it from source:
21
+
22
+ ```bash
23
+ # Install dependencies
24
+ sudo apt update
25
+ sudo apt install -y \
26
+ build-essential \
27
+ git \
28
+ libmagickcore-dev \
29
+ autotools-dev \
30
+ autopoint \
31
+ diffutils \
32
+ libtool \
33
+ intltool \
34
+ libpng-dev \
35
+ libexif-dev \
36
+ libtiff5-dev \
37
+ libjpeg-dev \
38
+ libxml2-dev \
39
+ libbz2-dev \
40
+ libpstoedit-dev \
41
+ libfreetype6-dev \
42
+ libpstoedit0c2a \
43
+ libbz2-1.0 \
44
+ libgd3 \
45
+ libffi-dev \
46
+ pkg-config
47
+
48
+ # Clone the repository
49
+ git clone https://github.com/autotrace/autotrace.git
50
+ cd autotrace
51
+
52
+ # Generate configuration files
53
+ ./autogen.sh
54
+
55
+ # Configure and build
56
+ ./configure --prefix=/usr
57
+ make
58
+
59
+ # Test if it works before installing
60
+ ./autotrace --version
61
+
62
+ # Install and update the shared library cache
63
+ sudo make install
64
+ sudo ldconfig
65
+ ```
66
+
67
+ **Note:** If you encounter issues with ImageMagick or Pstoedit during compilation, you can disable them with configuration options:
68
+
69
+ - `./configure --without-magick` - Disable ImageMagick support
70
+ - `./configure --without-pstoedit` - Disable Pstoedit support
71
+
72
+ For more detailed installation instructions and troubleshooting, refer to the [official Autotrace installation guide](https://github.com/autotrace/autotrace/blob/master/INSTALL.md).
73
+
74
+ #### 🐳 Using Docker
75
+
76
+ There is a reference Dockerfile here: [examples/Dockerfile](examples/Dockerfile).
77
+
78
+ ```bash
79
+ # Build the Docker image
80
+ docker build -t autotrace-example -f examples/Dockerfile .
81
+
82
+ # Create a directory to store output files
83
+ mkdir -p output
84
+
85
+ # Run the container with your image
86
+ docker run -v /path/to/your/image.png:/app/sample.png -v $(pwd)/output:/app/output autotrace-example
87
+ ```
88
+
89
+ ### 💎 Installing the Gem
90
+
91
+ Add this line to your application's Gemfile:
92
+
93
+ ```ruby
94
+ gem 'autotrace'
95
+ ```
96
+
97
+ And then execute:
98
+
99
+ ```bash
100
+ bundle install
101
+ ```
102
+
103
+ Or install it yourself as:
104
+
105
+ ```bash
106
+ gem install autotrace
107
+ ```
108
+
109
+ ## 🚀 Usage
110
+
111
+ ### Basic Usage
112
+
113
+ Convert a PNG image to SVG:
114
+
115
+ ```ruby
116
+ require 'autotrace'
117
+
118
+ # Convert image.png to image.svg
119
+ Autotrace.trace_image('image.png', output_suffix: 'svg')
120
+ ```
121
+
122
+ ### Advanced Usage
123
+
124
+ The library provides extensive configuration options for controlling the tracing process:
125
+
126
+ ```ruby
127
+ require 'autotrace'
128
+
129
+ # Convert with custom options
130
+ Autotrace.trace_image('input.png',
131
+ output_suffix: 'svg',
132
+ background_color: 'FFFFFF', # White background
133
+ error_threshold: 1.0, # Lower error threshold for more detail
134
+ despeckle_level: 2, # Remove small artifacts
135
+ preserve_width: true, # Preserve line widths
136
+ centerline: false, # Don't trace along centerline
137
+ noise_removal: 0.95, # Remove noise while preserving detail
138
+ color_count: 8 # Limit to 8 colors
139
+ )
140
+ ```
141
+
142
+ ### ⚙️ Available Options
143
+
144
+ The following options are available for fine-tuning the conversion process:
145
+
146
+ - `background_color`: Background color in hex format (e.g. "FFFFFF")
147
+ - `centerline`: Whether to trace along the centerline (boolean)
148
+ - `charcode`: Character code for text output (integer)
149
+ - `color_count`: Number of colors to use (integer)
150
+ - `corner_always_threshold`: Threshold for corner detection (float)
151
+ - `corner_surround`: Number of points to consider for corner detection (integer)
152
+ - `corner_threshold`: Threshold for corner detection (float)
153
+ - `despeckle_level`: Level of despeckling to apply (integer)
154
+ - `despeckle_tightness`: Tightness of despeckling (float)
155
+ - `dpi`: DPI setting for output (affects MIF output scaling) (integer)
156
+ - `error_threshold`: Error threshold for curve fitting (float)
157
+ - `filter_iterations`: Number of filter iterations (integer)
158
+ - `line_reversion_threshold`: Threshold for line reversion (float)
159
+ - `line_threshold`: Threshold for line detection (float)
160
+ - `noise_removal`: Level of noise removal (float)
161
+ - `preserve_width`: Whether to preserve line width (boolean)
162
+ - `remove_adjacent_corners`: Whether to remove adjacent corners (boolean)
163
+ - `tangent_surround`: Number of points to consider for tangent detection (integer)
164
+ - `width_weight_factor`: Weight factor for width preservation (float)
165
+
166
+ ## 🔧 Development
167
+
168
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
169
+
170
+ To install this gem onto your local machine, run `bundle exec rake install`.
171
+
172
+ ### 🚀 Creating a Release
173
+
174
+ This project uses GitHub Actions to automate the release process. To create a new release:
175
+
176
+ 1. Update the version number in `lib/autotrace/version.rb`
177
+ 2. Update the `CHANGELOG.md` with the changes for the new version
178
+ 3. Commit your changes:
179
+ ```bash
180
+ git add lib/autotrace/version.rb CHANGELOG.md
181
+ git commit -m "Bump version to vX.Y.Z"
182
+ ```
183
+ 4. Create and push a new tag:
184
+ ```bash
185
+ git tag -a vX.Y.Z -m "Release vX.Y.Z"
186
+ git push origin vX.Y.Z
187
+ ```
188
+
189
+ The GitHub Actions workflow will automatically:
190
+
191
+ - Run the test suite
192
+ - Build the gem
193
+ - Publish the gem to RubyGems.org
194
+
195
+ **Note:** Make sure you have set up the `RUBYGEMS_API_KEY` secret in your GitHub repository settings before creating a release. You can generate an API key from your RubyGems account settings.
196
+
197
+ ## 🧪 Testing
198
+
199
+ The gem includes a test suite that verifies the basic functionality works correctly.
200
+
201
+ ### Prerequisites for Testing
202
+
203
+ 1. Make sure you have the Autotrace C library installed (see Installation section above)
204
+ 2. Place a test image named `tower.png` in the `test/files` directory
205
+
206
+ ### Running the Tests
207
+
208
+ You can run the tests with:
209
+
210
+ ```bash
211
+ # Run all tests
212
+ rake test
213
+
214
+ # Run a specific test file
215
+ ruby -I lib:test test/test_autotrace.rb
216
+ ```
217
+
218
+ The test suite includes a basic test that converts a PNG image to SVG format to ensure the gem is working correctly with your system's Autotrace installation.
219
+
220
+ ### Troubleshooting Tests
221
+
222
+ If you encounter errors during testing:
223
+
224
+ 1. Verify that Autotrace is correctly installed on your system by running `autotrace --version` in your terminal
225
+ 2. Check that the test image file exists at `test/files/tower.png`
226
+ 3. Look for any warning messages about unsupported or missing libraries
227
+
228
+ ## 🤝 Contributing
229
+
230
+ Bug reports and pull requests are welcome on GitHub at https://github.com/851-labs/autotrace. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/851-labs/autotrace/blob/main/CODE_OF_CONDUCT.md).
231
+
232
+ ## 📄 License
233
+
234
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
235
+
236
+ ## ✨ Code of Conduct
237
+
238
+ Everyone interacting in the Autotrace project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/851-labs/autotrace/blob/main/CODE_OF_CONDUCT.md).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "minitest/test_task"
5
+
6
+ Minitest::TestTask.create
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[test rubocop]
@@ -0,0 +1,93 @@
1
+ FROM ruby:3.3.5-slim
2
+
3
+ # Install dependencies for Autotrace based on official build script
4
+ RUN apt-get update && apt-get install -y \
5
+ build-essential \
6
+ git \
7
+ libmagickcore-dev \
8
+ autotools-dev \
9
+ autopoint \
10
+ diffutils \
11
+ libtool \
12
+ intltool \
13
+ libpng-dev \
14
+ libexif-dev \
15
+ libtiff5-dev \
16
+ libjpeg-dev \
17
+ libxml2-dev \
18
+ libbz2-dev \
19
+ libpstoedit-dev \
20
+ libfreetype6-dev \
21
+ libpstoedit0c2a \
22
+ libbz2-1.0 \
23
+ libgd3 \
24
+ libffi-dev \
25
+ pkg-config \
26
+ curl \
27
+ wget \
28
+ && rm -rf /var/lib/apt/lists/*
29
+
30
+ # Clone and build Autotrace
31
+ WORKDIR /tmp
32
+ RUN git clone https://github.com/autotrace/autotrace.git && \
33
+ cd autotrace && \
34
+ ./autogen.sh && \
35
+ ./configure --prefix=/usr && \
36
+ make && \
37
+ make install && \
38
+ ldconfig && \
39
+ cd .. && \
40
+ rm -rf autotrace
41
+
42
+ # Set up working directory for the application
43
+ WORKDIR /app
44
+
45
+ # Create output directory
46
+ RUN mkdir -p /app/output
47
+
48
+ # Copy the entire gem source code to the container
49
+ COPY . /app/autotrace-gem/
50
+
51
+ # Install required dependencies for the gem
52
+ RUN gem install ffi -v "~> 1.17.1"
53
+
54
+ # Copy the example files to /app
55
+ COPY examples/trace_example.rb /app/trace_example.rb
56
+ COPY examples/run.sh /app/run.sh
57
+
58
+ # Make the run script executable
59
+ RUN chmod +x /app/run.sh
60
+
61
+ # Set RUBYLIB environment variable to include the autotrace gem lib directory
62
+ ENV RUBYLIB="/app/autotrace-gem/lib:${RUBYLIB}"
63
+
64
+ # Print information about the available libraries
65
+ RUN ldconfig -p | grep "libgobject\\|libglib\\|libMagickCore\\|libpstoedit\\|libpng"
66
+
67
+ # Set working directory back to /app
68
+ WORKDIR /app
69
+
70
+ # Find the locations of the required libraries for debugging
71
+ RUN echo "Checking for required libraries:" && \
72
+ find /usr/lib -name "libautotrace*" && \
73
+ find /usr/local/lib -name "libautotrace*" && \
74
+ ldconfig -p | grep autotrace
75
+
76
+ # Verify that we can load the autotrace gem with better error handling
77
+ RUN ruby -e "begin; \
78
+ require 'autotrace'; \
79
+ puts 'Autotrace gem loaded successfully!'; \
80
+ rescue LoadError => e; \
81
+ puts \"LoadError: #{e.message}\"; \
82
+ exit 1; \
83
+ rescue => e; \
84
+ puts \"Error: #{e.class.name} - #{e.message}\"; \
85
+ puts e.backtrace; \
86
+ exit 1; \
87
+ end"
88
+
89
+ # Set the entry point to the shell script
90
+ ENTRYPOINT ["/app/run.sh"]
91
+
92
+ # The sample.png should be mounted from the host
93
+ # Example: docker run -v $(pwd)/examples/sample.png:/app/sample.png -v $(pwd)/output:/app/output autotrace-example
@@ -0,0 +1,62 @@
1
+ # Autotrace Examples
2
+
3
+ This directory contains examples demonstrating how to use the Autotrace gem.
4
+
5
+ ## Contents
6
+
7
+ - `Dockerfile` - Docker setup for running Autotrace
8
+ - `trace_example.rb` - Example Ruby script showing various tracing options
9
+ - `sample.png` - Sample image for the examples
10
+
11
+ ## Running with Docker
12
+
13
+ The provided Dockerfile sets up a complete environment for running Autotrace.
14
+
15
+ ### Build the Docker image
16
+
17
+ ```bash
18
+ docker build -t autotrace-example -f examples/Dockerfile .
19
+ ```
20
+
21
+ ### Run the container with the sample image
22
+
23
+ ```bash
24
+ # Create a directory to store output files
25
+ mkdir -p output
26
+
27
+ # Run the container with the sample image mounted
28
+ docker run -v $(pwd)/examples/sample.png:/app/sample.png -v $(pwd)/output:/app/output autotrace-example
29
+ ```
30
+
31
+ ### Using your own images
32
+
33
+ You can convert your own images by mounting them to the container:
34
+
35
+ ```bash
36
+ docker run -v /path/to/your/image.png:/app/sample.png -v $(pwd)/output:/app/output autotrace-example
37
+ ```
38
+
39
+ ## Running the Ruby Example Directly
40
+
41
+ If you have Autotrace installed on your system, you can run the example script directly:
42
+
43
+ ```bash
44
+ cd examples
45
+ ruby trace_example.rb
46
+ ```
47
+
48
+ Make sure you have the `sample.png` file in the same directory as the script.
49
+
50
+ ## Output
51
+
52
+ The traced vector files will be created in the same directory as the input file, with the appropriate extension:
53
+
54
+ - `sample.svg` - SVG vector output
55
+ - `sample.eps` - EPS vector output (if you run Example 3)
56
+
57
+ ## Additional Resources
58
+
59
+ For more information about Autotrace and its options, see:
60
+
61
+ - [Autotrace GitHub Repository](https://github.com/autotrace/autotrace)
62
+ - [Ruby Gem Documentation](https://github.com/851-labs/autotrace)
data/examples/run.sh ADDED
@@ -0,0 +1,28 @@
1
+ #!/bin/bash
2
+
3
+ echo "==================================================="
4
+ echo "Autotrace - Converting raster images to vector graphics"
5
+ echo "==================================================="
6
+
7
+ if [ ! -f /app/sample.png ]; then
8
+ echo "Error: sample.png not found in /app directory."
9
+ echo "Please mount your image to /app/sample.png:"
10
+ echo " docker run -v /path/to/your/image.png:/app/sample.png autotrace-example"
11
+ exit 1
12
+ fi
13
+
14
+ echo "Found image: /app/sample.png"
15
+ echo "Running trace script..."
16
+ echo "==================================================="
17
+
18
+ # Run the Ruby example script
19
+ ruby /app/trace_example.rb
20
+
21
+ # Copy output files to output directory
22
+ cp /app/*.svg /app/output/ 2>/dev/null || true
23
+ cp /app/*.eps /app/output/ 2>/dev/null || true
24
+
25
+ echo "==================================================="
26
+ echo "Process complete!"
27
+ echo "Output files can be found in the mounted output directory"
28
+ echo "==================================================="
Binary file
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ puts "Ruby Version: #{RUBY_VERSION}"
5
+ puts "Load Path: #{$LOAD_PATH.join(":")}"
6
+ puts "Current Directory: #{Dir.pwd}"
7
+ puts "Files in /app/autotrace-gem/lib: #{Dir.glob("/app/autotrace-gem/lib/**/*")}"
8
+
9
+ begin
10
+ puts "Attempting to require autotrace..."
11
+ require "autotrace"
12
+ puts "Successfully loaded autotrace!"
13
+ rescue LoadError => e
14
+ puts "Error loading autotrace: #{e.message}"
15
+ puts "Try loading from direct path..."
16
+ require_relative "/app/autotrace-gem/lib/autotrace"
17
+ puts "Successfully loaded autotrace from direct path!"
18
+ end
19
+
20
+ # This example demonstrates how to use the Autotrace gem to convert
21
+ # a raster image to a vector format with various options.
22
+
23
+ def trace_with_options(input_file, options = {})
24
+ puts "Converting #{input_file} with options: #{options.inspect}"
25
+
26
+ # Trace the image with the specified options
27
+ result = Autotrace.trace_image(
28
+ input_file,
29
+ **options
30
+ )
31
+
32
+ puts "Conversion complete! Output file: #{result.path}"
33
+
34
+ # Return the result file
35
+ result
36
+ end
37
+
38
+ # Example 1: Simple conversion to SVG
39
+ puts "Example 1: Simple conversion to SVG"
40
+ trace_with_options("sample.png", output_suffix: "svg")
41
+
42
+ # Example 2: Conversion with custom options
43
+ puts "\nExample 2: Conversion with custom options"
44
+ trace_with_options("sample.png",
45
+ output_suffix: "svg",
46
+ background_color: "FFFFFF", # White background
47
+ error_threshold: 1.0, # Lower error threshold for more detail
48
+ despeckle_level: 2, # Remove small artifacts
49
+ preserve_width: true, # Preserve line widths
50
+ centerline: false, # Don't trace along centerline
51
+ noise_removal: 0.95) # Remove noise while preserving detail
52
+
53
+ # Example 3: Convert to EPS format
54
+ puts "\nExample 3: Convert to EPS format"
55
+ trace_with_options("sample.png", output_suffix: "eps")
56
+
57
+ puts "\nAll conversions completed successfully!"
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+
5
+ module Autotrace
6
+ # FFI module that provides bindings to the Autotrace C library.
7
+ # This module handles all the low-level interactions with the C library
8
+ # through FFI (Foreign Function Interface).
9
+ module FFI
10
+ extend ::FFI::Library
11
+
12
+ ffi_lib_flags :now, :global
13
+
14
+ ffi_lib [
15
+ # libgobject (Linux, macOS, Windows)
16
+ "libgobject-2.0", # generic name (might work if found via linker)
17
+ "libgobject-2.0.so.0", # typical on Linux distributions (Debian/RedHat)
18
+ "libgobject-2.0.dylib", # common on macOS (if installed via Homebrew or MacPorts)
19
+ "gobject-2.0.dll" # common on Windows
20
+ ]
21
+
22
+ ffi_lib [
23
+ # libglib
24
+ "libglib-2.0",
25
+ "libglib-2.0.so.0",
26
+ "libglib-2.0.dylib",
27
+ "glib-2.0.dll"
28
+ ]
29
+
30
+ ffi_lib [
31
+ # ImageMagick's MagickCore library
32
+ "libMagickCore-7.Q16HDRI",
33
+ "libMagickCore-6.Q16HDRI",
34
+ "libMagickCore-7.Q16.so",
35
+ "libMagickCore-6.Q16.so.6",
36
+ "libMagickCore-6.Q16.so"
37
+ ]
38
+
39
+ ffi_lib [
40
+ # pstoedit library
41
+ "libpstoedit",
42
+ "libpstoedit.so.0",
43
+ "libpstoedit.dylib",
44
+ "pstoedit.dll"
45
+ ]
46
+
47
+ ffi_lib [
48
+ # libpng library
49
+ "libpng",
50
+ "libpng16.so.16", # Often libpng is packaged as libpng16 on newer systems
51
+ "libpng.dylib",
52
+ "png.dll"
53
+ ]
54
+
55
+ # Load the main Autotrace library with alternate names:
56
+ ffi_lib [
57
+ "libautotrace.3",
58
+ "libautotrace.so.3", # Linux typical shared object name
59
+ "libautotrace.dylib", # macOS typical dynamic library name
60
+ "autotrace.dll" # Windows DLL alternative
61
+ ]
62
+
63
+ # Module providing bindings to standard C library functions
64
+ module CStdLib
65
+ extend ::FFI::Library
66
+ ffi_lib ::FFI::Library::LIBC
67
+
68
+ attach_function :fopen, %i[string string], :pointer
69
+ attach_function :fclose, [:pointer], :int
70
+ end
71
+
72
+ # Structure representing an RGB color in the Autotrace library
73
+ class AtColor < ::FFI::Struct
74
+ layout :r, :uint8, :g, :uint8, :b, :uint8
75
+ end
76
+
77
+ # Structure containing all the fitting options for the Autotrace algorithm
78
+ class AtFittingOpts < ::FFI::Struct
79
+ layout :background_color, :pointer, # at_color*
80
+ :charcode, :uint,
81
+ :color_count, :uint,
82
+ :corner_always_threshold, :float,
83
+ :corner_surround, :uint,
84
+ :corner_threshold, :float,
85
+ :error_threshold, :float,
86
+ :filter_iterations, :uint,
87
+ :line_reversion_threshold, :float,
88
+ :line_threshold, :float,
89
+ :remove_adjacent_corners, :bool,
90
+ :tangent_surround, :uint,
91
+ :despeckle_level, :uint,
92
+ :despeckle_tightness, :float,
93
+ :noise_removal, :float,
94
+ :centerline, :bool,
95
+ :preserve_width, :bool,
96
+ :width_weight_factor, :float
97
+ end
98
+
99
+ # Structure containing output options for the Autotrace library
100
+ class AtOutputOpts < ::FFI::Struct
101
+ layout :dpi, :int
102
+ end
103
+
104
+ # Initialize the Autotrace library
105
+ attach_function :autotrace_init, [], :void
106
+ # Initialize input handlers
107
+ attach_function :at_input_init, [], :int
108
+ # Initialize modules
109
+ attach_function :at_module_init, [], :int
110
+
111
+ # Create and free fitting options
112
+ attach_function :at_fitting_opts_new, [], :pointer
113
+ attach_function :at_fitting_opts_free, [:pointer], :void
114
+
115
+ # Create and free output options
116
+ attach_function :at_output_opts_new, [], :pointer
117
+ attach_function :at_output_opts_free, [:pointer], :void
118
+
119
+ # Get input handler for a specific file
120
+ attach_function :at_input_get_handler, [:string], :pointer
121
+ # Read bitmap from file
122
+ attach_function :at_bitmap_read, %i[pointer string pointer pointer pointer], :pointer
123
+
124
+ # Create splines from bitmap
125
+ attach_function :at_splines_new, %i[pointer pointer pointer pointer], :pointer
126
+ # Write splines to output file
127
+ attach_function :at_splines_write, %i[pointer pointer string pointer pointer pointer pointer], :void
128
+
129
+ # Get output handler by file suffix
130
+ attach_function :at_output_get_handler_by_suffix, [:string], :pointer
131
+
132
+ # Free allocated memory
133
+ attach_function :at_bitmap_free, [:pointer], :void
134
+ attach_function :at_splines_free, [:pointer], :void
135
+ end
136
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Autotrace
4
+ VERSION = "0.1.0"
5
+ end
data/lib/autotrace.rb ADDED
@@ -0,0 +1,259 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "autotrace/version"
4
+ require_relative "autotrace/ffi"
5
+
6
+ # Autotrace is a Ruby gem that provides bindings to the Autotrace library,
7
+ # which converts raster images (like PNG) into vector graphics (like SVG).
8
+ #
9
+ # The library supports various input and output formats, and provides extensive
10
+ # configuration options for controlling the tracing process.
11
+ #
12
+ # @example Converting a PNG to SVG
13
+ # Autotrace.trace_image("input.png", output_suffix: "svg")
14
+ #
15
+ # @example Converting with custom options
16
+ # Autotrace.trace_image("input.png",
17
+ # output_suffix: "svg",
18
+ # background_color: "FFFFFF",
19
+ # error_threshold: 1.0
20
+ # )
21
+ module Autotrace
22
+ # Base error class for all Autotrace-related errors
23
+ class Error < StandardError; end
24
+
25
+ class << self
26
+ attr_accessor :initialized
27
+
28
+ # Initialize the Autotrace library. This must be called before any other
29
+ # operations. It sets up input handlers and other necessary components.
30
+ #
31
+ # @return [void]
32
+ def init_autotrace
33
+ return if initialized
34
+
35
+ FFI.autotrace_init
36
+ FFI.at_input_init
37
+ FFI.at_module_init
38
+
39
+ self.initialized = true
40
+ end
41
+
42
+ # Convert a raster image to a vector graphic format.
43
+ #
44
+ # @param input_image [String] Path to the input raster image
45
+ #
46
+ # @param output_suffix [String] Desired output format (e.g. "svg", "eps")
47
+ # @param output_file [String, nil] Path to write the output file. If nil,
48
+ # the output file will be "<basename>.<output_suffix>" in the same folder
49
+ # as the input file.
50
+ #
51
+ # @param background_color [String, nil] Background color in hex format (e.g. "FFFFFF")
52
+ # @param centerline [Boolean] Whether to trace along the centerline
53
+ # @param charcode [Integer] Character code for text output
54
+ # @param color_count [Integer] Number of colors to use
55
+ # @param corner_always_threshold [Float] Threshold for corner detection
56
+ # @param corner_surround [Integer] Number of points to consider for corner detection
57
+ # @param corner_threshold [Float] Threshold for corner detection
58
+ # @param despeckle_level [Integer] Level of despeckling to apply
59
+ # @param despeckle_tightness [Float] Tightness of despeckling
60
+ # @param dpi [Integer] DPI setting for output (affects MIF output scaling)
61
+ # @param error_threshold [Float] Error threshold for curve fitting
62
+ # @param filter_iterations [Integer] Number of filter iterations
63
+ # @param line_reversion_threshold [Float] Threshold for line reversion
64
+ # @param line_threshold [Float] Threshold for line detection
65
+ # @param noise_removal [Float] Level of noise removal
66
+ # @param preserve_width [Boolean] Whether to preserve line width
67
+ # @param remove_adjacent_corners [Boolean] Whether to remove adjacent corners
68
+ # @param tangent_surround [Integer] Number of points to consider for tangent detection
69
+ # @param width_weight_factor [Float] Weight factor for width preservation
70
+ #
71
+ # @return [File] A File object pointing to the newly created vector file
72
+ # @raise [Error] If any step in the conversion process fails
73
+ def trace_image(
74
+ input_image,
75
+ output_suffix: "svg",
76
+ output_file: nil,
77
+ background_color: nil,
78
+ centerline: false,
79
+ charcode: 0,
80
+ color_count: 0,
81
+ corner_always_threshold: 60.0,
82
+ corner_surround: 4,
83
+ corner_threshold: 100.0,
84
+ despeckle_level: 0,
85
+ despeckle_tightness: 2.0,
86
+ dpi: 0,
87
+ error_threshold: 2.0,
88
+ filter_iterations: 4,
89
+ line_reversion_threshold: 0.01,
90
+ line_threshold: 1.0,
91
+ noise_removal: 0.99,
92
+ preserve_width: false,
93
+ remove_adjacent_corners: false,
94
+ tangent_surround: 3,
95
+ width_weight_factor: 0.0
96
+ )
97
+ init_autotrace
98
+
99
+ # 1. Create the input & output option structs
100
+ fitting_opts_ptr = FFI.at_fitting_opts_new
101
+ raise Error, "Failed to allocate fitting options" if fitting_opts_ptr.null?
102
+
103
+ output_opts_ptr = FFI.at_output_opts_new
104
+ raise Error, "Failed to allocate output options" if output_opts_ptr.null?
105
+
106
+ # 2. Fill in all the fields from your arguments.
107
+ configure_fitting_opts(
108
+ fitting_opts_ptr,
109
+ background_color: background_color,
110
+ centerline: centerline,
111
+ charcode: charcode,
112
+ color_count: color_count,
113
+ corner_always_threshold: corner_always_threshold,
114
+ corner_surround: corner_surround,
115
+ corner_threshold: corner_threshold,
116
+ despeckle_level: despeckle_level,
117
+ despeckle_tightness: despeckle_tightness,
118
+ error_threshold: error_threshold,
119
+ filter_iterations: filter_iterations,
120
+ line_reversion_threshold: line_reversion_threshold,
121
+ line_threshold: line_threshold,
122
+ noise_removal: noise_removal,
123
+ preserve_width: preserve_width,
124
+ remove_adjacent_corners: remove_adjacent_corners,
125
+ tangent_surround: tangent_surround,
126
+ width_weight_factor: width_weight_factor
127
+ )
128
+
129
+ configure_output_opts(output_opts_ptr, dpi: dpi)
130
+
131
+ # 3. Acquire input handler & read the bitmap
132
+ input_handler = FFI.at_input_get_handler(input_image)
133
+ raise Error, "Failed to get input handler for #{input_image}" if input_handler.null?
134
+
135
+ bitmap = FFI.at_bitmap_read(input_handler, input_image, nil, nil, nil)
136
+ raise Error, "Failed to read bitmap from #{input_image}" if bitmap.null?
137
+
138
+ # 4. Create splines
139
+ splines = FFI.at_splines_new(bitmap, fitting_opts_ptr, nil, nil)
140
+ raise Error, "Failed to create splines" if splines.null?
141
+
142
+ # 5. Output handler
143
+ output_handler = FFI.at_output_get_handler_by_suffix(output_suffix)
144
+ raise Error, "Unknown output format: .#{output_suffix}" if output_handler.null?
145
+
146
+ # 6. Determine output file path
147
+ if output_file.nil? || output_file.empty?
148
+ # default to "<basename>.<suffix>"
149
+ output_basename = File.basename(input_image, ".*")
150
+ output_file = "#{output_basename}.#{output_suffix}"
151
+ end
152
+
153
+ # 7. Write to a real file
154
+ c_file = FFI::CStdLib.fopen(output_file, "wb")
155
+ raise Error, "Failed to open #{output_file} with C fopen" if c_file.null?
156
+
157
+ FFI.at_splines_write(
158
+ output_handler,
159
+ c_file,
160
+ output_file,
161
+ output_opts_ptr,
162
+ splines,
163
+ nil, # msg_func
164
+ nil # msg_data
165
+ )
166
+
167
+ # Close
168
+ FFI::CStdLib.fclose(c_file)
169
+
170
+ # (Optional) free memory
171
+ FFI.at_fitting_opts_free(fitting_opts_ptr)
172
+ FFI.at_output_opts_free(output_opts_ptr)
173
+ FFI.at_bitmap_free(bitmap)
174
+ FFI.at_splines_free(splines)
175
+
176
+ File.open(output_file, "rb")
177
+ end
178
+
179
+ private
180
+
181
+ # Convert a background color hex string (e.g. "FF00FF") into an at_color struct pointer
182
+ # or return nil if background_color is not specified.
183
+ def parse_background_color(background_color)
184
+ return nil if background_color.nil? || background_color.empty?
185
+
186
+ # Convert e.g. "FFFFFF" => r=255,g=255,b=255
187
+ rgb = background_color.strip
188
+ rgb = rgb.delete_prefix("#") # remove leading '#' if present
189
+ raise Error, "Background color must be 6 hex digits" unless rgb.size == 6
190
+
191
+ r = rgb[0..1].to_i(16)
192
+ g = rgb[2..3].to_i(16)
193
+ b = rgb[4..5].to_i(16)
194
+
195
+ # Allocate an AtColor struct in memory
196
+ color_ptr = ::FFI::MemoryPointer.new(:uint8, 3)
197
+ color_struct = FFI::AtColor.new(color_ptr)
198
+ color_struct[:r] = r
199
+ color_struct[:g] = g
200
+ color_struct[:b] = b
201
+ color_ptr
202
+ end
203
+
204
+ # Fill in at_fitting_opts_type
205
+ def configure_fitting_opts(
206
+ fitting_opts_ptr,
207
+ background_color: nil,
208
+ centerline: false,
209
+ charcode: 0,
210
+ color_count: 0,
211
+ corner_always_threshold: 60.0,
212
+ corner_surround: 4,
213
+ corner_threshold: 100.0,
214
+ despeckle_level: 0,
215
+ despeckle_tightness: 2.0,
216
+ error_threshold: 2.0,
217
+ filter_iterations: 4,
218
+ line_reversion_threshold: 0.01,
219
+ line_threshold: 1.0,
220
+ noise_removal: 0.99,
221
+ preserve_width: false,
222
+ remove_adjacent_corners: false,
223
+ tangent_surround: 3,
224
+ width_weight_factor: 0.0
225
+ )
226
+ opts = FFI::AtFittingOpts.new(fitting_opts_ptr)
227
+
228
+ # Possibly parse background color
229
+ bg_ptr = parse_background_color(background_color)
230
+ opts[:background_color] = bg_ptr
231
+ opts[:charcode] = charcode
232
+ opts[:color_count] = color_count
233
+ opts[:corner_always_threshold] = corner_always_threshold
234
+ opts[:corner_surround] = corner_surround
235
+ opts[:corner_threshold] = corner_threshold
236
+ opts[:despeckle_level] = despeckle_level
237
+ opts[:despeckle_tightness] = despeckle_tightness
238
+ opts[:error_threshold] = error_threshold
239
+ opts[:filter_iterations] = filter_iterations
240
+ opts[:line_reversion_threshold] = line_reversion_threshold
241
+ opts[:line_threshold] = line_threshold
242
+ opts[:noise_removal] = noise_removal
243
+ opts[:preserve_width] = preserve_width
244
+ opts[:remove_adjacent_corners] = remove_adjacent_corners
245
+ opts[:tangent_surround] = tangent_surround
246
+ opts[:width_weight_factor] = width_weight_factor
247
+ opts[:centerline] = centerline
248
+
249
+ fitting_opts_ptr
250
+ end
251
+
252
+ # Fill in at_output_opts_type (currently only 'dpi')
253
+ def configure_output_opts(output_opts_ptr, dpi: 0)
254
+ out = FFI::AtOutputOpts.new(output_opts_ptr)
255
+ out[:dpi] = dpi
256
+ output_opts_ptr
257
+ end
258
+ end
259
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: autotrace
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dylan Player
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-04-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 1.17.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 1.17.1
27
+ description: |
28
+ Ruby bindings for the Autotrace library, which converts raster images (like PNG)
29
+ into vector graphics (like SVG). This gem provides a Ruby interface to the
30
+ powerful Autotrace library, allowing for easy conversion of bitmap images to
31
+ vector formats with extensive configuration options.
32
+ email:
33
+ - dylan@851.sh
34
+ executables: []
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - ".rubocop.yml"
39
+ - ".ruby-version"
40
+ - CHANGELOG.md
41
+ - CODE_OF_CONDUCT.md
42
+ - LICENSE.txt
43
+ - README.md
44
+ - Rakefile
45
+ - examples/Dockerfile
46
+ - examples/README.md
47
+ - examples/run.sh
48
+ - examples/sample.png
49
+ - examples/trace_example.rb
50
+ - lib/autotrace.rb
51
+ - lib/autotrace/ffi.rb
52
+ - lib/autotrace/version.rb
53
+ homepage: https://github.com/851-labs/autotrace
54
+ licenses:
55
+ - MIT
56
+ metadata:
57
+ homepage_uri: https://github.com/851-labs/autotrace
58
+ source_code_uri: https://github.com/851-labs/autotrace
59
+ changelog_uri: https://github.com/851-labs/autotrace/blob/main/CHANGELOG.md
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 3.0.0
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubygems_version: 3.5.16
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: Ruby bindings for the Autotrace library
79
+ test_files: []