svgr 0.1.0 → 0.1.1

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: d224bf9a5fc726732a3fc41025e5e427b854e64af0e98b885dfa07463b8f3163
4
- data.tar.gz: 50ab5833da2e78c564b801297d366807e28bd158029bc311753cf54efde76245
3
+ metadata.gz: 8120b4e3800cf5e6b972772814871defb5cc36bc37cb5c87492c28d821716c4e
4
+ data.tar.gz: be6890776b2bd151022c43965a12ecffa37cf343fd854a997f74a0132f08c20d
5
5
  SHA512:
6
- metadata.gz: 90ff675a77946193b6065b75346748f7b12fde67753ef4d516e8cfc152c20a198a04ac9cd54b07cf62f9dc86f1e0e8e3a70d033844d15bceed36884da57697bb
7
- data.tar.gz: cda5463648daf778a6e1dc9e2f11bf2b993f3ea96c63fdfbff6c0ea013d0f953fc4a6e1642ee50c491e4cde42a5798c2487d9ff1d3632798552714b0c5156940
6
+ metadata.gz: a2d8713feca84a423e47b5a36d086cf4a2b96a0c91f688378950153153da183f15ca0d0f84882d498a56a3632ee0b27b8e960430e73fcc09a68b598b707144b3
7
+ data.tar.gz: d041e160dd9dcaacec52b425f84e9086990fa4307bda054e44398ea31fb6e8923d5d9ba0d3c101eca4cf2ebbeb33413ba87c77eb693d806793d21b524f849bd4
data/bin/svgr CHANGED
@@ -1,15 +1,50 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require_relative '../lib/svgr'
4
-
5
- # The first command-line argument will be the subcommand (e.g., "combine")
6
- subcommand = ARGV.shift
7
-
8
- case subcommand
9
- when 'combine'
10
- Svgr::CombineSvgs.start(ARGV)
11
- else
12
- puts "Unknown subcommand: #{subcommand}"
13
- puts "Usage: svgr combine <source_directory> <output_file> <rows> <columns> [options]"
14
- exit(1)
15
- end
3
+ require "optparse"
4
+ require_relative "../lib/svgr/arrange_grid"
5
+ require_relative "../lib/svgr/document_resize"
6
+
7
+ module Svgr
8
+ def self.start(argv)
9
+ global_opts = {}
10
+
11
+ subcommands = {
12
+ "arrange:grid" => ->(args) { Svgr::ArrangeGrid.start(args) },
13
+ "document:resize" => ->(args) { Svgr::DocumentResize.start(args) },
14
+ }
15
+
16
+ opt_parser = OptionParser.new do |opts|
17
+ opts.banner = "Usage: svgr [options] <subcommand>"
18
+
19
+ opts.separator ""
20
+ opts.separator "Subcommands:"
21
+ subcommands.each do |name, _|
22
+ opts.separator " #{name}"
23
+ end
24
+
25
+ opts.separator ""
26
+ opts.separator "Global options:"
27
+
28
+ opts.on("-h", "--help", "Prints this help") do
29
+ puts opts
30
+ exit
31
+ end
32
+ end
33
+
34
+ opt_parser.order!(argv)
35
+
36
+ if argv.empty?
37
+ puts opt_parser
38
+ exit(1)
39
+ end
40
+
41
+ subcommand = argv.shift
42
+ subcommands.fetch(subcommand).call(argv)
43
+ rescue KeyError
44
+ puts "Error: Unknown subcommand '#{subcommand}'"
45
+ puts opt_parser
46
+ exit(1)
47
+ end
48
+ end
49
+
50
+ Svgr.start(ARGV)
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "nokogiri"
4
+ require "optparse"
5
+
6
+ module Svgr
7
+ class ArrangeGrid
8
+ class << self
9
+ def start(argv)
10
+ options = {
11
+ scaling_factor: 1,
12
+ margin_top: 0,
13
+ margin_left: 0,
14
+ sort: "default",
15
+ }
16
+
17
+ opt_parser =
18
+ OptionParser.new do |opts|
19
+ opts.banner =
20
+ "Usage: svgr arrange:grid [options] <source_directory> <rows> <columns>"
21
+
22
+ opts.on(
23
+ "-s",
24
+ "--scaling-factor FACTOR",
25
+ Float,
26
+ "Scaling factor for the SVG elements",
27
+ ) { |s| options[:scaling_factor] = s }
28
+
29
+ opts.on(
30
+ "-t",
31
+ "--margin-top MARGIN",
32
+ Integer,
33
+ "Top margin between the SVG elements",
34
+ ) { |t| options[:margin_top] = t }
35
+
36
+ opts.on(
37
+ "-l",
38
+ "--margin-left MARGIN",
39
+ Integer,
40
+ "Left margin between the SVG elements",
41
+ ) { |l| options[:margin_left] = l }
42
+
43
+ opts.on(
44
+ "--sort SORT",
45
+ ["default", "random"],
46
+ "Sorting option for the SVG files (default, random)",
47
+ ) { |sort| options[:sort] = sort }
48
+
49
+ opts.on("--out FILE", "Specify an output file path") do |file|
50
+ options[:out] = file
51
+ end
52
+
53
+ opts.on("-h", "--help", "Prints this help") do
54
+ puts opts
55
+ exit
56
+ end
57
+ end
58
+ opt_parser.parse!(argv)
59
+
60
+ if argv.length < 3
61
+ puts opt_parser.help
62
+ exit(1)
63
+ end
64
+
65
+ source_directory, rows, columns = argv.shift(3)
66
+ rows = rows.to_i
67
+ columns = columns.to_i
68
+ svg_files =
69
+ list_svg_files(source_directory, options[:sort])[0...rows * columns]
70
+
71
+ combined_elements =
72
+ svg_files.flat_map do |file|
73
+ content = read_svg_file(file)
74
+ extract_svg_elements(content)
75
+ end
76
+
77
+ combined_svg = create_combined_svg(
78
+ combined_elements,
79
+ rows,
80
+ columns,
81
+ options[:scaling_factor],
82
+ margin: { top: options[:margin_top], left: options[:margin_left] },
83
+ )
84
+
85
+ write_svg(combined_svg, options[:out])
86
+ end
87
+
88
+ def list_svg_files(directory, sort_option)
89
+ svg_files = Dir.glob(File.join(directory, "*.svg"))
90
+
91
+ case sort_option
92
+ when "default"
93
+ svg_files.sort_by { |file| File.basename(file, ".svg").to_i }
94
+ when "random"
95
+ svg_files.shuffle
96
+ else
97
+ puts "Invalid sorting option. Allowed options: default, random"
98
+ exit(1)
99
+ end
100
+ end
101
+
102
+ def read_svg_file(file)
103
+ File.read(file)
104
+ end
105
+
106
+ def extract_svg_elements(svg_content)
107
+ doc = Nokogiri.XML(svg_content)
108
+ doc.remove_namespaces!
109
+ top_level_groups = doc.xpath("//svg/g")
110
+
111
+ if top_level_groups.empty?
112
+ # Wrap all child elements of the SVG document in a group
113
+ svg_element = doc.at_xpath("//svg")
114
+ new_group = Nokogiri::XML::Node.new("g", doc)
115
+
116
+ svg_element.children.each { |child| new_group.add_child(child) }
117
+
118
+ svg_element.add_child(new_group)
119
+ top_level_groups = [new_group]
120
+ end
121
+
122
+ top_level_groups
123
+ end
124
+
125
+ def create_combined_svg(
126
+ elements,
127
+ rows,
128
+ columns,
129
+ scaling_factor,
130
+ margin: {}
131
+ )
132
+ margin_top = margin.fetch(:top, 0)
133
+ margin_left = margin.fetch(:left, 0)
134
+
135
+ width =
136
+ columns * 100 * scaling_factor +
137
+ (columns - 1) * margin_left * scaling_factor
138
+ height =
139
+ rows * 100 * scaling_factor + (rows - 1) * margin_top * scaling_factor
140
+
141
+ combined_svg =
142
+ Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
143
+ xml.svg(
144
+ xmlns: "http://www.w3.org/2000/svg",
145
+ width: width,
146
+ height: height,
147
+ ) do
148
+ elements.each_with_index do |element, index|
149
+ row = index / columns
150
+ col = index % columns
151
+
152
+ # Adjust the 'transform' attribute to position and scale the element in the grid
153
+ x =
154
+ col * (100 * scaling_factor + margin_left * scaling_factor) +
155
+ (width - 100 * scaling_factor) / 2
156
+ y = row * (100 * scaling_factor + margin_top * scaling_factor)
157
+
158
+ # Offset by half the size of the element vertically and horizontally
159
+ x += 50 * scaling_factor
160
+ y += 50 * scaling_factor
161
+
162
+ transform = "translate(#{x}, #{y}) scale(#{scaling_factor})"
163
+ element["transform"] = transform
164
+ xml << element.to_xml
165
+ end
166
+ end
167
+ end
168
+ combined_svg.to_xml
169
+ end
170
+
171
+ def write_svg(svg, output_file = nil)
172
+ if output_file
173
+ File.write(output_file, svg)
174
+ else
175
+ puts svg
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "nokogiri"
4
+ require "optparse"
5
+
6
+ module Svgr
7
+ class DocumentResize
8
+ class << self
9
+ def start(argv)
10
+ options = {}
11
+ parser = OptionParser.new do |opts|
12
+ opts.banner = "Usage: svgr document:resize <width> <height> [--in INPUT_FILE] [--out OUTPUT_FILE]"
13
+
14
+ opts.on("--in INPUT_FILE", "Specify the input file path") do |input_file|
15
+ options[:input_file] = input_file
16
+ end
17
+
18
+ opts.on("--out OUTPUT_FILE", "Specify the output file path") do |output_file|
19
+ options[:output_file] = output_file
20
+ end
21
+
22
+ opts.on("-h", "--help", "Prints this help") do
23
+ puts opts
24
+ exit
25
+ end
26
+ end
27
+ parser.parse!(argv)
28
+
29
+ if argv.size < 2
30
+ puts parser.help
31
+ exit(1)
32
+ end
33
+
34
+ width = argv[0].to_f
35
+ height = argv[1].to_f
36
+
37
+ input_file = options[:input_file]
38
+ output_file = options[:output_file]
39
+
40
+ svg_content = if input_file
41
+ File.read(input_file)
42
+ else
43
+ $stdin.read
44
+ end
45
+
46
+ resized_svg = resize(svg_content, width, height, input_file, output_file)
47
+
48
+ # Write the output
49
+ output = resized_svg.to_xml
50
+ if output_file
51
+ File.write(output_file, output)
52
+ else
53
+ puts output
54
+ end
55
+ end
56
+
57
+ def resize(content, width, height, input_file, output_file)
58
+ doc = Nokogiri.XML(content)
59
+ doc.remove_namespaces!
60
+ svg_element = doc.at_xpath("/svg")
61
+
62
+ # Get the original SVG width and height
63
+ svg_width = svg_element["width"].to_i
64
+ svg_height = svg_element["height"].to_i
65
+
66
+ # Calculate width and height in pixels using a DPI of 96
67
+ width_px = (width * 96 / 25.4).round
68
+ height_px = (height * 96 / 25.4).round
69
+
70
+ # Calculate the difference between the new width and height and the original width and height
71
+ width_diff = (width_px - svg_width) / 2
72
+ height_diff = (height_px - svg_height) / 2
73
+
74
+ # Update the width and height attributes of the SVG element
75
+ svg_element["width"] = width_px
76
+ svg_element["height"] = height_px
77
+
78
+ # Create a new group element to wrap all the existing elements and apply the translation
79
+ new_group = Nokogiri::XML::Node.new("g", doc)
80
+ new_group["transform"] = "translate(#{width_diff}, #{height_diff})"
81
+ svg_element.children.each do |child|
82
+ new_group.add_child(child)
83
+ end
84
+ svg_element.add_child(new_group)
85
+
86
+ doc
87
+ end
88
+ end
89
+ end
90
+ end
metadata CHANGED
@@ -1,29 +1,85 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: svgr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nassredean Nasseri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-04-05 00:00:00.000000000 Z
11
+ date: 2023-04-08 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop-rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop-shopify
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2'
13
69
  - !ruby/object:Gem::Dependency
14
70
  name: nokogiri
15
71
  requirement: !ruby/object:Gem::Requirement
16
72
  requirements:
17
73
  - - "~>"
18
74
  - !ruby/object:Gem::Version
19
- version: '1.12'
75
+ version: '1'
20
76
  type: :runtime
21
77
  prerelease: false
22
78
  version_requirements: !ruby/object:Gem::Requirement
23
79
  requirements:
24
80
  - - "~>"
25
81
  - !ruby/object:Gem::Version
26
- version: '1.12'
82
+ version: '1'
27
83
  description: A Ruby gem that provides a command-line interface for various SVG utilities
28
84
  email:
29
85
  executables:
@@ -32,10 +88,8 @@ extensions: []
32
88
  extra_rdoc_files: []
33
89
  files:
34
90
  - bin/svgr
35
- - lib/svgr.rb
36
- - lib/svgr/combine_svgs.rb
37
- - lib/svgr/count_files_by_type.rb
38
- - lib/svgr/delete_files_by_type.rb
91
+ - lib/svgr/arrange_grid.rb
92
+ - lib/svgr/document_resize.rb
39
93
  homepage: https://github.com/nassredean/svgr
40
94
  licenses:
41
95
  - MIT
@@ -1,132 +0,0 @@
1
- require "nokogiri"
2
- require "optparse"
3
-
4
- module Svgr
5
- class CombineSvgs
6
- def self.start(argv)
7
- options = {
8
- scaling_factor: 1,
9
- margin_top: 0,
10
- margin_left: 0,
11
- sort: "default"
12
- }
13
-
14
- OptionParser
15
- .new do |opts|
16
- opts.banner =
17
- "Usage: svgr combine [options] <source_directory> <output_file> <rows> <columns>"
18
-
19
- opts.on(
20
- "-s",
21
- "--scaling-factor FACTOR",
22
- Float,
23
- "Scaling factor for the SVG elements"
24
- ) { |s| options[:scaling_factor] = s }
25
-
26
- opts.on(
27
- "-t",
28
- "--margin-top MARGIN",
29
- Integer,
30
- "Top margin between the SVG elements"
31
- ) { |t| options[:margin_top] = t }
32
-
33
- opts.on(
34
- "-l",
35
- "--margin-left MARGIN",
36
- Integer,
37
- "Left margin between the SVG elements"
38
- ) { |l| options[:margin_left] = l }
39
-
40
- opts.on(
41
- "--sort SORT",
42
- %w[default random],
43
- "Sorting option for the SVG files (default, random)"
44
- ) { |sort| options[:sort] = sort }
45
- end
46
- .parse!(argv)
47
-
48
- if argv.length < 4
49
- puts "Usage: svgr combine [options] <source_directory> <output_file> <rows> <columns>"
50
- exit(1)
51
- end
52
-
53
- source_directory, output_file, rows, columns = argv.shift(4)
54
- rows = rows.to_i
55
- columns = columns.to_i
56
- svg_files =
57
- list_svg_files(source_directory, options[:sort])[0...rows * columns]
58
-
59
- combined_elements =
60
- svg_files.flat_map do |file|
61
- content = read_svg_file(file)
62
- extract_svg_elements(content)
63
- end
64
-
65
- combined_svg =
66
- create_combined_svg(
67
- combined_elements,
68
- rows,
69
- columns,
70
- options[:scaling_factor],
71
- options[:margin_top],
72
- options[:margin_left]
73
- )
74
-
75
- save_svg_to_file(combined_svg, output_file)
76
- end
77
-
78
- def self.list_svg_files(directory, sort_option)
79
- svg_files = Dir.glob(File.join(directory, "*.svg"))
80
-
81
- case sort_option
82
- when "default"
83
- svg_files.sort_by { |file| File.basename(file, ".svg").to_i }
84
- when "random"
85
- svg_files.shuffle
86
- else
87
- puts "Invalid sorting option. Allowed options: default, random"
88
- exit(1)
89
- end
90
- end
91
-
92
- def self.read_svg_file(file)
93
- File.read(file)
94
- end
95
-
96
- def self.extract_svg_elements(svg_content)
97
- doc = Nokogiri.XML(svg_content)
98
- doc.remove_namespaces!
99
- doc.xpath("//svg/g")
100
- end
101
-
102
- def self.create_combined_svg(
103
- elements,
104
- rows,
105
- columns,
106
- scaling_factor,
107
- margin_top,
108
- margin_left
109
- )
110
- combined_svg =
111
- Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
112
- xml.svg(xmlns: "http://www.w3.org/2000/svg") do
113
- elements.each_with_index do |element, index|
114
- row = index / columns
115
- col = index % columns
116
-
117
- # Adjust the 'transform' attribute to position and scale the element in the grid
118
- transform =
119
- "translate(#{col * (100 + margin_left) * scaling_factor}, #{row * (100 + margin_top) * scaling_factor}) scale(#{scaling_factor})"
120
- element["transform"] = transform
121
- xml << element.to_xml
122
- end
123
- end
124
- end
125
- combined_svg.to_xml
126
- end
127
-
128
- def self.save_svg_to_file(svg, file)
129
- File.write(file, svg)
130
- end
131
- end
132
- end
@@ -1,14 +0,0 @@
1
- def count_files_by_type(directory, file_extension)
2
- Dir.glob(File.join(directory, "*.#{file_extension}")).count
3
- end
4
-
5
- if ARGV.length != 2
6
- puts "Usage: ruby count_files_by_type.rb <source_directory> <file_extension>"
7
- exit(1)
8
- end
9
-
10
- source_directory = ARGV[0]
11
- file_extension = ARGV[1]
12
- file_count = count_files_by_type(source_directory, file_extension)
13
-
14
- puts "Number of #{file_extension.upcase} files in #{source_directory}: #{file_count}"
@@ -1,32 +0,0 @@
1
- require "fileutils"
2
-
3
- def get_files_by_type(directory, file_extension)
4
- Dir
5
- .glob(File.join(directory, "*.#{file_extension}"))
6
- .sort_by { |f| File.basename(f).to_i }
7
- end
8
-
9
- def delete_file(file)
10
- File.delete(file)
11
- end
12
-
13
- if ARGV.length != 2
14
- puts "Usage: ruby delete_files_by_type.rb <source_directory> <file_extension>"
15
- exit(1)
16
- end
17
-
18
- source_directory = ARGV[0]
19
- file_extension = ARGV[1]
20
-
21
- files = get_files_by_type(source_directory, file_extension)
22
-
23
- files.each do |file|
24
- puts "File: #{file}"
25
- print "Do you want to delete this file? [y/N]: "
26
- answer = STDIN.gets.chomp.downcase
27
-
28
- if answer == "y"
29
- delete_file(file)
30
- puts "Deleted #{file}"
31
- end
32
- end
data/lib/svgr.rb DELETED
@@ -1 +0,0 @@
1
- require_relative "svgr/combine_svgs"