frameit 2.8.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -5
- data/lib/frameit.rb +19 -1
- data/lib/frameit/commands_generator.rb +33 -4
- data/lib/frameit/config_parser.rb +2 -0
- data/lib/frameit/device_types.rb +6 -4
- data/lib/frameit/editor.rb +28 -7
- data/lib/frameit/frame_downloader.rb +71 -0
- data/lib/frameit/offsets.rb +10 -82
- data/lib/frameit/options.rb +13 -1
- data/lib/frameit/runner.rb +8 -8
- data/lib/frameit/screenshot.rb +17 -8
- data/lib/frameit/template_finder.rb +13 -65
- data/lib/frameit/version.rb +1 -1
- metadata +7 -7
- data/lib/frameit/frame_converter.rb +0 -99
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f153eb5635aba47fe4f2404223b06181bf98fd2
|
4
|
+
data.tar.gz: 48ef840b23d480681a43a256503c146f3bd8d928
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 736c49029deb88bdee79e932d4e1d0e807d1d89f1b461e5419dc3d3cd1bd9c050000f5844171c65e46fe5aa4a17bc2da078b7b022252abb65ee5a531bc5f9e76
|
7
|
+
data.tar.gz: 604c1f3b9918d28788ccefb101208a37973461ee447655dc8e8cdef716628da338a2b21b678566d869f6142c112aa052c93866279a81208d1447307153fd3b71
|
data/README.md
CHANGED
@@ -32,7 +32,6 @@ frameit
|
|
32
32
|
[![Twitter: @KauseFx](https://img.shields.io/badge/contact-@FastlaneTools-blue.svg?style=flat)](https://twitter.com/FastlaneTools)
|
33
33
|
[![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/fastlane/fastlane/blob/master/frameit/LICENSE)
|
34
34
|
[![Gem](https://img.shields.io/gem/v/frameit.svg?style=flat)](http://rubygems.org/gems/frameit)
|
35
|
-
[![Build Status](https://img.shields.io/circleci/project/fastlane/fastlane/master.svg?style=flat)](https://circleci.com/gh/fastlane/fastlane)
|
36
35
|
|
37
36
|
###### Quickly put your screenshots into the right device frames
|
38
37
|
|
@@ -52,7 +51,7 @@ Get in contact with the developer on Twitter: [@FastlaneTools](https://twitter.c
|
|
52
51
|
</p>
|
53
52
|
|
54
53
|
-------
|
55
|
-
<h5 align="center"><code>frameit</code> is part of <a href="https://fastlane.tools">fastlane</a>: The easiest way to automate
|
54
|
+
<h5 align="center"><code>frameit</code> is part of <a href="https://fastlane.tools">fastlane</a>: The easiest way to automate beta deployments and releases for your iOS and Android apps.</h5>
|
56
55
|
|
57
56
|
|
58
57
|
# Features
|
@@ -116,9 +115,9 @@ To use the silver version of the frames:
|
|
116
115
|
|
117
116
|
frameit silver
|
118
117
|
|
119
|
-
To
|
118
|
+
To download the latest frames
|
120
119
|
|
121
|
-
frameit
|
120
|
+
frameit download_frames
|
122
121
|
|
123
122
|
When using `frameit` without titles on top, the screenshots will have the full resolution, which means they can't be uploaded to the App Store directly. They are supposed to be used for websites, print media and emails. Check out the section below to use the screenshots for the App Store.
|
124
123
|
|
@@ -134,6 +133,7 @@ Use it to define the general information:
|
|
134
133
|
|
135
134
|
```json
|
136
135
|
{
|
136
|
+
"device_frame_version": "latest",
|
137
137
|
"default": {
|
138
138
|
"keyword": {
|
139
139
|
"font": "./fonts/MyFont-Rg.otf"
|
@@ -235,7 +235,7 @@ Check out the [MindNode example project](https://github.com/fastlane/examples/tr
|
|
235
235
|
|
236
236
|
## [`fastlane`](https://fastlane.tools) Toolchain
|
237
237
|
|
238
|
-
- [`fastlane`](https://fastlane.tools): The easiest way to automate
|
238
|
+
- [`fastlane`](https://fastlane.tools): The easiest way to automate beta deployments and releases for your iOS and Android apps
|
239
239
|
- [`deliver`](https://github.com/fastlane/fastlane/tree/master/deliver): Upload screenshots, metadata and your app to the App Store
|
240
240
|
- [`snapshot`](https://github.com/fastlane/fastlane/tree/master/snapshot): Automate taking localized screenshots of your iOS app on every device
|
241
241
|
- [`pem`](https://github.com/fastlane/fastlane/tree/master/pem): Automatically generate and renew your push notification profiles
|
data/lib/frameit.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'mini_magick'
|
2
2
|
require 'frameit/version'
|
3
|
-
require 'frameit/
|
3
|
+
require 'frameit/frame_downloader'
|
4
4
|
require 'frameit/device_types'
|
5
5
|
require 'frameit/runner'
|
6
6
|
require 'frameit/screenshot'
|
@@ -23,6 +23,24 @@ module Frameit
|
|
23
23
|
Helper = FastlaneCore::Helper # you gotta love Ruby: Helper.* should use the Helper class contained in FastlaneCore
|
24
24
|
UI = FastlaneCore::UI
|
25
25
|
ROOT = Pathname.new(File.expand_path('../..', __FILE__))
|
26
|
+
|
27
|
+
# Defaults to latest, might be a time stamp if defined in the Framefile.json
|
28
|
+
def self.frames_version
|
29
|
+
return @frames_version if @frames_version
|
30
|
+
@frames_version = "latest"
|
31
|
+
|
32
|
+
config_files = Dir["./**/Framefile.json"]
|
33
|
+
if config_files.count > 0
|
34
|
+
config = ConfigParser.new.load(config_files.first)
|
35
|
+
if config.data["device_frame_version"].to_s.length > 0
|
36
|
+
@frames_version = config.data["device_frame_version"]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
UI.success("Using device frames version '#{@frames_version}'")
|
41
|
+
|
42
|
+
return @frames_version
|
43
|
+
end
|
26
44
|
end
|
27
45
|
|
28
46
|
# rubocop:disable all
|
@@ -29,7 +29,7 @@ module Frameit
|
|
29
29
|
|
30
30
|
command :run do |c|
|
31
31
|
c.syntax = 'frameit black'
|
32
|
-
c.description = "Adds a black frame around all screenshots
|
32
|
+
c.description = "Adds a black frame around all screenshots"
|
33
33
|
|
34
34
|
c.action do |args, options|
|
35
35
|
load_config(options)
|
@@ -39,7 +39,7 @@ module Frameit
|
|
39
39
|
|
40
40
|
command :silver do |c|
|
41
41
|
c.syntax = 'frameit silver'
|
42
|
-
c.description = "Adds a silver frame around all screenshots
|
42
|
+
c.description = "Adds a silver frame around all screenshots"
|
43
43
|
|
44
44
|
c.action do |args, options|
|
45
45
|
load_config(options)
|
@@ -47,12 +47,41 @@ module Frameit
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
+
command :gold do |c|
|
51
|
+
c.syntax = 'frameit gold'
|
52
|
+
c.description = "Adds a gold frame around all screenshots"
|
53
|
+
|
54
|
+
c.action do |args, options|
|
55
|
+
load_config(options)
|
56
|
+
Frameit::Runner.new.run('.', Frameit::Color::GOLD)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
command :rose_gold do |c|
|
61
|
+
c.syntax = 'frameit rose_gold'
|
62
|
+
c.description = "Adds a rose gold frame around all screenshots"
|
63
|
+
|
64
|
+
c.action do |args, options|
|
65
|
+
load_config(options)
|
66
|
+
Frameit::Runner.new.run('.', Frameit::Color::ROSE_GOLD)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
50
70
|
command :setup do |c|
|
51
71
|
c.syntax = 'frameit setup'
|
52
|
-
c.description = "
|
72
|
+
c.description = "Downloads and sets up the latest device frames"
|
73
|
+
|
74
|
+
c.action do |args, options|
|
75
|
+
Frameit::FrameDownloader.new.download_frames
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
command :download_frames do |c|
|
80
|
+
c.syntax = 'frameit download_frames'
|
81
|
+
c.description = "Downloads and sets up the latest device frames"
|
53
82
|
|
54
83
|
c.action do |args, options|
|
55
|
-
Frameit::
|
84
|
+
Frameit::FrameDownloader.new.download_frames
|
56
85
|
end
|
57
86
|
end
|
58
87
|
|
data/lib/frameit/device_types.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
module Frameit
|
2
2
|
module Color
|
3
|
-
BLACK = "
|
4
|
-
SILVER = "
|
3
|
+
BLACK = "Space Gray"
|
4
|
+
SILVER = "Silver"
|
5
|
+
ROSE_GOLD = "Rose Gold"
|
6
|
+
GOLD = "Gold"
|
5
7
|
end
|
6
8
|
|
7
9
|
module Orientation
|
8
|
-
PORTRAIT = "
|
9
|
-
LANDSCAPE = "
|
10
|
+
PORTRAIT = "PORTRAIT"
|
11
|
+
LANDSCAPE = "LANDSCAPE"
|
10
12
|
end
|
11
13
|
end
|
data/lib/frameit/editor.rb
CHANGED
@@ -9,8 +9,13 @@ module Frameit
|
|
9
9
|
self.screenshot = screenshot
|
10
10
|
prepare_image
|
11
11
|
|
12
|
-
if load_frame #
|
12
|
+
if load_frame # Mac doesn't need a frame
|
13
13
|
self.frame = MiniMagick::Image.open(load_frame)
|
14
|
+
self.frame.rotate(90) unless self.screenshot.portrait? # we use portrait device frames for landscape screenshots
|
15
|
+
elsif self.class == Editor
|
16
|
+
# Couldn't find device frame (probably an iPhone 4, for which there are no images available any more)
|
17
|
+
# Message is already shown elsewhere
|
18
|
+
return
|
14
19
|
end
|
15
20
|
|
16
21
|
if should_add_title?
|
@@ -37,17 +42,31 @@ module Frameit
|
|
37
42
|
|
38
43
|
def store_result
|
39
44
|
output_path = screenshot.path.gsub('.png', '_framed.png').gsub('.PNG', '_framed.png')
|
40
|
-
image.format
|
41
|
-
image.write
|
45
|
+
image.format("png")
|
46
|
+
image.write(output_path)
|
42
47
|
UI.success "Added frame: '#{File.expand_path(output_path)}'"
|
43
48
|
end
|
44
49
|
|
45
50
|
# puts the screenshot into the frame
|
46
51
|
def put_into_frame
|
52
|
+
# We have to rotate the screenshot, since the offset information is for portrait
|
53
|
+
# only. Instead of doing the calculations ourselves, it's much easier to let
|
54
|
+
# imagemagick do the hard lifting for landscape screenshots
|
55
|
+
unless self.screenshot.portrait?
|
56
|
+
frame.rotate(-90)
|
57
|
+
@image.rotate(-90)
|
58
|
+
end
|
59
|
+
|
47
60
|
@image = frame.composite(image, "png") do |c|
|
48
61
|
c.compose "Over"
|
49
62
|
c.geometry offset['offset']
|
50
63
|
end
|
64
|
+
|
65
|
+
# We have to revert the state to be landscape screenshots
|
66
|
+
unless self.screenshot.portrait?
|
67
|
+
frame.rotate(90)
|
68
|
+
@image.rotate(90)
|
69
|
+
end
|
51
70
|
end
|
52
71
|
|
53
72
|
def offset
|
@@ -89,11 +108,11 @@ module Frameit
|
|
89
108
|
|
90
109
|
if self.frame # we have no frame on le mac
|
91
110
|
resize_frame!
|
92
|
-
|
111
|
+
put_into_frame
|
93
112
|
|
94
113
|
# Decrease the size of the framed screenshot to fit into the defined padding + background
|
95
114
|
frame_width = background.width - horizontal_frame_padding * 2
|
96
|
-
image.resize "#{frame_width}x"
|
115
|
+
@image.resize "#{frame_width}x"
|
97
116
|
end
|
98
117
|
|
99
118
|
self.top_space_above_device = vertical_frame_padding
|
@@ -160,7 +179,9 @@ module Frameit
|
|
160
179
|
|
161
180
|
# Resize the frame as it's too low quality by default
|
162
181
|
def resize_frame!
|
163
|
-
|
182
|
+
screenshot_width = self.screenshot.portrait? ? screenshot.size[0] : screenshot.size[1]
|
183
|
+
|
184
|
+
multiplicator = (screenshot_width.to_f / offset['width'].to_f) # by how much do we have to change this?
|
164
185
|
new_frame_width = multiplicator * frame.width # the new width for the frame
|
165
186
|
frame.resize "#{new_frame_width.round}x" # resize it to the calculated witdth
|
166
187
|
modify_offset(multiplicator) # modify the offset to properly insert the screenshot into the frame later
|
@@ -271,7 +292,7 @@ module Frameit
|
|
271
292
|
return @config if @config
|
272
293
|
|
273
294
|
config_path = File.join(File.expand_path("..", screenshot.path), "Framefile.json")
|
274
|
-
config_path = File.join(File.expand_path("../..", screenshot.path), "Framefile.json") unless File.exist?
|
295
|
+
config_path = File.join(File.expand_path("../..", screenshot.path), "Framefile.json") unless File.exist?(config_path)
|
275
296
|
file = ConfigParser.new.load(config_path)
|
276
297
|
return {} unless file # no config file at all
|
277
298
|
@config = file.fetch_value(screenshot.path)
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Frameit
|
2
|
+
class FrameDownloader
|
3
|
+
FRAME_PATH = '.frameit/devices_frames_2'
|
4
|
+
HOST_URL = "https://fastlane.github.io/frameit-frames"
|
5
|
+
|
6
|
+
def download_frames
|
7
|
+
print_disclaimer
|
8
|
+
|
9
|
+
require 'json'
|
10
|
+
require 'fileutils'
|
11
|
+
|
12
|
+
UI.message("Downloading device frames...")
|
13
|
+
FileUtils.mkdir_p(templates_path)
|
14
|
+
|
15
|
+
frames_version = download_file("version.txt")
|
16
|
+
File.write(File.join(templates_path, "version.txt"), frames_version)
|
17
|
+
UI.important("Using frame version '#{frames_version}', you can optionally lock that version in your Framefile.json using `device_frame_version`")
|
18
|
+
|
19
|
+
files = JSON.parse(download_file("files.json"))
|
20
|
+
files.each_with_index do |current, index|
|
21
|
+
content = download_file(current, txt: "#{index + 1} of #{files.count} files")
|
22
|
+
File.write(File.join(templates_path, current), content)
|
23
|
+
end
|
24
|
+
File.write(File.join(templates_path, "offsets.json"), download_file("offsets.json"))
|
25
|
+
|
26
|
+
UI.success("Successfully downloaded all required image assets")
|
27
|
+
end
|
28
|
+
|
29
|
+
def frames_exist?(version: "latest")
|
30
|
+
Dir["#{templates_path}/*.png"].count > 0 && File.read(File.join(templates_path, "version.txt")).to_i > 0
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.templates_path
|
34
|
+
File.join(ENV['HOME'], FRAME_PATH, Frameit.frames_version)
|
35
|
+
end
|
36
|
+
|
37
|
+
def templates_path
|
38
|
+
self.class.templates_path
|
39
|
+
end
|
40
|
+
|
41
|
+
def print_disclaimer
|
42
|
+
UI.header "Device frames disclaimer"
|
43
|
+
UI.important "All used device frames are available via Facebook Design: http://facebook.design/devices"
|
44
|
+
UI.message "----------------------------------------"
|
45
|
+
UI.message "While Facebook has redrawn and shares these assets for the benefit"
|
46
|
+
UI.message "of the design community, Facebook does not own any of the underlying"
|
47
|
+
UI.message "product or user interface designs."
|
48
|
+
UI.message "By accessing these assets, you agree to obtain all necessary permissions"
|
49
|
+
UI.message "from the underlying rights holders and/or adhere to any applicable brand"
|
50
|
+
UI.message "use guidelines before using them."
|
51
|
+
UI.message "Facebook disclaims all express or implied warranties with respect to these assets, including"
|
52
|
+
UI.message "non-infringement of intellectual property rights."
|
53
|
+
UI.message "----------------------------------------"
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def download_file(path, txt: "file")
|
59
|
+
require 'uri'
|
60
|
+
|
61
|
+
url = File.join(HOST_URL, Frameit.frames_version, URI.escape(path))
|
62
|
+
UI.message("Downloading #{txt} from '#{url}' ...")
|
63
|
+
body = Excon.get(url).body
|
64
|
+
raise body if body.include?("<Error>")
|
65
|
+
return body
|
66
|
+
rescue => ex
|
67
|
+
UI.error(ex)
|
68
|
+
UI.user_error!("Error accessing URL '#{url}'")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/frameit/offsets.rb
CHANGED
@@ -3,89 +3,17 @@ module Frameit
|
|
3
3
|
# Returns the image offset needed for a certain device type for a given orientation
|
4
4
|
# uses deliver to detect the screen size
|
5
5
|
def self.image_offset(screenshot)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
'offset' => '+41+146',
|
13
|
-
'width' => 541
|
14
|
-
}
|
15
|
-
when size::IOS_47
|
16
|
-
return {
|
17
|
-
'offset' => "+43+154",
|
18
|
-
'width' => 530
|
19
|
-
}
|
20
|
-
when size::IOS_40
|
21
|
-
if Frameit.config[:use_legacy_iphone5s]
|
22
|
-
return {
|
23
|
-
'offset' => "+54+197",
|
24
|
-
'width' => 544
|
25
|
-
}
|
26
|
-
else
|
27
|
-
return {
|
28
|
-
'offset' => "+48+178",
|
29
|
-
'width' => 485
|
30
|
-
}
|
31
|
-
end
|
32
|
-
when size::IOS_35
|
33
|
-
return {
|
34
|
-
'offset' => "+59+260",
|
35
|
-
'width' => 647
|
36
|
-
}
|
37
|
-
when size::IOS_IPAD
|
38
|
-
return {
|
39
|
-
'offset' => '+47+135',
|
40
|
-
'width' => 737
|
41
|
-
}
|
42
|
-
when size::IOS_IPAD_PRO
|
43
|
-
return {
|
44
|
-
'offset' => '+48+90',
|
45
|
-
'width' => 805
|
46
|
-
}
|
47
|
-
end
|
48
|
-
when Orientation::LANDSCAPE
|
49
|
-
case screenshot.screen_size
|
50
|
-
when size::IOS_55
|
51
|
-
return {
|
52
|
-
'offset' => "+146+41",
|
53
|
-
'width' => 960
|
54
|
-
}
|
55
|
-
when size::IOS_47
|
56
|
-
return {
|
57
|
-
'offset' => "+153+41",
|
58
|
-
'width' => 946
|
59
|
-
}
|
60
|
-
when size::IOS_40
|
61
|
-
if Frameit.config[:use_legacy_iphone5s]
|
62
|
-
return {
|
63
|
-
'offset' => "+201+48",
|
64
|
-
'width' => 970
|
65
|
-
}
|
66
|
-
else
|
67
|
-
return {
|
68
|
-
'offset' => "+177+41",
|
69
|
-
'width' => 859
|
70
|
-
}
|
71
|
-
end
|
72
|
-
when size::IOS_35
|
73
|
-
return {
|
74
|
-
'offset' => "+258+52",
|
75
|
-
'width' => 966
|
76
|
-
}
|
77
|
-
when size::IOS_IPAD
|
78
|
-
return {
|
79
|
-
'offset' => '+135+47',
|
80
|
-
'width' => 983
|
81
|
-
}
|
82
|
-
when size::IOS_IPAD_PRO
|
83
|
-
return {
|
84
|
-
'offset' => '+88+48',
|
85
|
-
'width' => 1075
|
86
|
-
}
|
87
|
-
end
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
unless @offsets
|
9
|
+
offsets_json_path = File.join(FrameDownloader.new.templates_path, "offsets.json")
|
10
|
+
UI.user_error!("Could not find offsets.json file at path '#{offsets_json_path}'") unless File.exist?(offsets_json_path)
|
11
|
+
@offsets = JSON.parse(File.read(offsets_json_path))
|
88
12
|
end
|
13
|
+
|
14
|
+
offset_value = @offsets["portrait"][screenshot.device_name]
|
15
|
+
UI.error("Tried looking for offset information for 'portrait', #{screenshot.device_name}") unless offset_value
|
16
|
+
return offset_value
|
89
17
|
end
|
90
18
|
end
|
91
19
|
end
|
data/lib/frameit/options.rb
CHANGED
@@ -12,6 +12,14 @@ module Frameit
|
|
12
12
|
description: "Use white device frames. Alias for :white",
|
13
13
|
optional: true,
|
14
14
|
is_string: false),
|
15
|
+
FastlaneCore::ConfigItem.new(key: :rose_gold,
|
16
|
+
description: "Use rose gold device frames. Alias for :rose_gold",
|
17
|
+
optional: true,
|
18
|
+
is_string: false),
|
19
|
+
FastlaneCore::ConfigItem.new(key: :gold,
|
20
|
+
description: "Use gold device frames. Alias for :gold",
|
21
|
+
optional: true,
|
22
|
+
is_string: false),
|
15
23
|
FastlaneCore::ConfigItem.new(key: :force_device_type,
|
16
24
|
env_name: "FRAMEIT_FORCE_DEVICE_TYPE",
|
17
25
|
description: "Forces a given device type, useful for Mac screenshots, as their sizes vary",
|
@@ -24,9 +32,13 @@ module Frameit
|
|
24
32
|
end),
|
25
33
|
FastlaneCore::ConfigItem.new(key: :use_legacy_iphone5s,
|
26
34
|
env_name: "FRAMEIT_USE_LEGACY_IPHONE_5_S",
|
27
|
-
optional: true,
|
28
35
|
is_string: false,
|
29
36
|
description: "use iPhone 5s instead of iPhone SE frames",
|
37
|
+
default_value: false),
|
38
|
+
FastlaneCore::ConfigItem.new(key: :use_legacy_iphone6s,
|
39
|
+
env_name: "FRAMEIT_USE_LEGACY_IPHONE_6_S",
|
40
|
+
is_string: false,
|
41
|
+
description: "Use iPhone 6s frames instead of iPhone 7 frames",
|
30
42
|
default_value: false)
|
31
43
|
]
|
32
44
|
end
|
data/lib/frameit/runner.rb
CHANGED
@@ -4,13 +4,9 @@ require 'fastimage'
|
|
4
4
|
module Frameit
|
5
5
|
class Runner
|
6
6
|
def initialize
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
converter.convert_frames
|
11
|
-
else
|
12
|
-
# First run
|
13
|
-
converter.run
|
7
|
+
downloader = FrameDownloader.new
|
8
|
+
unless downloader.frames_exist?
|
9
|
+
downloader.download_frames
|
14
10
|
end
|
15
11
|
end
|
16
12
|
|
@@ -18,6 +14,8 @@ module Frameit
|
|
18
14
|
unless color
|
19
15
|
color = Frameit::Color::BLACK
|
20
16
|
color = Frameit::Color::SILVER if Frameit.config[:white] || Frameit.config[:silver]
|
17
|
+
color = Frameit::Color::GOLD if Frameit.config[:gold]
|
18
|
+
color = Frameit::Color::ROSE_GOLD if Frameit.config[:rose_gold]
|
21
19
|
end
|
22
20
|
|
23
21
|
screenshots = Dir.glob("#{path}/**/*.{png,PNG}").uniq # uniq because thanks to {png,PNG} there are duplicates
|
@@ -29,6 +27,8 @@ module Frameit
|
|
29
27
|
next if full_path.include? "device_frames/" # these are the device frames the user is using
|
30
28
|
next if full_path.downcase.include? "watch" # we don't care about watches right now
|
31
29
|
|
30
|
+
UI.message("Framing screenshot '#{full_path}'")
|
31
|
+
|
32
32
|
begin
|
33
33
|
screenshot = Screenshot.new(full_path, color)
|
34
34
|
screenshot.frame!
|
@@ -38,7 +38,7 @@ module Frameit
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
else
|
41
|
-
UI.error "Could not find screenshots"
|
41
|
+
UI.error "Could not find screenshots in current directory: '#{File.expand_path(path)}'"
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
data/lib/frameit/screenshot.rb
CHANGED
@@ -22,30 +22,39 @@ module Frameit
|
|
22
22
|
sizes = Deliver::AppScreenshot::ScreenSize
|
23
23
|
case @screen_size
|
24
24
|
when sizes::IOS_55
|
25
|
-
return 'iPhone
|
25
|
+
return Frameit.config[:use_legacy_iphone6s] ? 'iPhone 6s Plus' : 'iPhone 7 Plus'
|
26
26
|
when sizes::IOS_47
|
27
|
-
return 'iPhone
|
27
|
+
return Frameit.config[:use_legacy_iphone6s] ? 'iPhone 6s' : 'iPhone 7'
|
28
28
|
when sizes::IOS_40
|
29
|
-
return Frameit.config[:use_legacy_iphone5s] ? '
|
29
|
+
return Frameit.config[:use_legacy_iphone5s] ? 'iPhone 5s' : 'iPhone SE'
|
30
30
|
when sizes::IOS_35
|
31
|
-
return '
|
31
|
+
return 'iPhone 4'
|
32
32
|
when sizes::IOS_IPAD
|
33
|
-
return 'iPad
|
33
|
+
return 'iPad Air 2'
|
34
34
|
when sizes::IOS_IPAD_PRO
|
35
|
-
return 'iPad
|
35
|
+
return 'iPad Pro'
|
36
36
|
when sizes::MAC
|
37
|
-
return '
|
37
|
+
return 'MacBook'
|
38
38
|
else
|
39
39
|
UI.error "Unknown device type for size #{@screen_size} for path '#{path}'"
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
def color
|
44
|
+
if !Frameit.config[:use_legacy_iphone6s] && @color == Frameit::Color::BLACK
|
45
|
+
if @screen_size == Deliver::AppScreenshot::ScreenSize::IOS_55 || @screen_size == Deliver::AppScreenshot::ScreenSize::IOS_47
|
46
|
+
return "Matte Black" # RIP space gray
|
47
|
+
end
|
48
|
+
end
|
49
|
+
return @color
|
50
|
+
end
|
51
|
+
|
43
52
|
# Is the device a 3x device? (e.g. 6 Plus)
|
44
53
|
def triple_density?
|
45
54
|
(screen_size == Deliver::AppScreenshot::ScreenSize::IOS_55)
|
46
55
|
end
|
47
56
|
|
48
|
-
# Super old devices
|
57
|
+
# Super old devices (iPhone 4)
|
49
58
|
def mini?
|
50
59
|
(screen_size == Deliver::AppScreenshot::ScreenSize::IOS_35)
|
51
60
|
end
|
@@ -1,84 +1,32 @@
|
|
1
1
|
module Frameit
|
2
2
|
# Responsible for finding the correct device
|
3
3
|
class TemplateFinder
|
4
|
-
class FilenameTransform
|
5
|
-
def initialize(device_name)
|
6
|
-
@device_name = device_name
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
# Example: iPhone_5s_Vert_SpaceGray_sRGB
|
11
|
-
class Type1Transform < FilenameTransform
|
12
|
-
def transform(color, orientation)
|
13
|
-
# Note the * on the end to handle the _sRGB part
|
14
|
-
"#{@device_name}_#{orientation}_#{color}*"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
# Example: iPad-Pro-Space-Gray-vertical.png
|
19
|
-
class Type2Transform < FilenameTransform
|
20
|
-
def transform(color, orientation)
|
21
|
-
fixed_color = color == 'SpaceGray' ? "Space-Gray" : "Silver"
|
22
|
-
fixed_orientation = orientation == 'Horz' ? 'horizontal' : 'vertical'
|
23
|
-
"#{@device_name}-#{fixed_color}-#{fixed_orientation}"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# Example: iPhone-SE-Space-Gray
|
28
|
-
# Note that 'vertical' is implied
|
29
|
-
class Type3Transform < FilenameTransform
|
30
|
-
def transform(color, orientation)
|
31
|
-
fixed_color = color == 'SpaceGray' ? "Space-Gray" : "Silver"
|
32
|
-
filename = "#{@device_name}-#{fixed_color}"
|
33
|
-
if orientation == 'Horz'
|
34
|
-
"#{filename}-horizontal"
|
35
|
-
else
|
36
|
-
filename
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
DEVICE_TO_TRANSFORM_TYPE = {
|
42
|
-
'iPhone-SE' => Type3Transform.new('iPhone-SE'),
|
43
|
-
'iPad-Pro' => Type2Transform.new('iPad-Pro'),
|
44
|
-
'iPad-mini' => Type2Transform.new('iPad-mini'),
|
45
|
-
'iPhone-6s' => Type2Transform.new('iPhone-6s'),
|
46
|
-
'iPhone-6s-Plus' => Type2Transform.new('iPhone-6s-Plus')
|
47
|
-
}
|
48
|
-
|
49
4
|
# This will detect the screen size and choose the correct template
|
50
5
|
def self.get_template(screenshot)
|
51
6
|
return nil if screenshot.mac?
|
52
7
|
|
53
|
-
|
54
|
-
|
55
|
-
# The "original" pattern is the type 1 transform
|
56
|
-
# so if we don't have something more specific, go for that
|
57
|
-
transformer ||= Type1Transform.new(screenshot.device_name)
|
58
|
-
filename = transformer.transform(screenshot.color, screenshot.orientation_name)
|
8
|
+
filename = "Apple #{screenshot.device_name} #{screenshot.color}"
|
59
9
|
|
60
|
-
|
61
|
-
templates = Dir["../**/#{filename}.{png,jpg}"] # local directory
|
62
|
-
templates += Dir["#{templates_path}/**/#{filename}.{png,jpg}"] # ~/.frameit folder
|
10
|
+
templates = Dir["#{FrameDownloader.templates_path}/#{filename}.{png,jpg}"] # ~/.frameit folder
|
63
11
|
|
64
|
-
UI.verbose "Looking for #{filename} and found #{templates.count}"
|
12
|
+
UI.verbose "Looking for #{filename} and found #{templates.count} template(s)"
|
65
13
|
|
66
14
|
if templates.count == 0
|
67
15
|
if screenshot.screen_size == Deliver::AppScreenshot::ScreenSize::IOS_35
|
68
16
|
UI.important "Unfortunately 3.5\" device frames were discontinued. Skipping screen '#{screenshot.path}'"
|
69
17
|
UI.error "Looked for: '#{filename}.png'"
|
70
|
-
elsif screenshot.
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
UI.
|
75
|
-
|
18
|
+
elsif screenshot.color == Frameit::Color::ROSE_GOLD || screenshot.color == Frameit::Color::GOLD
|
19
|
+
# Unfortunately not every device type is available in rose gold or gold
|
20
|
+
# This is why we can't have nice things #yatusabes
|
21
|
+
# fallback to a white iPhone, which looks similar
|
22
|
+
UI.important("Unfortunatey device type '#{screenshot.device_name}' is not available in #{screenshot.color}, falling back to silver...")
|
23
|
+
screenshot.color = Frameit::Color::SILVER
|
24
|
+
return self.get_template(screenshot)
|
76
25
|
else
|
77
|
-
UI.error
|
78
|
-
UI.error
|
79
|
-
UI.error "and store them in '#{templates_path}'"
|
80
|
-
UI.error "Missing file: '#{filename}.png'"
|
26
|
+
UI.error("Couldn't find template for screenshot type '#{filename}'")
|
27
|
+
UI.error("Please run `frameit download_frames` to download the latest frames")
|
81
28
|
end
|
29
|
+
return filename if Helper.test?
|
82
30
|
return nil
|
83
31
|
else
|
84
32
|
return templates.first.tr(" ", "\ ")
|
data/lib/frameit/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: frameit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felix Krause
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-10-
|
11
|
+
date: 2016-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: fastlane_core
|
@@ -16,7 +16,7 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.53.0
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: 1.0.0
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.
|
29
|
+
version: 0.53.0
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 1.0.0
|
@@ -204,14 +204,14 @@ dependencies:
|
|
204
204
|
requirements:
|
205
205
|
- - "~>"
|
206
206
|
- !ruby/object:Gem::Version
|
207
|
-
version: 0.
|
207
|
+
version: 0.44.0
|
208
208
|
type: :development
|
209
209
|
prerelease: false
|
210
210
|
version_requirements: !ruby/object:Gem::Requirement
|
211
211
|
requirements:
|
212
212
|
- - "~>"
|
213
213
|
- !ruby/object:Gem::Version
|
214
|
-
version: 0.
|
214
|
+
version: 0.44.0
|
215
215
|
description: Quickly put your screenshots into the right device frames
|
216
216
|
email:
|
217
217
|
- frameit@krausefx.com
|
@@ -230,7 +230,7 @@ files:
|
|
230
230
|
- lib/frameit/dependency_checker.rb
|
231
231
|
- lib/frameit/device_types.rb
|
232
232
|
- lib/frameit/editor.rb
|
233
|
-
- lib/frameit/
|
233
|
+
- lib/frameit/frame_downloader.rb
|
234
234
|
- lib/frameit/mac_editor.rb
|
235
235
|
- lib/frameit/offsets.rb
|
236
236
|
- lib/frameit/options.rb
|
@@ -1,99 +0,0 @@
|
|
1
|
-
module Frameit
|
2
|
-
class FrameConverter
|
3
|
-
DOWNLOAD_URL = 'https://developer.apple.com/app-store/marketing/guidelines/#images'
|
4
|
-
FRAME_PATH = '.frameit/devices_frames'
|
5
|
-
|
6
|
-
def run
|
7
|
-
self.setup_frames
|
8
|
-
end
|
9
|
-
|
10
|
-
def setup_frames
|
11
|
-
UI.success "----------------------------------------------------"
|
12
|
-
UI.success "Looks like you'd like to install new device templates"
|
13
|
-
UI.success "The images can not be pre-installed due to licensing"
|
14
|
-
UI.success "Press Enter to get started"
|
15
|
-
UI.success "----------------------------------------------------"
|
16
|
-
STDIN.gets
|
17
|
-
|
18
|
-
system("open '#{DOWNLOAD_URL}'")
|
19
|
-
UI.success "----------------------------------------------------"
|
20
|
-
UI.success "Download the zip files for the following devices"
|
21
|
-
UI.success "iPhone 6s, iPhone 6s Plus, iPhone SE, iPad mini 4 and iPad Pro"
|
22
|
-
UI.success "You only need to download the devices you want to use"
|
23
|
-
UI.success "Press Enter when you downloaded the zip files"
|
24
|
-
UI.success "----------------------------------------------------"
|
25
|
-
STDIN.gets
|
26
|
-
|
27
|
-
loop do
|
28
|
-
system("mkdir -p '#{templates_path}' && open '#{templates_path}'")
|
29
|
-
UI.success "----------------------------------------------------"
|
30
|
-
UI.success "Extract the downloaded files into the folder"
|
31
|
-
UI.success "'#{templates_path}', which should be open in your Finder"
|
32
|
-
UI.success "You can just copy the whole content into it."
|
33
|
-
UI.success "Press Enter when you extracted the files into the given folder"
|
34
|
-
UI.success "----------------------------------------------------"
|
35
|
-
STDIN.gets
|
36
|
-
|
37
|
-
if !frames_exist?
|
38
|
-
UI.error "Sorry, I can't find the PSD files. Make sure you unzipped them into '#{templates_path}'"
|
39
|
-
else
|
40
|
-
break # everything is finished
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
convert_frames
|
45
|
-
end
|
46
|
-
|
47
|
-
def frames_exist?
|
48
|
-
(Dir["#{templates_path}/**/*.psd"].count + Dir["../**/*sRGB.png"].count) > 0
|
49
|
-
end
|
50
|
-
|
51
|
-
def templates_path
|
52
|
-
"#{ENV['HOME']}/#{FRAME_PATH}"
|
53
|
-
end
|
54
|
-
|
55
|
-
# Converts all the PSD files to trimmed PNG files
|
56
|
-
def convert_frames
|
57
|
-
MiniMagick.configure do |config|
|
58
|
-
config.validate_on_create = false
|
59
|
-
end
|
60
|
-
|
61
|
-
Dir["#{templates_path}/**/*.psd"].each do |psd|
|
62
|
-
resulting_path = psd.gsub('.psd', '.png')
|
63
|
-
next if File.exist?(resulting_path)
|
64
|
-
|
65
|
-
UI.important "Converting PSD file '#{psd}'"
|
66
|
-
image = MiniMagick::Image.open(psd)
|
67
|
-
|
68
|
-
if psd =~ /iPhone-SE/
|
69
|
-
UI.success "Removing white background 🚫 ⬜️"
|
70
|
-
|
71
|
-
# The iPhone-SE screenshots from April 2016 have
|
72
|
-
# 3 layers, a background, a product, and the 'put your image here' layer
|
73
|
-
# imagemagick seems to add an additional layer with no label which this the
|
74
|
-
# composite of all three. We want to remove the background and composite layer
|
75
|
-
good_layers = image.layers.reject do |layer|
|
76
|
-
label = layer.details['Properties']['label']
|
77
|
-
label.to_s.length == 0 || label =~ /White B/i
|
78
|
-
end
|
79
|
-
product_layer = good_layers.shift
|
80
|
-
|
81
|
-
good_layers.each do |layer|
|
82
|
-
product_layer.layers << layer
|
83
|
-
end
|
84
|
-
|
85
|
-
image = product_layer
|
86
|
-
end
|
87
|
-
|
88
|
-
if image
|
89
|
-
image.format 'png'
|
90
|
-
image.trim
|
91
|
-
|
92
|
-
image.write(resulting_path)
|
93
|
-
else
|
94
|
-
UI.error "Could not parse PSD file at path '#{psd}'"
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|