svgr 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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"