tileset_tooling 0.0.2 → 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 +4 -4
- data/.gitignore +1 -1
- data/.rubocop.yml +3 -0
- data/Gemfile.lock +1 -1
- data/README.rdoc +2 -1
- data/features/insert_bleed.feature +2 -2
- data/lib/tileset_tooling/app.rb +4 -1
- data/lib/tileset_tooling/commands/insert_bleed.rb +83 -63
- data/lib/tileset_tooling/data.rb +3 -0
- data/lib/tileset_tooling/data/point.rb +8 -0
- data/lib/tileset_tooling/data/tile.rb +9 -4
- data/lib/tileset_tooling/data/tileset.rb +41 -23
- data/lib/tileset_tooling/utils.rb +4 -21
- data/lib/tileset_tooling/utils/common.rb +36 -0
- data/lib/tileset_tooling/utils/specs_loader.rb +65 -0
- data/lib/tileset_tooling/version.rb +1 -1
- data/test/commands/insert_bleed_test.rb +23 -13
- data/test/data/expected/simple_no_margin.png +0 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c708dba05b753997be72b94e89172f4f6dc0388a561ed9af27cd5136ef63371e
|
4
|
+
data.tar.gz: 013ff8cd539154a20637eb14ef2b4eae9c831301a31a87d3c999ffb27eb65a89
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c1e7efa99996036fb4c801d626ef7d5662f896d60908e79864214f533fac0406b5d29d06c756c5ba79686c8498d9ff7d66603aea862b38e0409dfa67074c958
|
7
|
+
data.tar.gz: 513fdaad596bfe275002fa6008a4018cbbdfd70c4e62145ebc4ba550f6d81d0e41f126b63887df4b87c12c7dea3b33bcf86b887441bb108dc2bb3051593b8d35
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
= tileset_tooling
|
2
2
|
|
3
3
|
{<img src="https://github.com/calestar/tileset_tooling/workflows/Ruby/badge.svg?branch=master" alt="Build Status" />}[https://github.com/calestar/tileset_tooling/actions?query=workflow%3ARuby]
|
4
|
-
{<img src="https://
|
4
|
+
{<img src="https://badgen.net/rubygems/dt/tileset_tooling" alt="Number of downloads" />}[https://rubygems.org/gems/tileset_tooling]
|
5
|
+
{<img src="https://badge.fury.io/rb/tileset_tooling.svg" alt="Gem Version" />}[https://badge.fury.io/rb/tileset_tooling]
|
5
6
|
|
6
7
|
Bits of tooling I use for working with tilesets.
|
7
8
|
|
@@ -13,8 +13,8 @@ Feature: App inserts bleed correctly
|
|
13
13
|
Then I type "0"
|
14
14
|
Then I type "0"
|
15
15
|
Then I type "0"
|
16
|
-
Then the exit status should be
|
17
|
-
Then
|
16
|
+
Then the exit status should be 0
|
17
|
+
Then generated file should be the same as data result "simple_no_margin.png"
|
18
18
|
|
19
19
|
Scenario: Insert bleed generate default output
|
20
20
|
When I insert bleed to test data "simple_with_margin.png"
|
data/lib/tileset_tooling/app.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'gli'
|
5
|
+
require 'mini_magick'
|
5
6
|
require 'semantic_logger'
|
6
7
|
|
7
8
|
require 'tileset_tooling/version'
|
@@ -29,6 +30,7 @@ class ::TilesetTooling::App
|
|
29
30
|
::SemanticLogger.default_level = :trace
|
30
31
|
::SemanticLogger.add_appender(io: $stdout, formatter: :color)
|
31
32
|
|
33
|
+
# ::MiniMagick.logger.level = ::Logger::DEBUG
|
32
34
|
true
|
33
35
|
end
|
34
36
|
|
@@ -49,7 +51,8 @@ class ::TilesetTooling::App
|
|
49
51
|
insert_command.switch([:'skip-specs'], desc: 'Skips the reading of the specs')
|
50
52
|
insert_command.flag([:output], default_value: nil, desc: 'Path where to store result', arg_name: 'path')
|
51
53
|
insert_command.action do |_, options, args|
|
52
|
-
|
54
|
+
specs_loader = ::TilesetTooling::Utils::SpecsLoader.new
|
55
|
+
command = ::TilesetTooling::Commands::InsertBleed.new(options, args, specs_loader)
|
53
56
|
command.unpack!
|
54
57
|
command.run
|
55
58
|
end
|
@@ -2,11 +2,18 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'tileset_tooling/data'
|
5
|
+
require 'tileset_tooling/utils'
|
5
6
|
|
6
7
|
require 'yaml'
|
7
8
|
|
8
9
|
# Command used to insert bleed around tiles
|
9
10
|
class ::TilesetTooling::Commands::InsertBleed < ::TilesetTooling::Commands::Command
|
11
|
+
# Constructor, initializes a few internal
|
12
|
+
def initialize(options, args, specs_loader)
|
13
|
+
@specs_loader = specs_loader
|
14
|
+
super(options, args)
|
15
|
+
end
|
16
|
+
|
10
17
|
# Validates arguments/options and unpacks them
|
11
18
|
def unpack!
|
12
19
|
raise(::StandardError, 'Missing argument') unless @args.count == 1
|
@@ -21,27 +28,56 @@ class ::TilesetTooling::Commands::InsertBleed < ::TilesetTooling::Commands::Comm
|
|
21
28
|
@logger.info("Adding bleed to tiles in image file '#{@image_path}'")
|
22
29
|
tileset = gather_image_information
|
23
30
|
|
24
|
-
|
31
|
+
if tileset.margin.positive?
|
32
|
+
modify_margin(tileset)
|
33
|
+
else
|
34
|
+
add_margin(tileset)
|
35
|
+
end
|
36
|
+
|
37
|
+
@logger.info("Result stored in '#{result_path}'")
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
25
41
|
|
42
|
+
def modify_margin(tileset)
|
26
43
|
::MiniMagick::Tool::Convert.new do |convert|
|
27
44
|
convert.background('none')
|
28
45
|
convert << tileset.original_image_path
|
29
46
|
|
30
47
|
tileset.for_each_tile do |tile|
|
31
|
-
|
32
|
-
copy_rect(convert, tile.left, tile.bottom - 1, 1, tile.width, tile.left, tile.bottom) unless tile.bottom >= tileset.height
|
33
|
-
copy_rect(convert, tile.left, tile.top, tile.height, 1, tile.left - 1, tile.top) unless tile.left <= 0
|
34
|
-
copy_rect(convert, tile.right - 1, tile.top, tile.height, 1, tile.right, tile.top) unless tile.right >= tileset.width
|
48
|
+
generate_bleed(convert, tileset, tile)
|
35
49
|
end
|
36
50
|
|
37
51
|
convert.flatten
|
38
52
|
convert << result_path
|
39
53
|
end
|
40
|
-
|
41
|
-
@logger.info("Result stored in '#{result_path}'")
|
42
54
|
end
|
43
55
|
|
44
|
-
|
56
|
+
def add_margin(tileset)
|
57
|
+
nb_pixels_in_bleed = 1
|
58
|
+
new_tileset = ::TilesetTooling::Utils.tileset_with_margin_from(tileset, nb_pixels_in_bleed)
|
59
|
+
image_path = tileset.original_image_path
|
60
|
+
|
61
|
+
::MiniMagick::Tool::Convert.new do |convert|
|
62
|
+
convert.background('none')
|
63
|
+
|
64
|
+
# Copy the original and resize so that we keep all the image specs
|
65
|
+
convert << image_path
|
66
|
+
convert.resize("#{new_tileset.width}x#{new_tileset.height}!")
|
67
|
+
convert.fill('white').draw("rectangle 0,0 #{new_tileset.width},#{new_tileset.height}").transparent('white')
|
68
|
+
convert.compose('Over')
|
69
|
+
|
70
|
+
# Copy tiles and bled
|
71
|
+
tileset.for_each_tile do |tile|
|
72
|
+
dest = new_tileset.tile_at(tile.row_index, tile.column_index)
|
73
|
+
copy_tile(convert, image_path, tile, dest)
|
74
|
+
generate_bleed(convert, tileset, tile, destination: dest, image_path: image_path)
|
75
|
+
end
|
76
|
+
|
77
|
+
convert.flatten
|
78
|
+
convert << result_path
|
79
|
+
end
|
80
|
+
end
|
45
81
|
|
46
82
|
def result_path
|
47
83
|
return @options[:output] if @options[:output]
|
@@ -53,55 +89,10 @@ class ::TilesetTooling::Commands::InsertBleed < ::TilesetTooling::Commands::Comm
|
|
53
89
|
"#{directory}/#{file_name}_result#{extension}"
|
54
90
|
end
|
55
91
|
|
56
|
-
def ask_specs
|
57
|
-
tile_height =
|
58
|
-
@cli.ask('Tile height? ', ::Integer) do |q|
|
59
|
-
q.default = 0
|
60
|
-
q.in = 1..256
|
61
|
-
end
|
62
|
-
tile_width =
|
63
|
-
@cli.ask('Tile width? ', ::Integer) do |q|
|
64
|
-
q.default = 0
|
65
|
-
q.in = 1..256
|
66
|
-
end
|
67
|
-
margin = @cli.ask('Margin? ', ::Integer) { |q| q.default = 0 }
|
68
|
-
offset_top = @cli.ask('Top Offset? ', ::Integer) { |q| q.default = 0 }
|
69
|
-
offset_left = @cli.ask('Left Offset? ', ::Integer) { |q| q.default = 0 }
|
70
|
-
|
71
|
-
[tile_height, tile_width, margin, offset_top, offset_left]
|
72
|
-
end
|
73
|
-
|
74
|
-
def load_specs_from_file(file_path)
|
75
|
-
@logger.info("Extracting specs from '#{file_path}'")
|
76
|
-
specs = ::YAML.load_file(file_path)
|
77
|
-
|
78
|
-
begin
|
79
|
-
tile_height = specs['specs']['details']['tile_height']
|
80
|
-
tile_width = specs['specs']['details']['tile_width']
|
81
|
-
margin = specs['specs']['details']['margin']
|
82
|
-
offset_top = specs['specs']['details']['offset_top']
|
83
|
-
offset_left = specs['specs']['details']['offset_left']
|
84
|
-
rescue ::NoMethodError
|
85
|
-
raise(::StandardError, 'Invalid specs file')
|
86
|
-
end
|
87
|
-
[tile_height, tile_width, margin, offset_top, offset_left]
|
88
|
-
end
|
89
|
-
|
90
|
-
def find_specs
|
91
|
-
specs_file = ::TilesetTooling::Utils.image_spec_file_path(@image_path)
|
92
|
-
if !@options[:'skip-specs'] && ::File.exist?(specs_file)
|
93
|
-
tile_height, tile_width, margin, offset_top, offset_left = load_specs_from_file(specs_file)
|
94
|
-
else
|
95
|
-
tile_height, tile_width, margin, offset_top, offset_left = ask_specs
|
96
|
-
end
|
97
|
-
[tile_height, tile_width, margin, offset_top, offset_left]
|
98
|
-
end
|
99
|
-
|
100
|
-
# Asks for information about the image and build a tileset
|
101
92
|
def gather_image_information
|
102
|
-
tile_height, tile_width, margin, offset_top, offset_left =
|
93
|
+
tile_height, tile_width, margin, offset_top, offset_left = @specs_loader.find_specs_for(@image_path, @options[:'skip-specs'])
|
103
94
|
|
104
|
-
::TilesetTooling::Data::
|
95
|
+
::TilesetTooling::Data::FileTileSet.new(
|
105
96
|
image: ::MiniMagick::Image.open(@image_path),
|
106
97
|
original_image_path: @image_path,
|
107
98
|
tile_height: tile_height,
|
@@ -112,15 +103,44 @@ class ::TilesetTooling::Commands::InsertBleed < ::TilesetTooling::Commands::Comm
|
|
112
103
|
)
|
113
104
|
end
|
114
105
|
|
115
|
-
def copy_rect(convert,
|
116
|
-
# convert image \( +clone -crop WxH+X1+Y1 +repage \) -geometry +X2+Y2 -compose over -composite result
|
106
|
+
def copy_rect(convert, width, height, source, destination, image_path: nil)
|
117
107
|
convert.stack do |stack|
|
118
|
-
|
119
|
-
|
120
|
-
|
108
|
+
if image_path.nil?
|
109
|
+
stack.clone.+
|
110
|
+
else
|
111
|
+
stack << image_path
|
112
|
+
end
|
113
|
+
stack.crop("#{width}x#{height}+#{source.x}+#{source.y}").repage.+
|
121
114
|
end
|
122
|
-
convert.geometry("+#{
|
123
|
-
convert.compose('Over')
|
124
|
-
|
115
|
+
convert.geometry("+#{destination.x}+#{destination.y}")
|
116
|
+
convert.compose('Over').composite
|
117
|
+
end
|
118
|
+
|
119
|
+
def copy_tile(convert, image_path, source, destination)
|
120
|
+
copy_rect(convert, source.width, source.height, source.top_left, destination.top_left, image_path: image_path)
|
121
|
+
end
|
122
|
+
|
123
|
+
def generate_bleed(convert, tileset, source, destination: nil, image_path: nil)
|
124
|
+
destination = source if destination.nil?
|
125
|
+
|
126
|
+
# Top
|
127
|
+
source_coord = ::TilesetTooling::Data::Point.new(x: source.left, y: source.top)
|
128
|
+
dest_coord = ::TilesetTooling::Data::Point.new(x: destination.left, y: destination.top - 1)
|
129
|
+
copy_rect(convert, source.width, 1, source_coord, dest_coord, image_path: image_path) unless source.top <= 0
|
130
|
+
|
131
|
+
# Bottom
|
132
|
+
source_coord = ::TilesetTooling::Data::Point.new(x: source.left, y: source.bottom - 1)
|
133
|
+
dest_coord = ::TilesetTooling::Data::Point.new(x: destination.left, y: destination.bottom)
|
134
|
+
copy_rect(convert, source.width, 1, source_coord, dest_coord, image_path: image_path) unless source.bottom >= tileset.height
|
135
|
+
|
136
|
+
# Left
|
137
|
+
source_coord = ::TilesetTooling::Data::Point.new(x: source.left, y: source.top)
|
138
|
+
dest_coord = ::TilesetTooling::Data::Point.new(x: destination.left - 1, y: destination.top)
|
139
|
+
copy_rect(convert, 1, source.height, source_coord, dest_coord, image_path: image_path) unless source.left <= 0
|
140
|
+
|
141
|
+
# Right
|
142
|
+
source_coord = ::TilesetTooling::Data::Point.new(x: source.right - 1, y: source.top)
|
143
|
+
dest_coord = ::TilesetTooling::Data::Point.new(x: destination.right, y: destination.top)
|
144
|
+
copy_rect(convert, 1, source.height, source_coord, dest_coord, image_path: image_path) unless source.right >= tileset.width
|
125
145
|
end
|
126
146
|
end
|
data/lib/tileset_tooling/data.rb
CHANGED
@@ -0,0 +1,8 @@
|
|
1
|
+
# Copyright (c) 2020 Jean-Sebastien Gelinas, see LICENSE.txt
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Simple structure to represent a point (X,Y)
|
5
|
+
class ::TilesetTooling::Data::Point < ::Dry::Struct
|
6
|
+
attribute :x, ::TilesetTooling::Data::Types::Integer
|
7
|
+
attribute :y, ::TilesetTooling::Data::Types::Integer
|
8
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# Copyright (c) 2020 Jean-Sebastien Gelinas, see LICENSE.txt
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require 'tileset_tooling/data/point'
|
5
|
+
|
4
6
|
# Class representing a TileSet's information
|
5
7
|
class ::TilesetTooling::Data::Tile < ::Dry::Struct
|
6
8
|
attribute :top, ::TilesetTooling::Data::Types::Integer
|
@@ -13,10 +15,8 @@ class ::TilesetTooling::Data::Tile < ::Dry::Struct
|
|
13
15
|
attribute :margin_bottom, ::TilesetTooling::Data::Types::Integer
|
14
16
|
attribute :margin_right, ::TilesetTooling::Data::Types::Integer
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
"#{top},#{left} [#{margin_top},#{margin_left},#{margin_bottom},#{margin_right}]"
|
19
|
-
end
|
18
|
+
attribute :row_index, ::TilesetTooling::Data::Types::Integer
|
19
|
+
attribute :column_index, ::TilesetTooling::Data::Types::Integer
|
20
20
|
|
21
21
|
# Helper to get the bottom coordinate
|
22
22
|
def bottom
|
@@ -27,4 +27,9 @@ class ::TilesetTooling::Data::Tile < ::Dry::Struct
|
|
27
27
|
def right
|
28
28
|
left + width
|
29
29
|
end
|
30
|
+
|
31
|
+
# Helper to get the top-left point of this tile
|
32
|
+
def top_left
|
33
|
+
::TilesetTooling::Data::Point.new(x: left, y: top)
|
34
|
+
end
|
30
35
|
end
|
@@ -13,28 +13,16 @@ class ::TilesetTooling::Data::TileSetRow
|
|
13
13
|
attr_reader :tiles
|
14
14
|
end
|
15
15
|
|
16
|
-
# Class representing
|
17
|
-
class ::TilesetTooling::Data::
|
18
|
-
attribute :
|
19
|
-
attribute :
|
16
|
+
# Class representing any TileSet's information
|
17
|
+
class ::TilesetTooling::Data::TileSetBase < ::Dry::Struct
|
18
|
+
attribute :height, ::TilesetTooling::Data::Types::Integer
|
19
|
+
attribute :width, ::TilesetTooling::Data::Types::Integer
|
20
20
|
attribute :tile_height, ::TilesetTooling::Data::Types::Integer
|
21
21
|
attribute :tile_width, ::TilesetTooling::Data::Types::Integer
|
22
22
|
attribute :margin, ::TilesetTooling::Data::Types::Integer
|
23
23
|
attribute :offset_top, ::TilesetTooling::Data::Types::Integer
|
24
24
|
attribute :offset_left, ::TilesetTooling::Data::Types::Integer
|
25
25
|
|
26
|
-
# Helper to print all information in the image
|
27
|
-
def to_s
|
28
|
-
%(
|
29
|
-
Image '#{original_image_path}'
|
30
|
-
Tile height: #{tile_height}
|
31
|
-
Tile width: #{tile_width}
|
32
|
-
Margin: #{margin}
|
33
|
-
Top offset: #{offset_top}
|
34
|
-
Left offset: #{offset_left}
|
35
|
-
Number of tiles: #{rows.count * rows[0].tiles.count})
|
36
|
-
end
|
37
|
-
|
38
26
|
# Runs the given bloc on each tile of the tileset
|
39
27
|
def for_each_tile(&block)
|
40
28
|
rows.each do |row|
|
@@ -44,14 +32,19 @@ Image '#{original_image_path}'
|
|
44
32
|
end
|
45
33
|
end
|
46
34
|
|
47
|
-
# Gets the
|
48
|
-
def
|
49
|
-
|
35
|
+
# Gets the number of tiles per row
|
36
|
+
def nb_tiles_per_row
|
37
|
+
rows[0].tiles.length
|
50
38
|
end
|
51
39
|
|
52
|
-
# Gets the
|
53
|
-
def
|
54
|
-
|
40
|
+
# Gets the number of tiles per column
|
41
|
+
def nb_tiles_per_column
|
42
|
+
rows.length
|
43
|
+
end
|
44
|
+
|
45
|
+
# Gets the tile at the specified row/column
|
46
|
+
def tile_at(row_index, column_index)
|
47
|
+
rows[row_index].tiles[column_index]
|
55
48
|
end
|
56
49
|
|
57
50
|
private
|
@@ -62,11 +55,13 @@ Image '#{original_image_path}'
|
|
62
55
|
|
63
56
|
@rows = []
|
64
57
|
top = offset_top
|
58
|
+
row_index = 0
|
65
59
|
loop do
|
66
60
|
left = offset_left
|
67
61
|
tiles = []
|
68
62
|
margin_top = top.positive? ? margin : 0
|
69
63
|
margin_bottom = top + tile_height < height ? margin : 0
|
64
|
+
column_index = 0
|
70
65
|
|
71
66
|
loop do
|
72
67
|
margin_left = left.positive? ? margin : 0
|
@@ -80,17 +75,40 @@ Image '#{original_image_path}'
|
|
80
75
|
margin_top: margin_top,
|
81
76
|
margin_left: margin_left,
|
82
77
|
margin_bottom: margin_bottom,
|
83
|
-
margin_right: margin_right
|
78
|
+
margin_right: margin_right,
|
79
|
+
row_index: row_index,
|
80
|
+
column_index: column_index
|
84
81
|
)
|
85
82
|
left += tile_width + margin_left + margin_right
|
83
|
+
column_index += 1
|
86
84
|
break if left >= width
|
87
85
|
end
|
88
86
|
|
89
87
|
@rows << ::TilesetTooling::Data::TileSetRow.new(tiles)
|
90
88
|
top += tile_height + margin_top + margin_bottom
|
89
|
+
row_index += 1
|
91
90
|
break if top >= height
|
92
91
|
end
|
93
92
|
|
94
93
|
@rows
|
95
94
|
end
|
96
95
|
end
|
96
|
+
|
97
|
+
# Real tileset, associated with an actual image on disk
|
98
|
+
class ::TilesetTooling::Data::FileTileSet < ::TilesetTooling::Data::TileSetBase
|
99
|
+
attribute :image, ::TilesetTooling::Data::Types::ImageType
|
100
|
+
attribute :original_image_path, ::TilesetTooling::Data::Types::String
|
101
|
+
|
102
|
+
def self.new(**kwargs)
|
103
|
+
image = kwargs[:image]
|
104
|
+
kwargs[:image] = image
|
105
|
+
kwargs[:height] = image.height
|
106
|
+
kwargs[:width] = image.width
|
107
|
+
|
108
|
+
super(**kwargs)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Virtual tileset, not associated with an actual image
|
113
|
+
class ::TilesetTooling::Data::VirtualTileSet < ::TilesetTooling::Data::TileSetBase
|
114
|
+
end
|
@@ -1,26 +1,9 @@
|
|
1
1
|
# Copyright (c) 2020 Jean-Sebastien Gelinas, see LICENSE.txt
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
# A few random utilities
|
4
|
+
# Module containing a few random utilities
|
7
5
|
module ::TilesetTooling::Utils
|
8
|
-
module_function
|
9
|
-
|
10
|
-
# Generate a signature from the image data
|
11
|
-
def image_signature(image_path)
|
12
|
-
::MiniMagick::Tool::Identify.new do |identity|
|
13
|
-
identity.quiet
|
14
|
-
identity.format('%#\\n')
|
15
|
-
identity << image_path
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
# Gets the path to the spec file that should go with the given image
|
20
|
-
def image_spec_file_path(image_path)
|
21
|
-
file_name = ::File.basename(image_path, '.*')
|
22
|
-
directory = ::File.dirname(image_path)
|
23
|
-
|
24
|
-
"#{directory}/#{file_name}.specs"
|
25
|
-
end
|
26
6
|
end
|
7
|
+
|
8
|
+
require 'tileset_tooling/utils/common'
|
9
|
+
require 'tileset_tooling/utils/specs_loader'
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Copyright (c) 2020 Jean-Sebastien Gelinas, see LICENSE.txt
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'mini_magick'
|
5
|
+
|
6
|
+
# A few random utilities
|
7
|
+
module ::TilesetTooling::Utils
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# Generate a signature from the image data
|
11
|
+
def image_signature(image_path)
|
12
|
+
::MiniMagick::Tool::Identify.new do |identity|
|
13
|
+
identity.quiet
|
14
|
+
identity.format('%#\\n')
|
15
|
+
identity << image_path
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Generates a virtual tileset with added margin to be used for coordinate
|
20
|
+
def tileset_with_margin_from(original_tileset, nb_pixels_in_margin)
|
21
|
+
raise(::StandardError, 'Original tileset already contains a margin') unless original_tileset.margin.zero?
|
22
|
+
|
23
|
+
new_height = original_tileset.height + (original_tileset.nb_tiles_per_column * 2 * nb_pixels_in_margin) - 2 * nb_pixels_in_margin
|
24
|
+
new_width = original_tileset.width + (original_tileset.nb_tiles_per_row * 2 * nb_pixels_in_margin) - 2 * nb_pixels_in_margin
|
25
|
+
|
26
|
+
::TilesetTooling::Data::VirtualTileSet.new(
|
27
|
+
tile_height: original_tileset.tile_height,
|
28
|
+
tile_width: original_tileset.tile_width,
|
29
|
+
margin: nb_pixels_in_margin,
|
30
|
+
offset_top: original_tileset.offset_top,
|
31
|
+
offset_left: original_tileset.offset_left,
|
32
|
+
height: new_height,
|
33
|
+
width: new_width
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Copyright (c) 2020 Jean-Sebastien Gelinas, see LICENSE.txt
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Class used to find/load specs for a given image
|
5
|
+
class ::TilesetTooling::Utils::SpecsLoader
|
6
|
+
# Constructor, initializes a few internals
|
7
|
+
def initialize
|
8
|
+
@logger = ::SemanticLogger[self.class.name.split('::').last]
|
9
|
+
@cli = ::HighLine.new
|
10
|
+
end
|
11
|
+
|
12
|
+
# Tries to find specs for the given image path
|
13
|
+
def find_specs_for(image_path, skip_specs_file)
|
14
|
+
specs_file = image_spec_file_path(image_path)
|
15
|
+
if !skip_specs_file && ::File.exist?(specs_file)
|
16
|
+
load_specs_from_file(specs_file)
|
17
|
+
else
|
18
|
+
ask_specs
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Gets the path to the spec file that should go with the given image
|
25
|
+
def image_spec_file_path(image_path)
|
26
|
+
file_name = ::File.basename(image_path, '.*')
|
27
|
+
directory = ::File.dirname(image_path)
|
28
|
+
|
29
|
+
"#{directory}/#{file_name}.specs"
|
30
|
+
end
|
31
|
+
|
32
|
+
def ask_specs
|
33
|
+
tile_height =
|
34
|
+
@cli.ask('Tile height? ', ::Integer) do |q|
|
35
|
+
q.default = 0
|
36
|
+
q.in = 1..256
|
37
|
+
end
|
38
|
+
tile_width =
|
39
|
+
@cli.ask('Tile width? ', ::Integer) do |q|
|
40
|
+
q.default = 0
|
41
|
+
q.in = 1..256
|
42
|
+
end
|
43
|
+
margin = @cli.ask('Margin? ', ::Integer) { |q| q.default = 0 }
|
44
|
+
offset_top = @cli.ask('Top Offset? ', ::Integer) { |q| q.default = 0 }
|
45
|
+
offset_left = @cli.ask('Left Offset? ', ::Integer) { |q| q.default = 0 }
|
46
|
+
|
47
|
+
[tile_height, tile_width, margin, offset_top, offset_left]
|
48
|
+
end
|
49
|
+
|
50
|
+
def load_specs_from_file(file_path)
|
51
|
+
@logger.info("Extracting specs from '#{file_path}'")
|
52
|
+
specs = ::YAML.load_file(file_path)
|
53
|
+
|
54
|
+
begin
|
55
|
+
tile_height = specs['specs']['details']['tile_height']
|
56
|
+
tile_width = specs['specs']['details']['tile_width']
|
57
|
+
margin = specs['specs']['details']['margin']
|
58
|
+
offset_top = specs['specs']['details']['offset_top']
|
59
|
+
offset_left = specs['specs']['details']['offset_left']
|
60
|
+
rescue ::NoMethodError
|
61
|
+
raise(::StandardError, 'Invalid specs file')
|
62
|
+
end
|
63
|
+
[tile_height, tile_width, margin, offset_top, offset_left]
|
64
|
+
end
|
65
|
+
end
|
@@ -5,23 +5,30 @@ require 'test_helper'
|
|
5
5
|
|
6
6
|
class ::TestInsertBleed < ::Test::Unit::TestCase
|
7
7
|
def test_margin_required
|
8
|
-
input, = get_png_data('simple_no_margin.png')
|
9
|
-
|
10
|
-
|
8
|
+
input, expected = get_png_data('simple_no_margin.png')
|
9
|
+
specs_loader = ::TilesetTooling::Utils::SpecsLoader.new
|
10
|
+
output = output_file_path
|
11
|
+
options = { output: output }
|
12
|
+
args = [input]
|
13
|
+
command = ::TilesetTooling::Commands::InsertBleed.new(options, args, specs_loader)
|
14
|
+
specs_loader.expects(:ask_specs).returns([16, 16, 0, 0, 0])
|
11
15
|
command.unpack!
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
command.run
|
17
|
+
assert ::File.exist?(expected)
|
18
|
+
assert ::File.exist?(output)
|
19
|
+
output_signature = ::TilesetTooling::Utils.image_signature(output)
|
20
|
+
expected_signature = ::TilesetTooling::Utils.image_signature(expected)
|
21
|
+
assert_equal(expected_signature, output_signature)
|
16
22
|
end
|
17
23
|
|
18
24
|
def test_simple_file
|
19
25
|
input, expected = get_png_data('simple_with_margin.png')
|
26
|
+
specs_loader = ::TilesetTooling::Utils::SpecsLoader.new
|
20
27
|
output = output_file_path
|
21
28
|
options = { output: output }
|
22
29
|
args = [input]
|
23
|
-
command = ::TilesetTooling::Commands::InsertBleed.new(options, args)
|
24
|
-
|
30
|
+
command = ::TilesetTooling::Commands::InsertBleed.new(options, args, specs_loader)
|
31
|
+
specs_loader.expects(:ask_specs).returns([16, 16, 1, 0, 0])
|
25
32
|
command.unpack!
|
26
33
|
command.run
|
27
34
|
assert ::File.exist?(expected)
|
@@ -33,10 +40,11 @@ class ::TestInsertBleed < ::Test::Unit::TestCase
|
|
33
40
|
|
34
41
|
def test_simple_file_with_specs
|
35
42
|
input, expected = get_png_data('simple_with_specs.png')
|
43
|
+
specs_loader = ::TilesetTooling::Utils::SpecsLoader.new
|
36
44
|
output = output_file_path
|
37
45
|
options = { output: output }
|
38
46
|
args = [input]
|
39
|
-
command = ::TilesetTooling::Commands::InsertBleed.new(options, args)
|
47
|
+
command = ::TilesetTooling::Commands::InsertBleed.new(options, args, specs_loader)
|
40
48
|
command.unpack!
|
41
49
|
command.run
|
42
50
|
assert ::File.exist?(expected)
|
@@ -48,10 +56,11 @@ class ::TestInsertBleed < ::Test::Unit::TestCase
|
|
48
56
|
|
49
57
|
def test_simple_file_with_bad_specs
|
50
58
|
input, = get_png_data('simple_with_bad_specs.png')
|
59
|
+
specs_loader = ::TilesetTooling::Utils::SpecsLoader.new
|
51
60
|
output = output_file_path
|
52
61
|
options = { output: output }
|
53
62
|
args = [input]
|
54
|
-
command = ::TilesetTooling::Commands::InsertBleed.new(options, args)
|
63
|
+
command = ::TilesetTooling::Commands::InsertBleed.new(options, args, specs_loader)
|
55
64
|
command.unpack!
|
56
65
|
assert_raise ::StandardError, 'Invalid specs file' do
|
57
66
|
command.run
|
@@ -60,11 +69,12 @@ class ::TestInsertBleed < ::Test::Unit::TestCase
|
|
60
69
|
|
61
70
|
def test_simple_file_with_skip_specs
|
62
71
|
input, expected = get_png_data('simple_with_bad_specs.png')
|
72
|
+
specs_loader = ::TilesetTooling::Utils::SpecsLoader.new
|
63
73
|
output = output_file_path
|
64
74
|
options = { output: output, 'skip-specs': true }
|
65
75
|
args = [input]
|
66
|
-
command = ::TilesetTooling::Commands::InsertBleed.new(options, args)
|
67
|
-
|
76
|
+
command = ::TilesetTooling::Commands::InsertBleed.new(options, args, specs_loader)
|
77
|
+
specs_loader.expects(:ask_specs).returns([16, 16, 1, 0, 0])
|
68
78
|
command.unpack!
|
69
79
|
command.run
|
70
80
|
assert ::File.exist?(expected)
|
Binary file
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tileset_tooling
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean-Sebastien Gelinas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aruba
|
@@ -263,13 +263,17 @@ files:
|
|
263
263
|
- lib/tileset_tooling/commands.rb
|
264
264
|
- lib/tileset_tooling/commands/insert_bleed.rb
|
265
265
|
- lib/tileset_tooling/data.rb
|
266
|
+
- lib/tileset_tooling/data/point.rb
|
266
267
|
- lib/tileset_tooling/data/tile.rb
|
267
268
|
- lib/tileset_tooling/data/tileset.rb
|
268
269
|
- lib/tileset_tooling/data/types.rb
|
269
270
|
- lib/tileset_tooling/utils.rb
|
271
|
+
- lib/tileset_tooling/utils/common.rb
|
272
|
+
- lib/tileset_tooling/utils/specs_loader.rb
|
270
273
|
- lib/tileset_tooling/version.rb
|
271
274
|
- test/commands/insert_bleed_test.rb
|
272
275
|
- test/data/UIpackSheet_transparent.png
|
276
|
+
- test/data/expected/simple_no_margin.png
|
273
277
|
- test/data/expected/simple_with_bad_specs.png
|
274
278
|
- test/data/expected/simple_with_margin.png
|
275
279
|
- test/data/expected/simple_with_specs.png
|