lgtm_hd 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +6 -0
- data/README.md +6 -2
- data/bin/lgtm_hd +2 -3
- data/lgtm_hd.gemspec +2 -0
- data/lib/lgtm_hd.rb +4 -122
- data/lib/lgtm_hd/cli.rb +13 -22
- data/lib/lgtm_hd/configuration.rb +8 -8
- data/lib/lgtm_hd/meme_generator.rb +118 -0
- data/lib/lgtm_hd/utilities.rb +5 -0
- data/lib/lgtm_hd/version.rb +1 -1
- metadata +32 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 690ffa92888775481986a81d37f5283cb85b5736
|
4
|
+
data.tar.gz: 9004f97a6135757b9206b11af5189f6af79c5d8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3be3ee8b19592dbcf5be3d03df690a0f24bab103b318ea0953d2c9fa571fe50ed8d03a1536c4141c85ce5b86b115d5a4e646a6a63ca402a4bf36a8a19856464d
|
7
|
+
data.tar.gz: 977302599a8bd739e8e7ee0900a7d19542850ee017e0bae2e41484316642844d690b89498ddcf082869b164780e13964a2ae3a6ad2176246c983cda752e4d508
|
data/.travis.yml
CHANGED
@@ -2,3 +2,9 @@ language: ruby
|
|
2
2
|
rvm:
|
3
3
|
- 2.2.3
|
4
4
|
before_install: gem install bundler -v 1.10.6
|
5
|
+
addons:
|
6
|
+
code_climate:
|
7
|
+
repo_token: f8de4766221c1d212d7c884d1415314f1c55a24c1a58e16db530efbf155d1ad3
|
8
|
+
# regular test configuration
|
9
|
+
after_success:
|
10
|
+
- bundle exec codeclimate-test-reporter
|
data/README.md
CHANGED
@@ -23,10 +23,14 @@ Source | Happy Taeyeon!
|
|
23
23
|
|
24
24
|
## Usage
|
25
25
|
|
26
|
-
$ lgtm_hd [transform] <
|
26
|
+
$ lgtm_hd [transform] <source_uri> <output_folder> [--clipboard] [--interactive]
|
27
27
|
$ lgtm_hd http://domain.com/image.jpg /path/lgtm.jpg
|
28
28
|
|
29
|
-
|
29
|
+
|
30
|
+
--clipboard will let the OS copy content of the file for direct pasting to Github comment box
|
31
|
+
--interactive is for lazy people who can\'t bother to type
|
32
|
+
Default command is transform so you can just leave the command empty.
|
33
|
+
|
30
34
|
|
31
35
|
## Features
|
32
36
|
|
data/bin/lgtm_hd
CHANGED
data/lgtm_hd.gemspec
CHANGED
@@ -33,6 +33,8 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_development_dependency "bundler", "~> 1.10"
|
34
34
|
spec.add_development_dependency "rake", "~> 10.0"
|
35
35
|
spec.add_development_dependency "rspec", "3.6.0"
|
36
|
+
spec.add_development_dependency "simplecov"
|
37
|
+
spec.add_development_dependency "codeclimate-test-reporter", "~> 1.0.0"
|
36
38
|
spec.add_runtime_dependency "commander", "4.4.3"
|
37
39
|
spec.add_runtime_dependency "clipboard", "1.1.1"
|
38
40
|
spec.add_runtime_dependency "os", "1.0.0"
|
data/lib/lgtm_hd.rb
CHANGED
@@ -1,123 +1,5 @@
|
|
1
|
+
require "lgtm_hd/version"
|
1
2
|
require "lgtm_hd/configuration"
|
2
|
-
require "
|
3
|
-
require "
|
4
|
-
|
5
|
-
module LgtmHD
|
6
|
-
|
7
|
-
class MemeGenerator
|
8
|
-
attr_accessor :input_image_URI, :output_image_URI
|
9
|
-
|
10
|
-
# TODO make options list for this class
|
11
|
-
# TODO pass BLOB data into this class instead of paths
|
12
|
-
def initialize(input_image_URI, output_image_URI)
|
13
|
-
@input_image_URI = input_image_URI
|
14
|
-
@output_image_URI = output_image_URI
|
15
|
-
|
16
|
-
@img = MiniMagick::Image.open(@input_image_URI)
|
17
|
-
@caption_position = :caption_position_bottom
|
18
|
-
end
|
19
|
-
|
20
|
-
##
|
21
|
-
# Used to create a new Image object data-copy. Not used to "paint" or
|
22
|
-
# that kind of thing.
|
23
|
-
#
|
24
|
-
# @param caption_text [String] Specify the caption for your LGTM meme
|
25
|
-
# @return [MiniMagick::Image] The drawn image
|
26
|
-
#
|
27
|
-
def draw (caption_text = "LGTM")
|
28
|
-
if @img.respond_to? (:combine_options) then
|
29
|
-
@img.combine_options do |c|
|
30
|
-
c.gravity captionPosition()
|
31
|
-
c.draw "text 0,0 " << "#{caption_text}"
|
32
|
-
c.font captionFont
|
33
|
-
c.pointsize captionFontSize
|
34
|
-
c.density imageDensity
|
35
|
-
c.fill captionColor
|
36
|
-
c.resize imageMaxSize().reduce() {|w,h| w << 'x' << h} # syntax: convert -resize $wx$h
|
37
|
-
end
|
38
|
-
@img.contrast
|
39
|
-
end
|
40
|
-
yield @img if block_given?
|
41
|
-
end
|
42
|
-
|
43
|
-
def export
|
44
|
-
@img.write(@output_image_URI)
|
45
|
-
yield @output_image_URI if block_given?
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def imageMaxSize
|
52
|
-
[Configuration::OUTPUT_MAX_WIDTH.to_s, Configuration::OUTPUT_MAX_HEIGHT.to_s]
|
53
|
-
end
|
54
|
-
|
55
|
-
##
|
56
|
-
# @return [String] the position of image
|
57
|
-
# Could be either :caption_position_top or :caption_position_bottom
|
58
|
-
#
|
59
|
-
def captionPosition ()
|
60
|
-
if not [:caption_position_top, :caption_position_bottom].include? (@caption_position)
|
61
|
-
@caption_position = :caption_position_top
|
62
|
-
end
|
63
|
-
return {:caption_position_top => "north center",
|
64
|
-
:caption_position_bottom => "south center"}[@caption_position]
|
65
|
-
end
|
66
|
-
|
67
|
-
def captionFont
|
68
|
-
'' << LgtmHD.root << Configuration::FONT_PATH
|
69
|
-
end
|
70
|
-
|
71
|
-
def captionFontSize
|
72
|
-
Configuration::CAPTION_FONT_SIZE_DEFAULT
|
73
|
-
end
|
74
|
-
|
75
|
-
def imageDensity
|
76
|
-
Configuration::OUTPUT_DENSITY
|
77
|
-
end
|
78
|
-
|
79
|
-
##
|
80
|
-
# Decide foreground color depending on background color
|
81
|
-
# https://en.wikipedia.org/wiki/Rec._601
|
82
|
-
#
|
83
|
-
# We use this method that include magic numbers .241, .691, .068 accroding to
|
84
|
-
# the provided wikipedia link
|
85
|
-
# Math.Sqrt(
|
86
|
-
# c.R * c.R * .241 +
|
87
|
-
# c.G * c.G * .691 +
|
88
|
-
# c.B * c.B * .068)
|
89
|
-
#
|
90
|
-
# Magic cut off number is 130.
|
91
|
-
# Under 130 is too dark, so the foreground color is white
|
92
|
-
# Above is too bright so the foreground color is black
|
93
|
-
#
|
94
|
-
# @return [String] the foreground color of caption
|
95
|
-
#
|
96
|
-
def captionColor
|
97
|
-
# Copy current image data instead of working directly on working file
|
98
|
-
img = MiniMagick::Image.read(@img.to_blob)
|
99
|
-
|
100
|
-
# cutoff's x is always 0 as we only support top or bottom right now
|
101
|
-
cutoff_y = @caption_position == :caption_position_bottom ? (img.height/2).round : 0
|
102
|
-
img.crop("#{img.width}x#{img.height/2}+0+#{cutoff_y}")
|
103
|
-
|
104
|
-
# Since we are getting
|
105
|
-
img = img.resize('1x1')
|
106
|
-
rgb = img.get_pixels[0][0] # Only 1x1 pixel remember? ^_^
|
107
|
-
color = {}
|
108
|
-
['r','g','b'].zip(rgb) { |k,v| color[k] = v }
|
109
|
-
|
110
|
-
magic_color_value = color['r'] * color['r'] * 0.241
|
111
|
-
magic_color_value += color['g'] * color['g'] * 0.691
|
112
|
-
magic_color_value += color['b'] * color['b'] * 0.068
|
113
|
-
magic_color_value = Math.sqrt(magic_color_value)
|
114
|
-
|
115
|
-
return (magic_color_value.round > 130) ? "#000000" : "#FFFFFF"
|
116
|
-
end
|
117
|
-
|
118
|
-
end # End of Class
|
119
|
-
|
120
|
-
def self.root
|
121
|
-
File.expand_path '../..', __FILE__
|
122
|
-
end
|
123
|
-
end # End of Module
|
3
|
+
require "lgtm_hd/utilities"
|
4
|
+
require "lgtm_hd/meme_generator"
|
5
|
+
require "lgtm_hd/cli"
|
data/lib/lgtm_hd/cli.rb
CHANGED
@@ -1,15 +1,9 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'commander'
|
3
3
|
require 'os'
|
4
|
-
require 'net/http'
|
5
|
-
require 'tempfile'
|
6
4
|
require 'clipboard'
|
7
5
|
require 'uri'
|
8
6
|
|
9
|
-
require 'lgtm_hd'
|
10
|
-
require 'lgtm_hd/version'
|
11
|
-
require 'lgtm_hd/configuration'
|
12
|
-
|
13
7
|
module LgtmHD
|
14
8
|
class CLI
|
15
9
|
include Commander::Methods
|
@@ -21,7 +15,7 @@ module LgtmHD
|
|
21
15
|
default_command :transform
|
22
16
|
|
23
17
|
command :transform do |c|
|
24
|
-
c.syntax = 'lgtm_hd
|
18
|
+
c.syntax = 'lgtm_hd <source_uri> <output_path> [--clipboard] [--interactive]'
|
25
19
|
c.summary = 'Generate a LGTM image from source_uri (local path or URL) into output folder'
|
26
20
|
c.description = ''
|
27
21
|
c.example '', 'lgtm_hd export http://domain.com/image.png /path/to/lgtm.png'
|
@@ -32,37 +26,34 @@ module LgtmHD
|
|
32
26
|
to_clipboard = options.clipboard
|
33
27
|
|
34
28
|
# ARGS validation!
|
35
|
-
if args.length == 2
|
29
|
+
if args.length == 2
|
36
30
|
source_uri = args[0]
|
37
31
|
output_uri = args[1]
|
38
|
-
|
39
32
|
elsif options.interactive # Interactive mode!
|
40
33
|
say "-- LGTM Interactive mode --"
|
41
34
|
source_uri = ask('Source (URL or Path/to/file): ')
|
42
|
-
output_uri = ask('Output Folder
|
43
|
-
# TODO accept relative path "~/.."
|
35
|
+
output_uri = ask('Output Folder: ')
|
44
36
|
to_clipboard = agree("Copy to clipboard afterward? [Y/N]")
|
45
37
|
else
|
46
|
-
|
38
|
+
say "usage: lgtm_hd <source_uri> <output_path> [--clipboard] [--interactive]"
|
39
|
+
raise ArgumentError, "Too few or too many arguments provided, need 2: source and output URIs"
|
47
40
|
end
|
48
41
|
|
49
42
|
|
50
43
|
# Validate the inputs
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
44
|
+
output_folder = File.expand_path(output_uri)
|
45
|
+
output_file = File.join(output_folder,
|
46
|
+
LgtmHD::Configuration::OUTPUT_PREFIX +
|
47
|
+
Time.now.strftime('%Y-%m-%d_%H-%M-%S') +
|
48
|
+
File.extname(source_uri))
|
49
|
+
raise "Source is not proper URIs (URL or Path/to/file)" unless source_uri =~ URI::regexp || File.exist?(source_uri)
|
50
|
+
raise "Output is invalid path or directory" unless File.exist?(output_folder) && File.directory?(output_folder)
|
55
51
|
|
56
|
-
unless File.exist?(output_uri) and File.directory?(output_uri) then
|
57
|
-
raise "Output is not a directory or valid path"
|
58
|
-
end
|
59
52
|
|
60
|
-
file_ext = File.extname(source_uri)
|
61
|
-
output_uri = File.join(output_uri, "" << LgtmHD::Configuration::OUTPUT_PREFIX << Time.now.strftime('%Y-%m-%d_%H-%M-%S') << file_ext)
|
62
53
|
|
63
54
|
# Do stuff with our LGTM meme
|
64
55
|
say "- Reading and inspecting source"
|
65
|
-
meme_generator = MemeGenerator.new(source_uri,
|
56
|
+
meme_generator = MemeGenerator.new(input_image_uri:source_uri, output_image_uri:output_file)
|
66
57
|
say "- Rendering output"
|
67
58
|
meme_generator.draw
|
68
59
|
|
@@ -1,18 +1,18 @@
|
|
1
1
|
module LgtmHD
|
2
2
|
module Configuration
|
3
3
|
# Program configurations
|
4
|
-
PROGRAM_NAME
|
5
|
-
DESCRIPTION
|
4
|
+
PROGRAM_NAME = "lgtm_hd".freeze
|
5
|
+
DESCRIPTION = "Generating images from user input with LGTM text on it, or fetching images from LGTM.in based on user's query. Finally put the image to clipboard.".freeze
|
6
6
|
|
7
7
|
# Output Image configurations
|
8
|
-
OUTPUT_PREFIX
|
9
|
-
OUTPUT_MAX_WIDTH
|
10
|
-
OUTPUT_MAX_HEIGHT
|
11
|
-
OUTPUT_DENSITY
|
8
|
+
OUTPUT_PREFIX = "lgtm_hd_".freeze
|
9
|
+
OUTPUT_MAX_WIDTH = 500.freeze
|
10
|
+
OUTPUT_MAX_HEIGHT = 500.freeze
|
11
|
+
OUTPUT_DENSITY = 90.freeze # or 120 point per inch
|
12
12
|
|
13
13
|
# Caption configurations
|
14
|
-
FONT_PATH
|
15
|
-
CAPTION_FONT_SIZE_DEFAULT
|
14
|
+
FONT_PATH = "/fonts/impact.ttf".freeze
|
15
|
+
CAPTION_FONT_SIZE_DEFAULT = 96.freeze
|
16
16
|
|
17
17
|
end
|
18
18
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require "mini_magick"
|
2
|
+
|
3
|
+
module LgtmHD
|
4
|
+
class MemeGenerator
|
5
|
+
|
6
|
+
# TODO make options list for this class
|
7
|
+
# TODO pass BLOB data into this class instead of paths
|
8
|
+
def initialize(input_image_uri:, output_image_uri:)
|
9
|
+
@input_image_uri = input_image_uri
|
10
|
+
@output_image_uri = output_image_uri
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Used to create a new Image object data-copy. Not used to "paint" or
|
15
|
+
# that kind of thing.
|
16
|
+
#
|
17
|
+
# @param caption_text [String] Specify the caption for your LGTM meme
|
18
|
+
# @return [MiniMagick::Image] The drawn image
|
19
|
+
#
|
20
|
+
def draw(caption_text = "LGTM")
|
21
|
+
img = image
|
22
|
+
img.combine_options do |c|
|
23
|
+
c.gravity caption_position
|
24
|
+
c.draw "text 0,0 " << caption_text
|
25
|
+
c.font caption_font
|
26
|
+
c.pointsize caption_font_size
|
27
|
+
c.density image_density
|
28
|
+
c.fill caption_color
|
29
|
+
c.resize image_max_size().reduce() {|w,h| "#{w}x#{h}"} # syntax: convert -resize $wx$h
|
30
|
+
img.contrast
|
31
|
+
end
|
32
|
+
yield img if block_given?
|
33
|
+
end
|
34
|
+
|
35
|
+
def export
|
36
|
+
image.write(@output_image_uri)
|
37
|
+
yield @output_image_uri if block_given?
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def image
|
44
|
+
@image ||= MiniMagick::Image.open(@input_image_uri)
|
45
|
+
end
|
46
|
+
|
47
|
+
def image_max_size
|
48
|
+
[Configuration::OUTPUT_MAX_WIDTH, Configuration::OUTPUT_MAX_HEIGHT]
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# @return [String] the position of image
|
53
|
+
# Could be either :caption_position_top or :caption_position_bottom
|
54
|
+
# Default value is top
|
55
|
+
#
|
56
|
+
def caption_position
|
57
|
+
if not [:caption_position_top, :caption_position_bottom].include? (@caption_position)
|
58
|
+
@caption_position = :caption_position_bottom
|
59
|
+
end
|
60
|
+
return {:caption_position_top => "north center",
|
61
|
+
:caption_position_bottom => "south center"}[@caption_position]
|
62
|
+
end
|
63
|
+
|
64
|
+
def caption_font
|
65
|
+
File.join(LgtmHD::gem_root, Configuration::FONT_PATH)
|
66
|
+
end
|
67
|
+
|
68
|
+
def caption_font_size
|
69
|
+
Configuration::CAPTION_FONT_SIZE_DEFAULT
|
70
|
+
end
|
71
|
+
|
72
|
+
def image_density
|
73
|
+
Configuration::OUTPUT_DENSITY
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# Decide foreground color depending on background color
|
78
|
+
# https://en.wikipedia.org/wiki/Rec._601
|
79
|
+
#
|
80
|
+
# We use this method that include magic numbers .241, .691, .068 accroding to
|
81
|
+
# the provided wikipedia link
|
82
|
+
# Math.Sqrt(
|
83
|
+
# c.R * c.R * .241 +
|
84
|
+
# c.G * c.G * .691 +
|
85
|
+
# c.B * c.B * .068)
|
86
|
+
#
|
87
|
+
# Magic cut off number is 130.
|
88
|
+
# Under 130 is too dark, so the foreground color is white
|
89
|
+
# Above is too bright so the foreground color is black
|
90
|
+
#
|
91
|
+
# @return [String] the foreground color of caption
|
92
|
+
#
|
93
|
+
def caption_color
|
94
|
+
# Copy current image data instead of working directly on working file
|
95
|
+
# because ImageMagick apply change directly to the temporary working file instead of keep changes in memory
|
96
|
+
# Might need to invest a bit further to ensure this, as for now, lazy..
|
97
|
+
temp_img = MiniMagick::Image.read(image.to_blob)
|
98
|
+
|
99
|
+
# cutoff's x is always 0 as we only support top or bottom right now
|
100
|
+
cutoff_y = @caption_position == :caption_position_bottom ? (temp_img.height/2).round : 0
|
101
|
+
temp_img.crop("#{temp_img.width}x#{temp_img.height/2}+0+#{cutoff_y}")
|
102
|
+
|
103
|
+
# Since we are getting
|
104
|
+
temp_img = temp_img.resize('1x1')
|
105
|
+
rgb = temp_img.get_pixels[0][0] # Only 1x1 pixel remember? ^_^
|
106
|
+
color = {}
|
107
|
+
['r','g','b'].zip(rgb) { |k,v| color[k] = v }
|
108
|
+
|
109
|
+
magic_color_value = color['r'] * color['r'] * 0.241
|
110
|
+
magic_color_value += color['g'] * color['g'] * 0.691
|
111
|
+
magic_color_value += color['b'] * color['b'] * 0.068
|
112
|
+
magic_color_value = Math.sqrt(magic_color_value)
|
113
|
+
|
114
|
+
(magic_color_value.round > 130) ? "#000000" : "#FFFFFF"
|
115
|
+
end
|
116
|
+
|
117
|
+
end # End of Class
|
118
|
+
end # End of module
|
data/lib/lgtm_hd/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lgtm_hd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Huy Dinh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,34 @@ dependencies:
|
|
52
52
|
- - '='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 3.6.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: simplecov
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: codeclimate-test-reporter
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.0.0
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.0.0
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: commander
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,6 +162,8 @@ files:
|
|
134
162
|
- lib/lgtm_hd.rb
|
135
163
|
- lib/lgtm_hd/cli.rb
|
136
164
|
- lib/lgtm_hd/configuration.rb
|
165
|
+
- lib/lgtm_hd/meme_generator.rb
|
166
|
+
- lib/lgtm_hd/utilities.rb
|
137
167
|
- lib/lgtm_hd/version.rb
|
138
168
|
homepage: http://github.com/phradion/lgtm_hd
|
139
169
|
licenses:
|