pageflow-linkmap-page 1.4.0 → 1.5.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/CHANGELOG.md +6 -7
- data/app/jobs/pageflow/linkmap_page/process_source_image_file_job.rb +15 -0
- data/app/models/pageflow/linkmap_page/color_map_file.rb +85 -0
- data/app/models/pageflow/linkmap_page/masked_image_file.rb +51 -0
- data/app/models/pageflow/linkmap_page/processed_image_file.rb +60 -0
- data/db/migrate/20171106151700_create_masked_image_files.rb +21 -0
- data/db/migrate/20180111145100_create_color_map_files.rb +24 -0
- data/lib/pageflow/linkmap_page/engine.rb +16 -0
- data/lib/pageflow/linkmap_page/images/palette.png +0 -0
- data/lib/pageflow/linkmap_page/paperclip_processors/color_mask.rb +53 -0
- data/lib/pageflow/linkmap_page/paperclip_processors/colors.rb +213 -0
- data/lib/pageflow/linkmap_page/paperclip_processors/image_dimensions.rb +21 -0
- data/lib/pageflow/linkmap_page/paperclip_processors/invoke_callback.rb +12 -0
- data/lib/pageflow/linkmap_page/paperclip_tempfile.rb +18 -0
- data/lib/pageflow/linkmap_page/progress.rb +43 -0
- data/lib/pageflow/linkmap_page/version.rb +1 -1
- data/lib/tasks/pageflow_linkmap_page_tasks.rake +149 -0
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 292a7ccb48c2c4a81d69edfee98d6567861b6df965ab6ff59d29384da534bcc8
|
4
|
+
data.tar.gz: 168b15ee2a7da3d2803e2d3ffac8625e3f2d154036e94b725efb261452f086b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5d6b1ddc936609028ccb8ef0a5c6c3ff0cd08ad122bfc8b9b0d9fb2e503d46c6d41df21c52b2eea16bb6cbad64b285f76ab8bdd0cbac43a5a42edce51cddc9c
|
7
|
+
data.tar.gz: 1699af6c8ab0e2719df1006f5f16e8947ae52860f7a0a7e863fa2e3c4cfa933b9045f28241cc35dfa3642284422ef57729857bbc56cef52a6afae69a0c27550f
|
data/CHANGELOG.md
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
-
### Version 1.
|
3
|
+
### Version 1.5.0
|
4
4
|
|
5
|
-
|
5
|
+
2019-01-23
|
6
6
|
|
7
|
-
[Compare changes](https://github.com/codevise/pageflow-linkmap-page/compare/1-
|
7
|
+
[Compare changes](https://github.com/codevise/pageflow-linkmap-page/compare/1-4-stable...v1.5.0)
|
8
8
|
|
9
|
-
- Add
|
10
|
-
([#
|
11
|
-
[#45](https://github.com/codevise/pageflow-linkmap-page/pull/45))
|
9
|
+
- Add Rake-Task to migrate existing linkmap pages to 2.0-version
|
10
|
+
([#47](https://github.com/codevise/pageflow-linkmap-page/pull/47))
|
12
11
|
|
13
12
|
See
|
14
|
-
[1-
|
13
|
+
[1-4-stable branch](https://github.com/codevise/pageflow-linkmap-page/blob/1-4-stable/CHANGELOG.md)
|
15
14
|
for previous changes.
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Pageflow
|
2
|
+
module LinkmapPage
|
3
|
+
class ProcessSourceImageFileJob
|
4
|
+
@queue = :resizing
|
5
|
+
|
6
|
+
extend StateMachineJob
|
7
|
+
|
8
|
+
def self.perform_with_result(file, _options)
|
9
|
+
file.attachment = file.source_image_file.attachment
|
10
|
+
file.save!
|
11
|
+
:ok
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Pageflow
|
2
|
+
module LinkmapPage
|
3
|
+
class ColorMapFile < ProcessedImageFile
|
4
|
+
belongs_to :source_image_file, class_name: 'Pageflow::ImageFile'
|
5
|
+
|
6
|
+
# Prevent anti aliasing. Otherwise, when processing color map
|
7
|
+
# images, borders between areas are blurred.
|
8
|
+
SOURCE_FILE_OPTIONS = '-filter point'.freeze
|
9
|
+
|
10
|
+
PALETTE_PATH = Pageflow::LinkmapPage::Engine.root
|
11
|
+
.join('lib', 'pageflow', 'linkmap_page', 'images', 'palette.png').freeze
|
12
|
+
|
13
|
+
CONVERT_OPTIONS = [
|
14
|
+
'-quality 70',
|
15
|
+
'-interlace Plane',
|
16
|
+
'-dither None',
|
17
|
+
'-colors 64',
|
18
|
+
"-remap #{PALETTE_PATH}",
|
19
|
+
].join(' ').freeze
|
20
|
+
|
21
|
+
has_attached_file(:attachment,
|
22
|
+
Pageflow.config.paperclip_s3_default_options
|
23
|
+
.merge(styles: {
|
24
|
+
remapped: {
|
25
|
+
processors: [:thumbnail],
|
26
|
+
format: 'png',
|
27
|
+
geometry: GEOMETRY,
|
28
|
+
source_file_options: SOURCE_FILE_OPTIONS,
|
29
|
+
convert_options: CONVERT_OPTIONS
|
30
|
+
},
|
31
|
+
sprite: {
|
32
|
+
processors: [
|
33
|
+
:thumbnail,
|
34
|
+
:pageflow_linkmap_page_image_dimensions,
|
35
|
+
:pageflow_linkmap_page_image_colors
|
36
|
+
],
|
37
|
+
format: 'png',
|
38
|
+
geometry: '1024x1024>',
|
39
|
+
source_file_options: SOURCE_FILE_OPTIONS,
|
40
|
+
convert_options: CONVERT_OPTIONS,
|
41
|
+
progress_callback: :update_processing_progress
|
42
|
+
}
|
43
|
+
}))
|
44
|
+
|
45
|
+
do_not_validate_attachment_file_type :attachment
|
46
|
+
|
47
|
+
serialize :attachment_colors
|
48
|
+
|
49
|
+
def sprite_url
|
50
|
+
attachment.url(:sprite)
|
51
|
+
end
|
52
|
+
|
53
|
+
def width
|
54
|
+
attachment_width
|
55
|
+
end
|
56
|
+
|
57
|
+
def height
|
58
|
+
attachment_height
|
59
|
+
end
|
60
|
+
|
61
|
+
def url
|
62
|
+
attachment.url(:remapped)
|
63
|
+
end
|
64
|
+
|
65
|
+
def processed_attachment
|
66
|
+
attachment.styles[:remapped]
|
67
|
+
end
|
68
|
+
|
69
|
+
def present_colors
|
70
|
+
attachment_colors ? attachment_colors.keys : []
|
71
|
+
end
|
72
|
+
|
73
|
+
def bounding_box_for_color(color)
|
74
|
+
attachment_colors[color]
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def update_processing_progress(percent)
|
80
|
+
update_column(:processing_progress, percent)
|
81
|
+
touch
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Pageflow
|
2
|
+
module LinkmapPage
|
3
|
+
class MaskedImageFile < ProcessedImageFile
|
4
|
+
belongs_to :color_map_file, class_name: 'Pageflow::LinkmapPage::ColorMapFile'
|
5
|
+
|
6
|
+
STYLES = lambda do |attachment|
|
7
|
+
masked_image_file = attachment.instance
|
8
|
+
|
9
|
+
masked_image_file.present_styles.each_with_object({}) do |color, result|
|
10
|
+
result[color.to_sym] = {
|
11
|
+
processors: [
|
12
|
+
:thumbnail,
|
13
|
+
:pageflow_linkmap_page_color_mask,
|
14
|
+
:pageflow_linkmap_page_invoke_callback
|
15
|
+
],
|
16
|
+
color_map_attachment: masked_image_file.color_map_file.processed_attachment,
|
17
|
+
format: 'png',
|
18
|
+
geometry: GEOMETRY,
|
19
|
+
callback: :update_processing_progress
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
has_attached_file(:attachment,
|
25
|
+
Pageflow.config.paperclip_s3_default_options
|
26
|
+
.merge(styles: STYLES))
|
27
|
+
|
28
|
+
do_not_validate_attachment_file_type :attachment
|
29
|
+
|
30
|
+
def url_for_color(color)
|
31
|
+
attachment.url(color.to_sym)
|
32
|
+
end
|
33
|
+
|
34
|
+
def for_color(color)
|
35
|
+
attachment.styles[color.to_sym]
|
36
|
+
end
|
37
|
+
|
38
|
+
def present_styles
|
39
|
+
color_map_file.present_colors
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def update_processing_progress(style)
|
45
|
+
update_column(:processing_progress,
|
46
|
+
(present_styles.index(style.to_s) + 1) * 100 / present_styles.size)
|
47
|
+
touch
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Pageflow
|
2
|
+
module LinkmapPage
|
3
|
+
class ProcessedImageFile < ActiveRecord::Base
|
4
|
+
self.abstract_class = true
|
5
|
+
|
6
|
+
include Pageflow::UploadedFile
|
7
|
+
|
8
|
+
belongs_to :source_image_file, class_name: 'Pageflow::ImageFile'
|
9
|
+
|
10
|
+
GEOMETRY = '1920x1080^'.freeze
|
11
|
+
|
12
|
+
state_machine initial: 'not_processed' do
|
13
|
+
extend StateMachineJob::Macro
|
14
|
+
|
15
|
+
state 'not_processed'
|
16
|
+
state 'processing'
|
17
|
+
state 'processed'
|
18
|
+
|
19
|
+
event :process do
|
20
|
+
transition 'not_processed' => 'processing'
|
21
|
+
transition 'processing_failed' => 'processing'
|
22
|
+
end
|
23
|
+
|
24
|
+
job ProcessSourceImageFileJob do
|
25
|
+
on_enter 'processing'
|
26
|
+
result ok: 'processed'
|
27
|
+
result error: 'processing_failed'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def url
|
32
|
+
''
|
33
|
+
end
|
34
|
+
|
35
|
+
def original_url
|
36
|
+
''
|
37
|
+
end
|
38
|
+
|
39
|
+
def retry!
|
40
|
+
process!
|
41
|
+
end
|
42
|
+
|
43
|
+
def publish!
|
44
|
+
process!
|
45
|
+
end
|
46
|
+
|
47
|
+
def retryable?
|
48
|
+
processing_failed?
|
49
|
+
end
|
50
|
+
|
51
|
+
def ready?
|
52
|
+
processed?
|
53
|
+
end
|
54
|
+
|
55
|
+
def basename
|
56
|
+
'unused'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class CreateMaskedImageFiles < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :pageflow_linkmap_page_masked_image_files do |t|
|
4
|
+
t.belongs_to :entry, index: true
|
5
|
+
t.string :state
|
6
|
+
t.string :rights
|
7
|
+
t.integer :parent_file_id
|
8
|
+
t.string :parent_file_model_type
|
9
|
+
|
10
|
+
t.belongs_to :source_image_file
|
11
|
+
t.belongs_to :color_map_file
|
12
|
+
t.string :attachment_file_name
|
13
|
+
t.integer :processing_progress, default: 0, null: false
|
14
|
+
|
15
|
+
t.timestamps
|
16
|
+
|
17
|
+
t.index([:parent_file_id, :parent_file_model_type],
|
18
|
+
name: 'index_masked_image_files_on_parent_id_and_parent_model_type')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class CreateColorMapFiles < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :pageflow_linkmap_page_color_map_files do |t|
|
4
|
+
t.belongs_to :entry, index: true
|
5
|
+
t.string :state
|
6
|
+
t.string :rights
|
7
|
+
t.integer :parent_file_id
|
8
|
+
t.string :parent_file_model_type
|
9
|
+
|
10
|
+
t.string :attachment_file_name
|
11
|
+
t.text :attachment_colors
|
12
|
+
t.integer :attachment_width
|
13
|
+
t.integer :attachment_height
|
14
|
+
t.integer :processing_progress, default: 0, null: false
|
15
|
+
|
16
|
+
t.belongs_to :source_image_file
|
17
|
+
|
18
|
+
t.timestamps
|
19
|
+
|
20
|
+
t.index([:parent_file_id, :parent_file_model_type],
|
21
|
+
name: 'index_color_map_files_on_parent_id_and_parent_model_type')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -8,6 +8,22 @@ module Pageflow
|
|
8
8
|
config.autoload_paths << File.join(config.root, 'lib')
|
9
9
|
config.i18n.load_path += Dir[config.root.join('config', 'locales', '**', '*.yml').to_s]
|
10
10
|
|
11
|
+
initializer 'pageflow_linkmap_page.paperclip' do
|
12
|
+
Paperclip.configure do |config|
|
13
|
+
config.register_processor(:pageflow_linkmap_page_image_colors,
|
14
|
+
Pageflow::LinkmapPage::PaperclipProcessors::Colors)
|
15
|
+
|
16
|
+
config.register_processor(:pageflow_linkmap_page_color_mask,
|
17
|
+
Pageflow::LinkmapPage::PaperclipProcessors::ColorMask)
|
18
|
+
|
19
|
+
config.register_processor(:pageflow_linkmap_page_invoke_callback,
|
20
|
+
Pageflow::LinkmapPage::PaperclipProcessors::InvokeCallback)
|
21
|
+
|
22
|
+
config.register_processor(:pageflow_linkmap_page_image_dimensions,
|
23
|
+
Pageflow::LinkmapPage::PaperclipProcessors::ImageDimensions)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
11
27
|
config.generators do |g|
|
12
28
|
g.test_framework :rspec,:fixture => false
|
13
29
|
g.fixture_replacement :factory_girl, :dir => 'spec/factories'
|
Binary file
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Pageflow
|
2
|
+
module LinkmapPage
|
3
|
+
module PaperclipProcessors
|
4
|
+
class ColorMask < Paperclip::Processor
|
5
|
+
CONVERT_COMMAND = [
|
6
|
+
# Create mask by making all non-matching colors in color map
|
7
|
+
# image transparent
|
8
|
+
':color_map',
|
9
|
+
'+transparent :color',
|
10
|
+
# Make all areas transparent in source that are transparent in mask
|
11
|
+
':source',
|
12
|
+
'-compose src-in -composite',
|
13
|
+
# Write result to output file
|
14
|
+
':dest'
|
15
|
+
].join(' ').freeze
|
16
|
+
|
17
|
+
def make
|
18
|
+
with_destination_tempfile do |dest|
|
19
|
+
with_color_map do |color_map_path|
|
20
|
+
convert(CONVERT_COMMAND,
|
21
|
+
color: "##{options[:style]}",
|
22
|
+
color_map: color_map_path,
|
23
|
+
source: File.expand_path(file.path),
|
24
|
+
dest: File.expand_path(dest.path))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def with_destination_tempfile
|
32
|
+
current_format = File.extname(file.path)
|
33
|
+
basename = File.basename(file.path, current_format)
|
34
|
+
|
35
|
+
dest = Tempfile.new([basename, '.png'])
|
36
|
+
dest.binmode
|
37
|
+
|
38
|
+
yield dest
|
39
|
+
|
40
|
+
dest
|
41
|
+
end
|
42
|
+
|
43
|
+
def with_color_map(&block)
|
44
|
+
Pageflow::LinkmapPage::PaperclipTempfile.for(color_map_attachment, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def color_map_attachment
|
48
|
+
options.fetch(:color_map_attachment)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
module Pageflow
|
2
|
+
module LinkmapPage
|
3
|
+
module PaperclipProcessors
|
4
|
+
class Colors < Paperclip::Processor
|
5
|
+
def make
|
6
|
+
with_progress(steps: 2) do |progress|
|
7
|
+
colors = unique_colors(file) - ['000000']
|
8
|
+
boxes = color_bounding_boxes_ignoring_single_pixels(file, colors, progress)
|
9
|
+
|
10
|
+
attachment.instance_write('colors', boxes)
|
11
|
+
make_color_sprite(file, boxes.keys, progress)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def unique_colors(file)
|
18
|
+
ConvertOutput.parse_unique_colors(convert(':source -unique-colors txt:-',
|
19
|
+
source: file.path))
|
20
|
+
end
|
21
|
+
|
22
|
+
def color_bounding_boxes_ignoring_single_pixels(file, colors, overall_progress)
|
23
|
+
overall_progress.divide(steps: colors.size) do |progress|
|
24
|
+
boxes = colors.each_with_object({}) do |color, result|
|
25
|
+
result[color] = color_bounding_box_ignoring_single_pixels(file, color)
|
26
|
+
progress.step
|
27
|
+
end
|
28
|
+
|
29
|
+
remove_boxes_for_ignored_colors(boxes)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove_boxes_for_ignored_colors(boxes)
|
34
|
+
boxes.delete_if do |_, box|
|
35
|
+
box[:width].zero? && box[:height].zero?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
COLOR_MASK_ARGS = [
|
40
|
+
# Make transparent areas black
|
41
|
+
'-background black -flatten',
|
42
|
+
# Make all non matching colors black
|
43
|
+
'-fill black +opaque :color',
|
44
|
+
# Replace color with white - required for morphology
|
45
|
+
'-fill white -opaque :color',
|
46
|
+
# Remove shapes that are smaller than 3x3 pixels
|
47
|
+
'-morphology Open Square:1',
|
48
|
+
# Make black areas transparent
|
49
|
+
'-transparent black',
|
50
|
+
# Restore original color
|
51
|
+
'-fill :color -opaque white',
|
52
|
+
].join(' ').freeze
|
53
|
+
|
54
|
+
TRIM_CONVERT_ARGS = [
|
55
|
+
# Make all non-matching colors in color map image
|
56
|
+
# transparent
|
57
|
+
':source',
|
58
|
+
COLOR_MASK_ARGS,
|
59
|
+
# Create a transparent border
|
60
|
+
'-bordercolor none',
|
61
|
+
'-border 1x1',
|
62
|
+
# Trim transparent region.
|
63
|
+
'-trim',
|
64
|
+
].join(' ').freeze
|
65
|
+
|
66
|
+
TRIM_INFO_CONVERT_ARGS = [
|
67
|
+
TRIM_CONVERT_ARGS,
|
68
|
+
# Write info to stdout
|
69
|
+
'info:-'
|
70
|
+
].join(' ').freeze
|
71
|
+
|
72
|
+
def color_bounding_box_ignoring_single_pixels(file, color)
|
73
|
+
box = ConvertOutput.parse_trim(convert(TRIM_INFO_CONVERT_ARGS,
|
74
|
+
color: "##{color}",
|
75
|
+
source: file.path))
|
76
|
+
ignore_added_border_in_coordinated(box)
|
77
|
+
end
|
78
|
+
|
79
|
+
def ignore_added_border_in_coordinated(box)
|
80
|
+
{
|
81
|
+
left: box[:left] - 1,
|
82
|
+
top: box[:top] - 1,
|
83
|
+
width: box[:width],
|
84
|
+
height: box[:height]
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
def make_color_sprite(file, colors, overall_progress)
|
89
|
+
with_destination_tempfile do |sprite_tempfile|
|
90
|
+
with_tempfiles(colors) do |color_tempfiles|
|
91
|
+
overall_progress.divide(steps: colors.size + 1) do |progress|
|
92
|
+
color_tempfiles.each do |color, color_tempfile|
|
93
|
+
make_color_filtered_image(file, color, color_tempfile)
|
94
|
+
progress.step
|
95
|
+
end
|
96
|
+
|
97
|
+
make_sprite(color_tempfiles, sprite_tempfile)
|
98
|
+
progress.step
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
COLOR_FILTER_CONVERT_ARGS = [
|
105
|
+
TRIM_CONVERT_ARGS,
|
106
|
+
# Crop image to trimmed area
|
107
|
+
'+repage',
|
108
|
+
':dest'
|
109
|
+
].join(' ').freeze
|
110
|
+
|
111
|
+
def make_color_filtered_image(file, color, destination_tempfile)
|
112
|
+
convert(COLOR_FILTER_CONVERT_ARGS,
|
113
|
+
color: "##{color}",
|
114
|
+
source: File.expand_path(file.path),
|
115
|
+
dest: File.expand_path(destination_tempfile.path))
|
116
|
+
end
|
117
|
+
|
118
|
+
def make_sprite(files, destination_tempfile)
|
119
|
+
inputs = files.each_with_object({}) do |(key, tempfile), result|
|
120
|
+
result["input_#{key}"] = File.expand_path(tempfile.path)
|
121
|
+
end
|
122
|
+
|
123
|
+
placeholders = inputs.keys.sort.map { |key| ":#{key}" }
|
124
|
+
|
125
|
+
Paperclip.run('montage',
|
126
|
+
[
|
127
|
+
*placeholders,
|
128
|
+
'-background transparent',
|
129
|
+
"-tile #{inputs.size}x",
|
130
|
+
'-mode Concatenate',
|
131
|
+
':output'
|
132
|
+
].join(' '),
|
133
|
+
inputs.merge(output: File.expand_path(destination_tempfile.path)))
|
134
|
+
end
|
135
|
+
|
136
|
+
def with_destination_tempfile
|
137
|
+
dest = create_tempfile
|
138
|
+
yield dest
|
139
|
+
dest
|
140
|
+
end
|
141
|
+
|
142
|
+
def with_tempfiles(keys)
|
143
|
+
files = keys.each_with_object({}) do |key, result|
|
144
|
+
result[key] = create_tempfile(key)
|
145
|
+
end
|
146
|
+
|
147
|
+
yield files
|
148
|
+
ensure
|
149
|
+
files.each_value do |file|
|
150
|
+
file.close
|
151
|
+
file.unlink
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def create_tempfile(suffix = nil)
|
156
|
+
current_format = File.extname(file.path)
|
157
|
+
basename = File.basename(file.path, current_format)
|
158
|
+
|
159
|
+
dest = Tempfile.new([[basename, suffix].compact.join('-'), '.png'])
|
160
|
+
dest.binmode
|
161
|
+
|
162
|
+
dest
|
163
|
+
end
|
164
|
+
|
165
|
+
def with_progress(steps:)
|
166
|
+
progress = Pageflow::LinkmapPage::Progress.new(steps: steps) do |percent|
|
167
|
+
if options[:progress_callback]
|
168
|
+
attachment.instance.send(options[:progress_callback], percent)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
yield progress
|
173
|
+
end
|
174
|
+
|
175
|
+
module ConvertOutput
|
176
|
+
HEX_COLOR_REGEXP = /#[0-9a-f]{6,8}/i
|
177
|
+
TRANSPARENT = '#00000000'.freeze
|
178
|
+
|
179
|
+
module_function
|
180
|
+
|
181
|
+
def parse_unique_colors(output)
|
182
|
+
output
|
183
|
+
.split("\n")
|
184
|
+
.reject { |line| line.starts_with?('#') }
|
185
|
+
.map { |line| line[HEX_COLOR_REGEXP] }
|
186
|
+
.reject { |color| color == TRANSPARENT }
|
187
|
+
.map { |color| color.tr('#', '') }
|
188
|
+
.map(&:downcase)
|
189
|
+
.sort
|
190
|
+
end
|
191
|
+
|
192
|
+
def parse_trim(output)
|
193
|
+
trimmed_size, size_and_offset = output.split(' ')[2, 3]
|
194
|
+
width, height = trimmed_size.split('x')
|
195
|
+
|
196
|
+
if size_and_offset.ends_with?('-1-1')
|
197
|
+
return {left: 0, top: 0, width: 0, height: 0}
|
198
|
+
end
|
199
|
+
|
200
|
+
_size, left, top = size_and_offset.split('+')
|
201
|
+
|
202
|
+
{
|
203
|
+
left: left.to_i,
|
204
|
+
top: top.to_i,
|
205
|
+
width: width.to_i,
|
206
|
+
height: height.to_i
|
207
|
+
}
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Pageflow
|
2
|
+
module LinkmapPage
|
3
|
+
module PaperclipProcessors
|
4
|
+
class ImageDimensions < Paperclip::Processor
|
5
|
+
def make
|
6
|
+
store_dimensions(file)
|
7
|
+
file
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def store_dimensions(file)
|
13
|
+
geometry = Paperclip::Geometry.from_file(file)
|
14
|
+
|
15
|
+
attachment.instance_write('width', geometry.width)
|
16
|
+
attachment.instance_write('height', geometry.height)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Pageflow
|
2
|
+
module LinkmapPage
|
3
|
+
module PaperclipTempfile
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def for(attachment)
|
7
|
+
tempfile = Paperclip.io_adapters.for(attachment)
|
8
|
+
|
9
|
+
begin
|
10
|
+
yield(tempfile.path)
|
11
|
+
ensure
|
12
|
+
tempfile.close
|
13
|
+
tempfile.unlink
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Pageflow
|
2
|
+
module LinkmapPage
|
3
|
+
class Progress
|
4
|
+
def initialize(steps:, &block)
|
5
|
+
@total_steps = steps
|
6
|
+
@block = block
|
7
|
+
@counter = 0
|
8
|
+
end
|
9
|
+
|
10
|
+
def step
|
11
|
+
return if counter >= total_steps
|
12
|
+
@counter += 1
|
13
|
+
report(current_percent)
|
14
|
+
end
|
15
|
+
|
16
|
+
def divide(steps:)
|
17
|
+
return if counter >= total_steps
|
18
|
+
|
19
|
+
sub_progress = Progress.new(steps: steps) do |percent|
|
20
|
+
if percent == 100
|
21
|
+
step
|
22
|
+
else
|
23
|
+
report(current_percent + percent / total_steps)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
yield sub_progress
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_reader :block, :total_steps, :counter
|
33
|
+
|
34
|
+
def current_percent
|
35
|
+
100.0 / total_steps * counter
|
36
|
+
end
|
37
|
+
|
38
|
+
def report(percent)
|
39
|
+
@block.call(percent)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
namespace :pageflow_linkmap_page do
|
2
|
+
desc 'Migrate to server generated files'
|
3
|
+
task migrate_to_masked_image_files: :environment do
|
4
|
+
Pageflow::LinkmapPage::MaskedImageFilesMigrator.run
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
module Pageflow
|
9
|
+
module LinkmapPage
|
10
|
+
module MaskedImageFilesMigrator
|
11
|
+
extend self
|
12
|
+
|
13
|
+
def run
|
14
|
+
Resque.inline = true
|
15
|
+
total = pages_with_mask_image.count
|
16
|
+
|
17
|
+
pages_with_mask_image.find_each.with_index do |page, index|
|
18
|
+
puts "== Migrating page #{page.id} (#{index}/#{total})"
|
19
|
+
color_map_file = create_files(page)
|
20
|
+
|
21
|
+
if color_map_file
|
22
|
+
puts '-- Migrating mask perma ids...'
|
23
|
+
migrate_mask_perma_ids(page, color_map_file)
|
24
|
+
end
|
25
|
+
|
26
|
+
page.save!
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def create_files(page)
|
33
|
+
color_map_image_file =
|
34
|
+
ImageFile.find_by_id(page.configuration['linkmap_color_map_image_id'])
|
35
|
+
|
36
|
+
if color_map_image_file
|
37
|
+
revision = page.chapter.storyline.revision
|
38
|
+
|
39
|
+
puts "-- Color map file for image file #{color_map_image_file.id}"
|
40
|
+
|
41
|
+
color_map_file = color_map_file_for(color_map_image_file, revision)
|
42
|
+
page.configuration['linkmap_color_map_file_id'] = color_map_file.id
|
43
|
+
|
44
|
+
hover_image_file = ImageFile.find_by_id(page.configuration['hover_image_id'])
|
45
|
+
|
46
|
+
if hover_image_file
|
47
|
+
puts "-- Masked image file for hover image file #{hover_image_file.id}"
|
48
|
+
|
49
|
+
masked_image_file = masked_image_file_for(hover_image_file, color_map_file, revision)
|
50
|
+
page.configuration['linkmap_masked_hover_image_id'] = masked_image_file.id
|
51
|
+
end
|
52
|
+
|
53
|
+
visited_image_file = ImageFile.find_by_id(page.configuration['visited_image_id'])
|
54
|
+
|
55
|
+
if visited_image_file
|
56
|
+
puts "-- Masked image file for visited image file #{visited_image_file.id}"
|
57
|
+
|
58
|
+
masked_image_file = masked_image_file_for(visited_image_file, color_map_file, revision)
|
59
|
+
page.configuration['linkmap_masked_visited_image_id'] = masked_image_file.id
|
60
|
+
end
|
61
|
+
|
62
|
+
color_map_file
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def color_map_file_for(image_file, revision)
|
67
|
+
color_map_file = ColorMapFile.find_or_create_by(source_image_file_id: image_file.id) do |c|
|
68
|
+
c.entry_id = revision.entry_id
|
69
|
+
end
|
70
|
+
|
71
|
+
unless color_map_file.processed?
|
72
|
+
puts ' Processing...'
|
73
|
+
|
74
|
+
color_map_file.process!
|
75
|
+
color_map_file.reload
|
76
|
+
end
|
77
|
+
|
78
|
+
revision.file_usages.find_or_create_by(file: color_map_file)
|
79
|
+
color_map_file
|
80
|
+
end
|
81
|
+
|
82
|
+
def masked_image_file_for(image_file, color_map_file, revision)
|
83
|
+
masked_image_file = MaskedImageFile.find_or_create_by(source_image_file: image_file,
|
84
|
+
color_map_file: color_map_file) do |m|
|
85
|
+
m.entry_id = revision.entry_id
|
86
|
+
end
|
87
|
+
|
88
|
+
unless masked_image_file.processed?
|
89
|
+
puts ' Processing...'
|
90
|
+
|
91
|
+
masked_image_file.process!
|
92
|
+
masked_image_file.reload
|
93
|
+
end
|
94
|
+
|
95
|
+
revision.file_usages.find_or_create_by(file: masked_image_file)
|
96
|
+
masked_image_file
|
97
|
+
end
|
98
|
+
|
99
|
+
def migrate_mask_perma_ids(page, color_map_file)
|
100
|
+
areas = page.configuration['linkmap_areas'] || []
|
101
|
+
|
102
|
+
page.configuration['linkmap_areas'] = areas.map do |area_attributes|
|
103
|
+
mask_perma_id = area_attributes['mask_perma_id']
|
104
|
+
|
105
|
+
if mask_perma_id && !area_attributes['color_map_component_id']
|
106
|
+
sprite_id = page.configuration.fetch('linkmap_masks').fetch('id')
|
107
|
+
colors =
|
108
|
+
page
|
109
|
+
.configuration
|
110
|
+
.fetch('linkmap_masks')
|
111
|
+
.fetch('c')
|
112
|
+
.fetch('c')
|
113
|
+
.map { |component| component['c'] }
|
114
|
+
|
115
|
+
area_attributes.merge(color_map_component_id: convert_mask_perma_id(mask_perma_id,
|
116
|
+
colors,
|
117
|
+
color_map_file,
|
118
|
+
sprite_id))
|
119
|
+
else
|
120
|
+
area_attributes
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def convert_mask_perma_id(perma_id, colors, color_map_file, sprite_id)
|
126
|
+
target_sprite_id, color_index = perma_id.split(':')
|
127
|
+
|
128
|
+
if target_sprite_id.to_i == sprite_id
|
129
|
+
"#{color_map_file.id}:#{nearest_color(color_map_file, *colors[color_index.to_i])}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def nearest_color(color_map_file, r, g, b)
|
134
|
+
color_map_file.present_colors.min_by do |color|
|
135
|
+
(color[0..1].to_i(16) - r).abs +
|
136
|
+
(color[2..3].to_i(16) - g).abs +
|
137
|
+
(color[4..5].to_i(16) - b).abs
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def pages_with_mask_image
|
142
|
+
Page
|
143
|
+
.where(template: 'linkmap_page')
|
144
|
+
.where('configuration LIKE "%linkmap_color_map_image_id%"')
|
145
|
+
.includes(chapter: {storyline: :revision})
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pageflow-linkmap-page
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Codevise Solutions Ltd.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pageflow
|
@@ -253,7 +253,11 @@ files:
|
|
253
253
|
- app/assets/stylesheets/pageflow/linkmap_page/themes/default/scroll_indicators.scss
|
254
254
|
- app/controllers/pageflow/linkmap_page/mask_sprites_controller.rb
|
255
255
|
- app/helpers/pageflow/linkmap_page/areas_helper.rb
|
256
|
+
- app/jobs/pageflow/linkmap_page/process_source_image_file_job.rb
|
257
|
+
- app/models/pageflow/linkmap_page/color_map_file.rb
|
256
258
|
- app/models/pageflow/linkmap_page/mask_sprite.rb
|
259
|
+
- app/models/pageflow/linkmap_page/masked_image_file.rb
|
260
|
+
- app/models/pageflow/linkmap_page/processed_image_file.rb
|
257
261
|
- app/views/pageflow/linkmap_page/areas/_div.html.erb
|
258
262
|
- app/views/pageflow/linkmap_page/page.html.erb
|
259
263
|
- bin/rspec
|
@@ -263,12 +267,22 @@ files:
|
|
263
267
|
- config/routes.rb
|
264
268
|
- config/spring.rb
|
265
269
|
- db/migrate/20170330201200_create_mask_sprites.rb
|
270
|
+
- db/migrate/20171106151700_create_masked_image_files.rb
|
271
|
+
- db/migrate/20180111145100_create_color_map_files.rb
|
266
272
|
- lib/generators/pageflow_linkmap_page/install/install_generator.rb
|
267
273
|
- lib/pageflow-linkmap-page.rb
|
268
274
|
- lib/pageflow/linkmap_page/engine.rb
|
275
|
+
- lib/pageflow/linkmap_page/images/palette.png
|
269
276
|
- lib/pageflow/linkmap_page/page_type.rb
|
277
|
+
- lib/pageflow/linkmap_page/paperclip_processors/color_mask.rb
|
278
|
+
- lib/pageflow/linkmap_page/paperclip_processors/colors.rb
|
279
|
+
- lib/pageflow/linkmap_page/paperclip_processors/image_dimensions.rb
|
280
|
+
- lib/pageflow/linkmap_page/paperclip_processors/invoke_callback.rb
|
281
|
+
- lib/pageflow/linkmap_page/paperclip_tempfile.rb
|
270
282
|
- lib/pageflow/linkmap_page/plugin.rb
|
283
|
+
- lib/pageflow/linkmap_page/progress.rb
|
271
284
|
- lib/pageflow/linkmap_page/version.rb
|
285
|
+
- lib/tasks/pageflow_linkmap_page_tasks.rake
|
272
286
|
- pageflow-linkmap-page.gemspec
|
273
287
|
- spec/controllers/pageflow/linkmap_page/mask_sprites_controller_spec.rb
|
274
288
|
- spec/helpers/pageflow/linkmap_page/areas_helper_spec.rb
|
@@ -295,7 +309,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
295
309
|
version: '0'
|
296
310
|
requirements: []
|
297
311
|
rubyforge_project:
|
298
|
-
rubygems_version: 2.7.
|
312
|
+
rubygems_version: 2.7.8
|
299
313
|
signing_key:
|
300
314
|
specification_version: 4
|
301
315
|
summary: Pageflow page type for a page that contains customizable link areas
|