tsf 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 +7 -0
- data/README.md +23 -0
- data/lib/tsf/convert/tsf_to_image.rb +14 -0
- data/lib/tsf/convert/tsf_to_svg.rb +14 -0
- data/lib/tsf/vector.rb +168 -0
- data/lib/tsf/version.rb +3 -0
- data/lib/tsf.rb +10 -0
- metadata +45 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 8dd49df524555e9c11369bba05b4c55855a972ead2493da6bd03aedb5ffbee55
|
4
|
+
data.tar.gz: 94d338f36c27841fa5efc52b83060c3788a01fd5df5687be82db1b0e260f88e3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 11c7ba675c35eb3be2f35d08e3f9f694a5336d87994f8ab338cdeafa0f67ac9507be1674be52dd0bfb456f8d15a62a3e85bbaaeb1d4c40f3d331e1448e060f87
|
7
|
+
data.tar.gz: ab80180d202b2f7ab15b956c86488b3aca4a90fe7aa5cfa5b75fe9438fd4d0d26a45f631e220b1baf73f63003f2c9f00fa70f6d4a9e9116f29a4919288e880ed
|
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# TSF.rb
|
2
|
+
Ruby parser for Trotect's TSF file format. The TSF file format is the main format of [Trotec's JobControl software](https://www.troteclaser.com/de/lasermaschinen/jobcontrol). JobControl is the key piece of software between a design in illustrator and a trotec laser machine. To create a TSF, you _print_ from design software to JobControl to generate a TSF with vector lines and bitmaps for cutting and engraving. Typically these files are only previewable by JobControl, making it difficult to share & reuse files within an organisation with confidence.
|
3
|
+
|
4
|
+
This Ruby Gem is used as an interface with the TSF file format to read metadata, bitmap, and polygon data, as well as generate previews of the files without the need for JobControl or design software.
|
5
|
+
|
6
|
+
# Get started
|
7
|
+
## Instalation
|
8
|
+
|
9
|
+
```bash
|
10
|
+
bundle install tsf
|
11
|
+
```
|
12
|
+
|
13
|
+
## How to use
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
require 'tsf'
|
17
|
+
|
18
|
+
data = File.read('to/your/file.tsf')
|
19
|
+
vector = TSF::Vector.load_tsf(data)
|
20
|
+
|
21
|
+
vector.loaded
|
22
|
+
# => True
|
23
|
+
```
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Converter
|
2
|
+
# Converts a TSF file to an image format (PNG, JPG, etc.)
|
3
|
+
class TsfToImage
|
4
|
+
def initialize(tsf_file_path)
|
5
|
+
@tsf_file_path = tsf_file_path
|
6
|
+
end
|
7
|
+
|
8
|
+
def convert_to_image(output_format)
|
9
|
+
# Logic to convert TSF to image
|
10
|
+
puts "Converting #{@tsf_file_path} to #{output_format}..."
|
11
|
+
# Conversion logic goes here
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Converter
|
2
|
+
# Converts a TSF file to an SVG format
|
3
|
+
class TsfToSvg
|
4
|
+
def initialize(tsf_file_path)
|
5
|
+
@tsf_file_path = tsf_file_path
|
6
|
+
end
|
7
|
+
|
8
|
+
def convert_to_svg
|
9
|
+
# Logic to convert TSF to SVG
|
10
|
+
puts "Converting #{@tsf_file_path} to SVG..."
|
11
|
+
# Conversion logic goes here
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
data/lib/tsf/vector.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
module Tsf
|
2
|
+
# Loads a TSF file and parses its content
|
3
|
+
class Vector
|
4
|
+
attr_reader :loaded, :grouped_data, :polygons, :headers
|
5
|
+
attr_reader :material_group, :material_name, :job_name, :job_number, :resolution, :size, :bitmap
|
6
|
+
|
7
|
+
# Initialize the Vector class
|
8
|
+
def initialize
|
9
|
+
@loaded = false
|
10
|
+
@grouped_data = nil
|
11
|
+
@polygons = []
|
12
|
+
@headers = []
|
13
|
+
|
14
|
+
## Header information. Deconstructed.
|
15
|
+
# Material settings for the job.
|
16
|
+
@material_group = nil
|
17
|
+
@material_name = nil
|
18
|
+
|
19
|
+
# Job name as set in the Trotec software.
|
20
|
+
@job_name = nil
|
21
|
+
@job_number = nil
|
22
|
+
|
23
|
+
# Usualy 500 DPI.
|
24
|
+
@resoultion = nil
|
25
|
+
# Will be set artboard size. when creating the tsf.
|
26
|
+
@size = nil
|
27
|
+
|
28
|
+
## Image Data
|
29
|
+
# Images in TSF files are stored as a monochrome bitmap.
|
30
|
+
# The bitmap is used to determine the engraving area.
|
31
|
+
# Image data, if present.
|
32
|
+
@bitmap = nil
|
33
|
+
|
34
|
+
#####
|
35
|
+
|
36
|
+
# Minimum required variables to be present in the TSF file.
|
37
|
+
# CamelCase
|
38
|
+
@min_vars = ['MaterialGroup', 'MaterialName', 'JobName', 'JobNumber', 'Resolution', 'Size']
|
39
|
+
end
|
40
|
+
|
41
|
+
# Data is the raw data from the TSF file.
|
42
|
+
# data = File.read('path/to/file.tsf')
|
43
|
+
def self.load_tsf(data)
|
44
|
+
vector = new
|
45
|
+
if data.is_a?(String)
|
46
|
+
|
47
|
+
# Check if the data is empty
|
48
|
+
if data.empty?
|
49
|
+
raise ArgumentError, "Data is empty. Please provide a valid TSF file."
|
50
|
+
end
|
51
|
+
|
52
|
+
# Parse vector data
|
53
|
+
vector.parse_tsf(data)
|
54
|
+
else
|
55
|
+
raise ArgumentError, "Expected a String, got #{data.class}"
|
56
|
+
end
|
57
|
+
vector
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
def parse_tsf(data)
|
62
|
+
# Tsf files are text formatted files that repsresnte vector paths for a Troctec laser to follow. Similar to that of Gcode.
|
63
|
+
# TSF file use a xml-like format the prefix "BegGroup" and "EndGroup" to denote the start and end of a group of commands or meta data.
|
64
|
+
# TSF files are structed it to 4 top level groups.
|
65
|
+
# - Header - Contains the header information of the file.
|
66
|
+
# - JobMeta - Contains meta data about the job, such as the name, date, and other information.
|
67
|
+
# - Bitmap - Contains the engraving data, such as the image to be engraved.
|
68
|
+
# - DrawCommands - Contains the vector data, such as the paths to be followed by the laser.
|
69
|
+
# - contains many "DrawPolygon" commands, which are the actual vector paths to be followed by the laser.
|
70
|
+
# - Each "DrawPolygon" command contains a list of points, which are the coordinates of the points to be followed by the laser. Delimtited by a ;.
|
71
|
+
# - The first 4 digits of the command contain, ID, then R,G,B color values of the Polygon.
|
72
|
+
|
73
|
+
@grouped_data = get_grouped_data(data)
|
74
|
+
|
75
|
+
# Check if the grouped data has the required groups
|
76
|
+
# A TSF file is not complete if it does not have a header and draw commands.
|
77
|
+
unless @grouped_data.key?('Header') || @grouped_data.key?('DrawCommands')
|
78
|
+
raise ArgumentError, "Invalid TSF data. Missing required groups core groups: Header, DrawCommands"
|
79
|
+
end
|
80
|
+
|
81
|
+
# Check if the grouped data has the required keys
|
82
|
+
missing_headers = @min_vars - @grouped_data['Header'].keys
|
83
|
+
if missing_headers.any?
|
84
|
+
raise ArgumentError, "Invalid TSF data. Missing required headers: #{missing_headers.join(', ')}"
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
@material_group = @grouped_data['Header']['MaterialGroup']
|
89
|
+
@material_name = @grouped_data['Header']['MaterialName']
|
90
|
+
|
91
|
+
@job_name = @grouped_data['Header']['JobName']
|
92
|
+
@job_number = @grouped_data['Header']['JobNumber']
|
93
|
+
|
94
|
+
@resolution = @grouped_data['Header']['Resolution'].to_i
|
95
|
+
@size = @grouped_data['Header']['Size'].split(";").map(&:to_f)
|
96
|
+
|
97
|
+
@polygons = get_polygons(@grouped_data)
|
98
|
+
|
99
|
+
@loaded = true
|
100
|
+
@grouped_data
|
101
|
+
end
|
102
|
+
|
103
|
+
def get_grouped_data(data)
|
104
|
+
# Groups are delimited by the "BegGroup" and "EndGroup" tags.
|
105
|
+
# Each group contains a list of commands or meta data.
|
106
|
+
# The normal groups are:
|
107
|
+
# - Header
|
108
|
+
# - JobMeta
|
109
|
+
# - Bitmap (optional)
|
110
|
+
# - DrawCommands
|
111
|
+
|
112
|
+
# Auto create nested hash when accessed.
|
113
|
+
nested_group_and_values = Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) }
|
114
|
+
# Typically, we only get 2 levels of groups. But we can have more.
|
115
|
+
current_groups = []
|
116
|
+
|
117
|
+
data.split("\n").each do |line|
|
118
|
+
# a line is a command and a value. ie. <JobNumber: 1234> or <DrawPolygon: 12;0;1;2;3>
|
119
|
+
# a line can define a group where value is the group name. ie. <BegGroup: Header> <EndGroup: Header>
|
120
|
+
# groups can have groups (max 2.)
|
121
|
+
# groups can have multple commands.
|
122
|
+
# a command has only one value.
|
123
|
+
|
124
|
+
command, value = line.split(":").map(&:strip).map { |s| s.gsub(/<|>/, '') }
|
125
|
+
|
126
|
+
case command
|
127
|
+
when "BegGroup"
|
128
|
+
# Start a new group
|
129
|
+
current_groups << value
|
130
|
+
when "EndGroup"
|
131
|
+
# End the current group
|
132
|
+
current_groups.pop
|
133
|
+
else
|
134
|
+
# Assign the command and value to the appropriate group
|
135
|
+
if current_groups.any?
|
136
|
+
current = nested_group_and_values.dig(*current_groups)
|
137
|
+
current[command] = value
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
nested_group_and_values
|
143
|
+
end
|
144
|
+
|
145
|
+
def get_polygons(grouped_data)
|
146
|
+
polygons = []
|
147
|
+
grouped_data['DrawCommands'].each do |key, value|
|
148
|
+
polygon_string = value['DrawPolygon']
|
149
|
+
polygon_array = polygon_string.split(";")
|
150
|
+
|
151
|
+
polygon = {
|
152
|
+
'id': polygon_array[0].to_i,
|
153
|
+
'color': {
|
154
|
+
'r': polygon_array[1].to_i,
|
155
|
+
'g': polygon_array[2].to_i,
|
156
|
+
'b': polygon_array[3].to_i,
|
157
|
+
},
|
158
|
+
'points': []
|
159
|
+
}
|
160
|
+
|
161
|
+
polygon[:data] = polygon_array.drop(4).map(&:to_i).each_slice(2).to_a
|
162
|
+
|
163
|
+
polygons << polygon
|
164
|
+
end
|
165
|
+
polygons
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
data/lib/tsf/version.rb
ADDED
data/lib/tsf.rb
ADDED
metadata
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tsf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Isaac Bonora
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-04-14 00:00:00.000000000 Z
|
11
|
+
dependencies: []
|
12
|
+
description: Ruby parser for Trotec's TSF file format.
|
13
|
+
email: isaac@isbonora.com
|
14
|
+
executables: []
|
15
|
+
extensions: []
|
16
|
+
extra_rdoc_files: []
|
17
|
+
files:
|
18
|
+
- README.md
|
19
|
+
- lib/tsf.rb
|
20
|
+
- lib/tsf/convert/tsf_to_image.rb
|
21
|
+
- lib/tsf/convert/tsf_to_svg.rb
|
22
|
+
- lib/tsf/vector.rb
|
23
|
+
- lib/tsf/version.rb
|
24
|
+
homepage: https://rubygems.org/gems/tsfrb
|
25
|
+
licenses:
|
26
|
+
- MIT
|
27
|
+
metadata: {}
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
requirements: []
|
42
|
+
rubygems_version: 3.6.6
|
43
|
+
specification_version: 4
|
44
|
+
summary: Ruby parser for Trotec's TSF file format.
|
45
|
+
test_files: []
|