distorted 0.5.7 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/distorted/checking_you_out.rb +116 -0
- data/lib/distorted/error_code.rb +43 -0
- data/lib/distorted/injection_of_love.rb +247 -0
- data/lib/distorted/modular_technology/pango.rb +20 -5
- data/lib/distorted/modular_technology/triple_counter.rb +45 -0
- data/lib/distorted/modular_technology/ttfunk.rb +48 -0
- data/lib/distorted/modular_technology/vips.rb +17 -0
- data/lib/distorted/modular_technology/vips_load.rb +77 -0
- data/lib/distorted/modular_technology/vips_save.rb +172 -0
- data/lib/distorted/molecule/C18H27NO3.rb +10 -0
- data/lib/distorted/{font.rb → molecule/font.rb} +33 -27
- data/lib/distorted/molecule/image.rb +36 -0
- data/lib/distorted/{pdf.rb → molecule/pdf.rb} +23 -14
- data/lib/distorted/molecule/svg.rb +60 -0
- data/lib/distorted/{text.rb → molecule/text.rb} +70 -86
- data/lib/distorted/{video.rb → molecule/video.rb} +9 -7
- data/lib/distorted/types/README +4 -0
- data/lib/distorted/types/application.yaml +8 -0
- data/lib/distorted/types/font.yaml +29 -0
- data/lib/distorted/version.rb +3 -1
- metadata +33 -8
- data/lib/distorted/image.rb +0 -121
- data/lib/distorted/svg.rb +0 -21
@@ -0,0 +1,45 @@
|
|
1
|
+
TripleCounter = Struct.new(:major, :minor, :micro) do
|
2
|
+
attr_reader :major, :minor, :micro
|
3
|
+
|
4
|
+
def initialize(major = 0, minor = 0, micro = 0)
|
5
|
+
@major = major
|
6
|
+
@minor = minor
|
7
|
+
@micro = micro
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
[major, minor, micro].join('.'.freeze)
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(otra)
|
15
|
+
major == otra.major && minor == otra.minor
|
16
|
+
end
|
17
|
+
|
18
|
+
def ===(otra)
|
19
|
+
all_operator(otra, :==)
|
20
|
+
end
|
21
|
+
|
22
|
+
def >=(otra)
|
23
|
+
all_operator(otra, :>=)
|
24
|
+
end
|
25
|
+
|
26
|
+
def <=(otra)
|
27
|
+
all_operator(otra, :<=)
|
28
|
+
end
|
29
|
+
|
30
|
+
def >(otra)
|
31
|
+
all_operator(otra, :>)
|
32
|
+
end
|
33
|
+
|
34
|
+
def <(otra)
|
35
|
+
all_operator(otra, :<)
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_array
|
39
|
+
[major, minor, micro]
|
40
|
+
end
|
41
|
+
|
42
|
+
def all_operator(otra, operator)
|
43
|
+
to_array.zip(otra.to_array).all?{|us, otra| us.send(operator, otra)}
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'ttfunk'
|
2
|
+
|
3
|
+
module Cooltrainer; end
|
4
|
+
module Cooltrainer::DistorteD; end
|
5
|
+
module Cooltrainer::DistorteD::Technology; end
|
6
|
+
module Cooltrainer::DistorteD::Technology::TTFunk
|
7
|
+
|
8
|
+
def to_ttfunk
|
9
|
+
# TODO: Check that src exists, because TTFunk won't and will just
|
10
|
+
# give us an unusable object instead.
|
11
|
+
@ttfunk_file ||= TTFunk::File.open(font_path)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns a boolean for whether or not this font is monospaced.
|
15
|
+
# true == monospace
|
16
|
+
# false == proportional
|
17
|
+
def font_spacing
|
18
|
+
# Monospace fonts will (read: should) have the same width
|
19
|
+
# for every glyph, so we can tell a monospace font by
|
20
|
+
# checking if a deduplicated widths table has size == 1:
|
21
|
+
# irb(main)> font.horizontal_metrics.widths.count
|
22
|
+
# => 256
|
23
|
+
# irb(main)> font.horizontal_metrics.widths.uniq.compact.length
|
24
|
+
# => 1
|
25
|
+
to_ttfunk.horizontal_metrics.widths.uniq.compact.length == 1 ? :monospace : :proportional
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns the Family and Subfamily as one string suitable for libvips
|
29
|
+
def font_name
|
30
|
+
"#{to_ttfunk.name.font_family.first.encode('UTF-8')} #{to_ttfunk.name.font_subfamily.first.encode('UTF-8')}"
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the Pango-Markup-encoded UTF-8 String version + revision of the font
|
34
|
+
def font_version
|
35
|
+
g_markup_escape_text(to_ttfunk.name&.version&.first&.encode('UTF-8').to_s)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the Pango-Markup-encoded UTF-8 String font file description
|
39
|
+
def font_description
|
40
|
+
g_markup_escape_text(to_ttfunk.name&.description&.first&.encode('UTF-8').to_s)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns the Pango-Markup-encoded UTF-8 String copyright information of the font
|
44
|
+
def font_copyright
|
45
|
+
g_markup_escape_text(to_ttfunk.name&.copyright&.first&.encode('UTF-8').to_s)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require 'distorted/checking_you_out'
|
4
|
+
|
5
|
+
require 'distorted/modular_technology/vips_load'
|
6
|
+
require 'distorted/modular_technology/vips_save'
|
7
|
+
|
8
|
+
|
9
|
+
module Cooltrainer; end
|
10
|
+
module Cooltrainer::DistorteD; end
|
11
|
+
module Cooltrainer::DistorteD::Technology; end
|
12
|
+
module Cooltrainer::DistorteD::Technology::Vips
|
13
|
+
|
14
|
+
include Cooltrainer::DistorteD::Technology::VipsSave
|
15
|
+
include Cooltrainer::DistorteD::Technology::VipsLoad
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
require 'distorted/checking_you_out'
|
5
|
+
require 'distorted/modular_technology/vips_save'
|
6
|
+
|
7
|
+
|
8
|
+
module Cooltrainer; end
|
9
|
+
module Cooltrainer::DistorteD; end
|
10
|
+
module Cooltrainer::DistorteD::Technology; end
|
11
|
+
module Cooltrainer::DistorteD::Technology::VipsLoad
|
12
|
+
|
13
|
+
# Returns a Set of MIME::Types based on libvips LipsForeignLoad capabilities.
|
14
|
+
# NOTE: libvips only declares support (via :get_suffixes) for the "saver" types,
|
15
|
+
# but libvips can use additional external libraries for wider media-types support, e.g.:
|
16
|
+
#
|
17
|
+
# - SVG with librsvg2★ / libcairo. [*]
|
18
|
+
# - PDF with PDFium if available, otherwise with libpoppler-glib / libcairo.
|
19
|
+
# - OpenEXR/libIlmImf — ILM high dynamic range image format.
|
20
|
+
# - maybe more: https://github.com/libvips/libvips/blob/master/configure.ac
|
21
|
+
#
|
22
|
+
# [FITS]: https://heasarc.gsfc.nasa.gov/docs/heasarc/fits.html
|
23
|
+
#
|
24
|
+
# [RSVG2]: This is the normal SVG library for the GNOME/GLib world and is
|
25
|
+
# probably fine for 95% of use-cases, but I'm pissed off at it because of:
|
26
|
+
#
|
27
|
+
# - https://gitlab.gnome.org/GNOME/librsvg/-/issues/56
|
28
|
+
# - https://gitlab.gnome.org/GNOME/librsvg/-/issues/100
|
29
|
+
# - https://gitlab.gnome.org/GNOME/librsvg/-/issues/183
|
30
|
+
# - https://gitlab.gnome.org/GNOME/librsvg/-/issues/494
|
31
|
+
# - https://bugzilla.gnome.org/show_bug.cgi?id=666477
|
32
|
+
# - https://phabricator.wikimedia.org/T35245
|
33
|
+
#
|
34
|
+
# TLDR: SVG <tspan> elements' [:x, :y, :dy, :dx] attributes can be
|
35
|
+
# a space-delimited list of position values for individual
|
36
|
+
# characters in the <tspan>, but librsvg2 only supported reading
|
37
|
+
# those attributes as a single one-shot numeric value.
|
38
|
+
# Documents using this totally-common and totally-in-spec feature
|
39
|
+
# rendered incorrectly with librsvg2. Effected <tspan> elements'
|
40
|
+
# subsequent children would hug one edge of the rendered output.
|
41
|
+
#
|
42
|
+
# And wouldn't you know it but the one (1) SVG on my website
|
43
|
+
# at the time I built this feature (IIDX-Turntable-parts.svg) used
|
44
|
+
# this feature for the double-digit parts diagram labels.
|
45
|
+
# I ended up having to edit my input document to just squash the
|
46
|
+
# offending <tspan>s down to a single child each.
|
47
|
+
# I guess that's semantically more correct in my document since they are
|
48
|
+
# numbers like Eleven and not two separate characters like '1 1'
|
49
|
+
# but still ugh lol
|
50
|
+
#
|
51
|
+
# This was finally fixed in 2019 as of librsvg2 version 2.45.91 :)
|
52
|
+
# https://gitlab.gnome.org/GNOME/librsvg/-/issues/494#note_579774
|
53
|
+
#
|
54
|
+
|
55
|
+
# TODO: Figure out how to detect non-Magick non-Saver Loader support,
|
56
|
+
# by which I mean "everything not included in :get_suffixes".
|
57
|
+
# NOTE: The Magick-based '.bmp' loader is broken/missing in libvips <= 8.9.1:
|
58
|
+
# https://github.com/libvips/libvips/issues/1528
|
59
|
+
# irb> MIME::Types.type_for('.bmp')
|
60
|
+
# => [#<MIME::Type: image/bmp>, #<MIME::Type: image/x-bmp>, #<MIME::Type: image/x-ms-bmp>]
|
61
|
+
# irb> MIME::Types.type_for('.bmp').map(&:preferred_extension)
|
62
|
+
# => ["bmp", "bmp", "bmp"]
|
63
|
+
LOWER_WORLD = (VIPS_AVAILABLE_VER < TripleCounter.new(8, 9, 1)) ?
|
64
|
+
Cooltrainer::DistorteD::Technology::VipsSave::OUTER_LIMITS.keep_if { |t| t.preferred_extension != 'bmp'.freeze } :
|
65
|
+
Cooltrainer::DistorteD::Technology::VipsSave::OUTER_LIMITS
|
66
|
+
|
67
|
+
def to_vips_image
|
68
|
+
# TODO: Learn more about what VipsAccess means for our use case,
|
69
|
+
# if the default should be changed, and if it should be
|
70
|
+
# a user-controllable attr or not.
|
71
|
+
# https://libvips.github.io/libvips/API/current/VipsImage.html#VipsAccess
|
72
|
+
# https://libvips.github.io/libvips/API/current/How-it-opens-files.md.html
|
73
|
+
@vips_image ||= Vips::Image.new_from_file(path)
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
|
2
|
+
# Requiring libvips 8.8 for HEIC/HEIF (moo) support, `justify` support in the
|
3
|
+
# Vips::Image text operator, animated WebP support, and more:
|
4
|
+
# https://libvips.github.io/libvips/2019/04/22/What's-new-in-8.8.html
|
5
|
+
|
6
|
+
require 'distorted/modular_technology/triple_counter'
|
7
|
+
VIPS_MINIMUM_VER = TripleCounter.new(8, 8, 0)
|
8
|
+
|
9
|
+
# Tell the user to install the shared library if it's missing.
|
10
|
+
begin
|
11
|
+
require 'vips'
|
12
|
+
VIPS_AVAILABLE_VER = TripleCounter.new(Vips::version(0), Vips::version(1), Vips::version(2))
|
13
|
+
|
14
|
+
unless VIPS_AVAILABLE_VER >= VIPS_MINIMUM_VER
|
15
|
+
raise LoadError.new(
|
16
|
+
"DistorteD needs libvips #{VIPS_MINIMUM_VER}, but the available version is '#{Vips::version_string}'"
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
rescue LoadError => le
|
21
|
+
# Only match libvips.so load failure
|
22
|
+
raise unless le.message =~ /libvips.so/
|
23
|
+
|
24
|
+
# Multiple OS help
|
25
|
+
help = <<~INSTALL
|
26
|
+
|
27
|
+
Please install the VIPS (libvips) image processing library, version #{VIPS_MINIMUM_VER} or later.
|
28
|
+
|
29
|
+
FreeBSD:
|
30
|
+
pkg install graphics/vips
|
31
|
+
|
32
|
+
macOS:
|
33
|
+
brew install vips
|
34
|
+
|
35
|
+
Debian/Ubuntu/Mint:
|
36
|
+
apt install libvips libvips-dev
|
37
|
+
INSTALL
|
38
|
+
|
39
|
+
# Re-raise with install message
|
40
|
+
raise $!, "#{help}\n#{$!}", $!.backtrace
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
require 'set'
|
45
|
+
|
46
|
+
require 'distorted/checking_you_out'
|
47
|
+
|
48
|
+
|
49
|
+
module Cooltrainer; end
|
50
|
+
module Cooltrainer::DistorteD; end
|
51
|
+
module Cooltrainer::DistorteD::Technology; end
|
52
|
+
module Cooltrainer::DistorteD::Technology::VipsSave
|
53
|
+
|
54
|
+
ATTRIBUTES = {
|
55
|
+
:crop => nil,
|
56
|
+
:Q => Set[:quality],
|
57
|
+
}
|
58
|
+
ATTRIBUTES_DEFAULT = {
|
59
|
+
:crop => :attention,
|
60
|
+
}
|
61
|
+
ATTRIBUTES_VALUES = {
|
62
|
+
# https://www.rubydoc.info/gems/ruby-vips/Vips/Interesting
|
63
|
+
:crop => {
|
64
|
+
:none => nil,
|
65
|
+
:centre => Set[:center], # America, FUCK YEAH!
|
66
|
+
:entropy => nil,
|
67
|
+
:attention => nil,
|
68
|
+
},
|
69
|
+
}
|
70
|
+
|
71
|
+
# Returns a Set of MIME::Types based on libvips VipsForeignSave capabilities.
|
72
|
+
# https://libvips.github.io/libvips/API/current/VipsForeignSave.html
|
73
|
+
#
|
74
|
+
# There is one (only one) native libvips image format, with file extname `.vips`.
|
75
|
+
# As I write this—running libvips 8.8—the :get_suffixes function does not include
|
76
|
+
# its own '.vips' as a supported extension.
|
77
|
+
# There also (as of mid 2020) seems to be no official media-type assigned
|
78
|
+
# for VIPS format, so I am going to make one up in CHECKING::YOU::OUT's local-data.
|
79
|
+
# - Raw pixel data
|
80
|
+
#
|
81
|
+
# [RAW]: https://libvips.github.io/libvips/API/current/VipsForeignSave.html#vips-rawload
|
82
|
+
# https://libvips.github.io/libvips/API/current/VipsForeignSave.html#vips-csvload
|
83
|
+
#
|
84
|
+
# Most libvips installations, even very minimally-built ones,
|
85
|
+
# will almost certainly support a few very common formats:
|
86
|
+
# - JPEG with libjpeg.
|
87
|
+
# - PNG with libpng.
|
88
|
+
# - GIF with giflib.
|
89
|
+
# - WebP with libwebp.
|
90
|
+
# - TIFF with libtiff.
|
91
|
+
#
|
92
|
+
# Normal libvips installations probably also support many less-mainstream formats:
|
93
|
+
# - HEIF/HEIC with libheif.
|
94
|
+
# - ICC profiles with liblcms2.
|
95
|
+
# - Matlab with matio/libhdf5.
|
96
|
+
# - FITS★ with cfitsio.
|
97
|
+
# - Styled text with Pango/ft2.
|
98
|
+
# - Saving GIF/BMP with Magick.
|
99
|
+
# NOTE that GIFs are *loaded* using giflib,
|
100
|
+
# and that BMP loading is unsupported.
|
101
|
+
# - Various simple ASCII/binary-based formats with libgsf★
|
102
|
+
# · Comma-separated values
|
103
|
+
# · Netpbm★
|
104
|
+
# · VIPS (non-Matlab) matrices★
|
105
|
+
#
|
106
|
+
# [NETPBM]: https://en.wikipedia.org/wiki/Netpbm#File_formats
|
107
|
+
# [LIBGSF]: https://developer.gnome.org/gsf/
|
108
|
+
# [MATRIX]: https://libvips.github.io/libvips/API/current/VipsForeignSave.html#vips-matrixload
|
109
|
+
|
110
|
+
# Vips allows us to query supported *SAVE* types by suffix.
|
111
|
+
# There's a simple relationship between filetype and extension since
|
112
|
+
# libvips uses the suffix to pick the Saver module.
|
113
|
+
#
|
114
|
+
# Loader modules, on the other hand, are picked by sniffing the
|
115
|
+
# first few bytes of the file, so a list of file extensions for
|
116
|
+
# supported loadable formats won't always be complete.
|
117
|
+
# For example, SVG and PDF are usually supported as loaders
|
118
|
+
# (via rsvg and PDFium/Poppler)
|
119
|
+
# https://github.com/libvips/ruby-vips/issues/186
|
120
|
+
#
|
121
|
+
# irb(main)> Vips.get_suffixes
|
122
|
+
# => [".csv", ".mat", ".v", ".vips", ".ppm", ".pgm", ".pbm", ".pfm",
|
123
|
+
# ".hdr", ".dz", ".png", ".jpg", ".jpeg", ".jpe", ".webp", ".tif",
|
124
|
+
# ".tiff", ".fits", ".fit", ".fts", ".gif", ".bmp"]
|
125
|
+
OUTER_LIMITS = Vips.get_suffixes.map{ |t|
|
126
|
+
# A single call to this will return a Set of MIME::Types for a String input
|
127
|
+
CHECKING::YOU::OUT(t)
|
128
|
+
}.reduce { |c,t|
|
129
|
+
# Flatten the Set-of-Sets-of-Types into a Set-of-Types
|
130
|
+
(c || Set[]).merge(t)
|
131
|
+
}.keep_if { |t|
|
132
|
+
# Filter out any of libvips' supported output Types that aren't
|
133
|
+
# actually images (e.g. CSV)
|
134
|
+
t.media_type == 'image'
|
135
|
+
}
|
136
|
+
|
137
|
+
# Define a to_<mediatype>_<subtype> method for each MIME::Type supported by libvips,
|
138
|
+
# e.g. a supported Type 'image/png' will define a method :to_image_png in any
|
139
|
+
# context where this module is included.
|
140
|
+
self::OUTER_LIMITS.each { |t|
|
141
|
+
define_method(t.distorted_method) { |*a, **k, &b|
|
142
|
+
vips_save(*a, **k, &b)
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
protected
|
147
|
+
|
148
|
+
# Generic Vips saver method, optionally handling resizing and cropping.
|
149
|
+
# NOTE: libvips chooses a saver (internally) based on the extname of the destination path.
|
150
|
+
def vips_save(dest, width: nil, **kw)
|
151
|
+
begin
|
152
|
+
if width.nil? or width == :full
|
153
|
+
return to_vips_image.write_to_file(dest)
|
154
|
+
elsif width.respond_to?(:to_i)
|
155
|
+
ver = to_vips_image.thumbnail_image(
|
156
|
+
width.to_i,
|
157
|
+
# Use `self` namespace for constants so subclasses can redefine
|
158
|
+
**{:crop => abstract(:crop)},
|
159
|
+
)
|
160
|
+
return ver.write_to_file(dest)
|
161
|
+
end
|
162
|
+
rescue Vips::Error => v
|
163
|
+
if v.message.include?('No known saver')
|
164
|
+
# TODO: Handle missing output formats. Replacements? Skip it? Die?
|
165
|
+
return nil
|
166
|
+
else
|
167
|
+
raise
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end # save
|
171
|
+
|
172
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'distorted/injection_of_love'
|
2
|
+
|
3
|
+
module Cooltrainer; end
|
4
|
+
module Cooltrainer::DistorteD; end
|
5
|
+
module Cooltrainer::DistorteD::Molecule; end
|
6
|
+
module Cooltrainer::DistorteD::Molecule::C18H27NO3
|
7
|
+
|
8
|
+
BOOLEAN_ATTR_VALUES = Set[0, 1, false, true, '0'.freeze, '1'.freeze, 'false'.freeze, 'true'.freeze]
|
9
|
+
|
10
|
+
end
|
@@ -3,35 +3,48 @@ require 'set'
|
|
3
3
|
# Font metadata extraction
|
4
4
|
require 'ttfunk'
|
5
5
|
|
6
|
-
require '
|
7
|
-
|
8
|
-
|
9
|
-
require '
|
10
|
-
|
11
|
-
require 'distorted/text'
|
6
|
+
require 'distorted/modular_technology/pango'
|
7
|
+
require 'distorted/modular_technology/ttfunk'
|
8
|
+
require 'distorted/modular_technology/vips_save'
|
9
|
+
require 'distorted/checking_you_out'
|
10
|
+
require 'distorted/injection_of_love'
|
12
11
|
|
13
12
|
|
14
13
|
module Cooltrainer
|
15
14
|
module DistorteD
|
16
|
-
|
15
|
+
module Font
|
17
16
|
|
18
|
-
MEDIA_TYPE = 'font'.freeze
|
19
17
|
|
20
18
|
# TODO: Test OTF, OTB, and others.
|
21
19
|
# NOTE: Traditional bitmap fonts won't be supported due to Pango 1.44
|
22
20
|
# and later switching to Harfbuzz from Freetype:
|
23
21
|
# https://gitlab.gnome.org/GNOME/pango/-/issues/386
|
24
22
|
# https://blogs.gnome.org/mclasen/2019/05/25/pango-future-directions/
|
25
|
-
|
23
|
+
LOWER_WORLD = CHECKING::YOU::IN(/^font\/ttf/)
|
24
|
+
OUTER_LIMITS = CHECKING::YOU::IN(/^font\/ttf/)
|
26
25
|
|
27
|
-
|
26
|
+
ATTRIBUTES = Set[
|
28
27
|
:alt,
|
29
28
|
]
|
30
|
-
|
29
|
+
ATTRIBUTES_VALUES = {
|
31
30
|
}
|
32
|
-
|
31
|
+
ATTRIBUTES_DEFAULT = {
|
32
|
+
}
|
33
|
+
|
34
|
+
|
35
|
+
# Maybe T0DO: Process output with TTFunk instead of only using it
|
36
|
+
# to generate images and metadata.
|
37
|
+
self::OUTER_LIMITS.each { |t|
|
38
|
+
define_method(t.distorted_method) { |*a, **k, &b|
|
39
|
+
copy_file(*a, **k, &b)
|
40
|
+
}
|
33
41
|
}
|
34
42
|
|
43
|
+
include Cooltrainer::DistorteD::Technology::TTFunk
|
44
|
+
include Cooltrainer::DistorteD::Technology::Pango
|
45
|
+
include Cooltrainer::DistorteD::Technology::VipsSave
|
46
|
+
include Cooltrainer::DistorteD::InjectionOfLove
|
47
|
+
|
35
48
|
|
36
49
|
# irb(main):089:0> chars.take(5)
|
37
50
|
# => [[1, 255], [2, 1], [3, 2], [4, 3], [5, 4]]
|
@@ -49,8 +62,8 @@ module Cooltrainer
|
|
49
62
|
output << "<span size='24576'> #{font_version}</span>" << cr << cr
|
50
63
|
|
51
64
|
# Print a preview String in using the loaded font. Or don't.
|
52
|
-
if
|
53
|
-
output << cr << cr << "<span size='24576' foreground='grey'> #{g_markup_escape_text(
|
65
|
+
if abstract(:title)
|
66
|
+
output << cr << cr << "<span size='24576' foreground='grey'> #{g_markup_escape_text(abstract(:title))}</span>" << cr << cr << cr
|
54
67
|
end
|
55
68
|
|
56
69
|
# /!\ MANDATORY READING /!\
|
@@ -71,7 +84,7 @@ module Cooltrainer
|
|
71
84
|
# => 3
|
72
85
|
# irb(main):175:0> font_meta.cmap.unicode.count
|
73
86
|
# => 2
|
74
|
-
|
87
|
+
to_ttfunk.cmap.tables.each do |table|
|
75
88
|
next if !table.unicode?
|
76
89
|
# Each subtable's `code_map` is a Hash map of character codes (the Hash keys)
|
77
90
|
# to the glyph IDs from the original font (the Hash's values).
|
@@ -93,7 +106,7 @@ module Cooltrainer
|
|
93
106
|
encoded.each_pair { |c, (old, new)|
|
94
107
|
|
95
108
|
begin
|
96
|
-
if glyph =
|
109
|
+
if glyph = to_ttfunk.glyph_outlines.for(c)
|
97
110
|
# Add a space on either side of the character so they aren't
|
98
111
|
# all smooshed up against each other and unreadable.
|
99
112
|
output << ' ' << g_markup_escape_char(c) << ' '
|
@@ -133,19 +146,12 @@ module Cooltrainer
|
|
133
146
|
# Return the `src` as the font_path since we aren't using
|
134
147
|
# any of the built-in fonts.
|
135
148
|
def font_path
|
136
|
-
|
149
|
+
path
|
137
150
|
end
|
138
151
|
|
139
|
-
def
|
140
|
-
@src = src
|
141
|
-
@demo = demo
|
142
|
-
|
143
|
-
# TODO: Check that src exists, because TTFunk won't and will just
|
144
|
-
# give us an unusable object instead.
|
145
|
-
@font_meta = TTFunk::File.open(src)
|
146
|
-
|
152
|
+
def to_vips_image
|
147
153
|
# https://libvips.github.io/libvips/API/current/libvips-create.html#vips-text
|
148
|
-
|
154
|
+
Vips::Image.text(
|
149
155
|
# This string must be well-escaped Pango Markup:
|
150
156
|
# https://developer.gnome.org/pango/stable/pango-Markup.html
|
151
157
|
# However the official function for escaping text is
|
@@ -158,7 +164,7 @@ module Cooltrainer
|
|
158
164
|
# we must also specify a font family, subfamily, and size.
|
159
165
|
:font => "#{font_name}",
|
160
166
|
# Space between lines (in Points).
|
161
|
-
:spacing =>
|
167
|
+
:spacing => to_ttfunk.line_gap,
|
162
168
|
# Requires libvips 8.8
|
163
169
|
:justify => false,
|
164
170
|
:dpi => 144,
|