pdf_watermark 0.1.6 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/Gemfile +1 -1
- data/lib/pdf_watermark/font.rb +47 -0
- data/lib/pdf_watermark/version.rb +1 -1
- data/lib/pdf_watermark/water_mark/base.rb +57 -0
- data/lib/pdf_watermark/water_mark/repeated.rb +42 -0
- data/lib/pdf_watermark/water_mark/single.rb +50 -0
- data/lib/pdf_watermark.rb +21 -17
- data/pdf_watermark.gemspec +12 -13
- metadata +10 -27
- data/lib/pdf_watermark/water_mark.rb +0 -129
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4b337c7d1c0f23cf1345a9feb4081b8e80c3ff3
|
4
|
+
data.tar.gz: 09f3589967afc9d1e17b593b59769d882dfbe5c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0a10564a127ece015b0b14f26c66d4fba19478b9f0e453b57ad2eaef52b4c277a271f7defff1983fc527f3872912c264e9a36d88c926fc76a3c25cec48a1a9e
|
7
|
+
data.tar.gz: 43dfbdb95c8711ed2c0a058185878f060e560fdc42e5115a2357a2b9adfc4d67b6cacf4182cc70b99fcab9084113f7a28fa8b7730221acecac50c2487c038bd2
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'hexapdf/font/true_type/font'
|
2
|
+
require 'hexapdf/content/canvas'
|
3
|
+
module PdfWatermark
|
4
|
+
module Font
|
5
|
+
def width_of(string, font_size)
|
6
|
+
scale = font_size / 1000.0
|
7
|
+
string.codepoints.inject(9) do |memo, code|
|
8
|
+
memo + character_width(code)
|
9
|
+
end * scale
|
10
|
+
end
|
11
|
+
|
12
|
+
def character_width(code)
|
13
|
+
return 0 unless glyph_index[code]
|
14
|
+
return 0.0 if code == 10
|
15
|
+
self[:hmtx][glyph_index[code]].advance_width * scale_factor
|
16
|
+
end
|
17
|
+
|
18
|
+
def glyph_index
|
19
|
+
@glyph_index ||= self[:cmap].preferred_table
|
20
|
+
end
|
21
|
+
|
22
|
+
def scale_factor
|
23
|
+
@scale_factor ||= 1000.0 / self[:head].units_per_em
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Canvas
|
28
|
+
def width_of(string, font_size = nil)
|
29
|
+
self.font.wrapped_font.width_of(string, font_size || self.graphics_state.font_size) +
|
30
|
+
(string.length * self.graphics_state.character_spacing)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module FontDescriptor
|
35
|
+
def perform_validation
|
36
|
+
descent = self[:Descent]
|
37
|
+
if descent && descent > 0
|
38
|
+
self[:Descent] = - descent
|
39
|
+
end
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
HexaPDF::Font::TrueType::Font.include(PdfWatermark::Font)
|
46
|
+
HexaPDF::Content::Canvas.include(PdfWatermark::Canvas)
|
47
|
+
HexaPDF::Type::FontDescriptor.prepend(PdfWatermark::FontDescriptor)
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'hexapdf'
|
2
|
+
require 'hexapdf/utils/math_helpers'
|
3
|
+
require 'pdf_watermark/font'
|
4
|
+
module PdfWatermark
|
5
|
+
module WaterMark
|
6
|
+
class Base
|
7
|
+
include HexaPDF::Utils::MathHelpers
|
8
|
+
|
9
|
+
def initialize(mark_string, source_path, options)
|
10
|
+
@source_path = source_path
|
11
|
+
@options = options
|
12
|
+
source_size = page_size
|
13
|
+
@content_width = source_size[0] - (options[:margin][1] + options[:margin][3])
|
14
|
+
@content_height = source_size[1] - (options[:margin][0] + options[:margin][2])
|
15
|
+
@angle = options[:angle] == :diagonal ? rad_to_deg(Math.atan(@content_height.to_f/@content_width.to_f)) : options[:angle]
|
16
|
+
@mark_string = mark_string
|
17
|
+
|
18
|
+
@font_size = @options[:font_size]
|
19
|
+
if @font_size.is_a?(String)
|
20
|
+
if @font_size =~ /(\d+[.]?\d*)%/
|
21
|
+
@font_size = ($1.to_f / 100) * @content_width
|
22
|
+
@font_size = [@font_size, @options[:max_font_size]].min
|
23
|
+
@font_size = [@font_size, @options[:min_font_size]].max
|
24
|
+
else
|
25
|
+
@font_size = @font_size.to_i
|
26
|
+
end
|
27
|
+
end
|
28
|
+
@options[:font]
|
29
|
+
@x = @options[:x] || 0
|
30
|
+
@y = @options[:y] || @content_height
|
31
|
+
|
32
|
+
@font = load_font(@options[:font], :watermark_font)
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
protected
|
37
|
+
|
38
|
+
def load_font(font_path, name = nil)
|
39
|
+
font_name = name.nil? ? File.basename(font_path, '.ttf') : name
|
40
|
+
map = {}
|
41
|
+
map[font_name] = { none: font_path }
|
42
|
+
document.config['font.map'].merge!(map)
|
43
|
+
|
44
|
+
document.fonts.load(font_name).wrapped_font
|
45
|
+
end
|
46
|
+
|
47
|
+
def page_size
|
48
|
+
box = document.pages[0].box.value
|
49
|
+
[box[2] - box[0], box[3] - box[1]]
|
50
|
+
end
|
51
|
+
|
52
|
+
def document
|
53
|
+
@document ||= HexaPDF::Document.open(@source_path)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'pdf_watermark/water_mark/base'
|
2
|
+
module PdfWatermark
|
3
|
+
module WaterMark
|
4
|
+
class Repeated < PdfWatermark::WaterMark::Base
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
super(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def render
|
11
|
+
document.pages.each do |page|
|
12
|
+
canvas = page.canvas(type: :overlay)
|
13
|
+
canvas.font(:watermark_font, size: @font_size)
|
14
|
+
canvas.fill_color(@options[:font_color])
|
15
|
+
box_height = @font_size
|
16
|
+
box_width = canvas.width_of(@mark_string)
|
17
|
+
temp_y = @y
|
18
|
+
indent = false
|
19
|
+
offset_x = box_width + @options[:repeat_offset] * @font_size
|
20
|
+
offset_y = box_height + @options[:repeat_offset] * @font_size
|
21
|
+
|
22
|
+
|
23
|
+
canvas.opacity(fill_alpha: @options[:transparent]) do
|
24
|
+
canvas.rotate(@angle, origin: [@content_width/2, @content_height/2]) do
|
25
|
+
while temp_y > 0 do
|
26
|
+
temp_x = indent ? (offset_x / 2.0) : 0
|
27
|
+
while temp_x <= @content_width
|
28
|
+
canvas.text(@mark_string, at: [temp_x, temp_y])
|
29
|
+
temp_x += offset_x
|
30
|
+
end
|
31
|
+
temp_y -= offset_y
|
32
|
+
indent = !indent
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
document
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'pdf_watermark/water_mark/base'
|
2
|
+
module PdfWatermark
|
3
|
+
module WaterMark
|
4
|
+
class Single < PdfWatermark::WaterMark::Base
|
5
|
+
|
6
|
+
def initialize(*args)
|
7
|
+
super(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def render
|
11
|
+
document.pages.each do |page|
|
12
|
+
canvas = page.canvas(type: :overlay)
|
13
|
+
canvas.fill_color(@options[:font_color])
|
14
|
+
canvas.font(:watermark_font, size: 18)
|
15
|
+
rad = deg_to_rad(@angle)
|
16
|
+
|
17
|
+
if Math.tan(rad) < @content_height.to_f/@content_width.to_f
|
18
|
+
max_text_width = (@content_width/Math.cos(rad)).abs
|
19
|
+
else
|
20
|
+
max_text_width = (@content_height/Math.sin(rad)).abs
|
21
|
+
end
|
22
|
+
# if user does not provide the font size, scale to fill the whole page
|
23
|
+
if @font_size
|
24
|
+
canvas.font_size(@font_size)
|
25
|
+
else
|
26
|
+
@font_size = calculated_font_size(canvas, @mark_string, @options[:max_font_size], max_text_width)
|
27
|
+
canvas.font_size(@font_size)
|
28
|
+
@x = (@content_width - canvas.width_of(@mark_string))/2 + @options[:margin][3]
|
29
|
+
@y = @content_height / 2 + @options[:margin][2]
|
30
|
+
end
|
31
|
+
canvas.opacity(fill_alpha: @options[:transparent]) do
|
32
|
+
canvas.rotate(@angle, origin: [@content_width/2, @content_height/2]) do
|
33
|
+
canvas.text(@mark_string, at: [@x, @y])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
document
|
38
|
+
end
|
39
|
+
|
40
|
+
def calculated_font_size(canvas, string, max_font, max_width)
|
41
|
+
text_width = canvas.width_of(string, max_font)
|
42
|
+
if text_width > max_width
|
43
|
+
(max_width - canvas.graphics_state.character_spacing * string.size) / string.size
|
44
|
+
else
|
45
|
+
max_font
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/pdf_watermark.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
require "pdf_watermark/version"
|
2
|
-
require 'pdf_watermark/water_mark'
|
3
|
-
require '
|
2
|
+
require 'pdf_watermark/water_mark/repeated'
|
3
|
+
require 'pdf_watermark/water_mark/single'
|
4
4
|
module PdfWatermark
|
5
5
|
|
6
|
+
include HexaPDF::Encryption::StandardSecurityHandler::Permissions
|
7
|
+
|
6
8
|
LIB_DIR = File.dirname(File.realpath(__FILE__))
|
7
|
-
BASEDIR = File.join(LIB_DIR, '..')
|
8
|
-
FONT_DIR = File.join(LIB_DIR, '..', 'fonts')
|
9
|
+
BASEDIR = File.realpath File.join(LIB_DIR, '..')
|
10
|
+
FONT_DIR = File.realpath File.join(LIB_DIR, '..', 'fonts')
|
9
11
|
REPEAT_X_OFFSET = 80
|
10
12
|
REPEAT_Y_OFFSET = 80
|
11
13
|
|
@@ -26,23 +28,25 @@ module PdfWatermark
|
|
26
28
|
}
|
27
29
|
options = default.merge(options)
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
+
if options[:mode].to_sym == :repeat
|
32
|
+
document = PdfWatermark::WaterMark::Repeated.new(mark_string, source, options).render
|
33
|
+
else
|
34
|
+
document = PdfWatermark::WaterMark::Single.new(mark_string, source, options).render
|
35
|
+
end
|
31
36
|
|
32
|
-
options[:
|
33
|
-
|
34
|
-
|
37
|
+
if options[:read_only]
|
38
|
+
permissions = 1
|
39
|
+
document.encrypt(name: :Standard, owner_password: options[:password], permissions: permissions)
|
40
|
+
end
|
35
41
|
|
36
|
-
wm = WaterMark.new(mark_string, options).render
|
37
|
-
water_mark_pdf = CombinePDF.parse(wm, allow_optional_content: true).pages[0]
|
38
42
|
|
39
|
-
|
40
|
-
|
41
|
-
end
|
42
|
-
if destination.nil?
|
43
|
-
source_pdf.to_pdf
|
43
|
+
if destination
|
44
|
+
document.write(destination)
|
44
45
|
else
|
45
|
-
|
46
|
+
StringIO.open('', 'wb') do |io|
|
47
|
+
document.write(io)
|
48
|
+
io.string
|
49
|
+
end
|
46
50
|
end
|
47
51
|
end
|
48
52
|
|
data/pdf_watermark.gemspec
CHANGED
@@ -4,27 +4,26 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'pdf_watermark/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name
|
8
|
-
spec.version
|
9
|
-
spec.authors
|
10
|
-
spec.email
|
7
|
+
spec.name = "pdf_watermark"
|
8
|
+
spec.version = PdfWatermark::VERSION
|
9
|
+
spec.authors = ["bruce"]
|
10
|
+
spec.email = ["shibocuhk@gmail.com"]
|
11
11
|
|
12
|
-
spec.summary
|
13
|
-
spec.description
|
14
|
-
spec.homepage
|
15
|
-
spec.license
|
12
|
+
spec.summary = %q{pdf watermark}
|
13
|
+
spec.description = %q{add watermark to pdf files}
|
14
|
+
spec.homepage = "http://bruceshi.me"
|
15
|
+
spec.license = "MIT"
|
16
16
|
|
17
17
|
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
18
18
|
# delete this section to allow pushing this gem to any host.
|
19
19
|
|
20
|
-
spec.files
|
21
|
-
spec.bindir
|
22
|
-
spec.executables
|
20
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
21
|
+
spec.bindir = "exe"
|
22
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
23
23
|
spec.require_paths = ['lib']
|
24
24
|
spec.test_files = Dir['spec/*_spec.rb']
|
25
25
|
|
26
|
-
spec.add_runtime_dependency('
|
27
|
-
spec.add_runtime_dependency('combine_pdf', '~> 0.2.34')
|
26
|
+
spec.add_runtime_dependency('hexapdf', '~> 0.3')
|
28
27
|
|
29
28
|
spec.add_development_dependency('bundler', '~> 1.10')
|
30
29
|
spec.add_development_dependency('rake', '~> 10.0')
|
metadata
CHANGED
@@ -1,49 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pdf_watermark
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- bruce
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: hexapdf
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
- - ">="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 2.1.0
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - "~>"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: '2.1'
|
30
|
-
- - ">="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 2.1.0
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: combine_pdf
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - "~>"
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: 0.2.34
|
19
|
+
version: '0.3'
|
40
20
|
type: :runtime
|
41
21
|
prerelease: false
|
42
22
|
version_requirements: !ruby/object:Gem::Requirement
|
43
23
|
requirements:
|
44
24
|
- - "~>"
|
45
25
|
- !ruby/object:Gem::Version
|
46
|
-
version: 0.
|
26
|
+
version: '0.3'
|
47
27
|
- !ruby/object:Gem::Dependency
|
48
28
|
name: bundler
|
49
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -147,8 +127,11 @@ files:
|
|
147
127
|
- bin/setup
|
148
128
|
- fonts/SourceHanSansSC-Regular.ttf
|
149
129
|
- lib/pdf_watermark.rb
|
130
|
+
- lib/pdf_watermark/font.rb
|
150
131
|
- lib/pdf_watermark/version.rb
|
151
|
-
- lib/pdf_watermark/water_mark.rb
|
132
|
+
- lib/pdf_watermark/water_mark/base.rb
|
133
|
+
- lib/pdf_watermark/water_mark/repeated.rb
|
134
|
+
- lib/pdf_watermark/water_mark/single.rb
|
152
135
|
- pdf_watermark.gemspec
|
153
136
|
homepage: http://bruceshi.me
|
154
137
|
licenses:
|
@@ -170,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
170
153
|
version: '0'
|
171
154
|
requirements: []
|
172
155
|
rubyforge_project:
|
173
|
-
rubygems_version: 2.
|
156
|
+
rubygems_version: 2.6.8
|
174
157
|
signing_key:
|
175
158
|
specification_version: 4
|
176
159
|
summary: pdf watermark
|
@@ -1,129 +0,0 @@
|
|
1
|
-
require 'prawn'
|
2
|
-
module PdfWatermark
|
3
|
-
class WaterMark
|
4
|
-
include Prawn::View
|
5
|
-
|
6
|
-
def initialize(mark_string, options)
|
7
|
-
@options = options
|
8
|
-
@content_width = options[:content_width]
|
9
|
-
@content_height = options[:content_height]
|
10
|
-
@angle = options[:angle] == :diagonal ? rad_to_degree(Math.atan(@content_height.to_f/@content_width.to_f)) : options[:angle]
|
11
|
-
@mark_string = mark_string
|
12
|
-
@font_size = @options[:font_size]
|
13
|
-
if @font_size.is_a?(String)
|
14
|
-
if @font_size =~ /(\d+[.]?\d*)%/
|
15
|
-
@font_size = ($1.to_f / 100) * @content_width
|
16
|
-
@font_size = [@font_size, @options[:max_font_size]].min
|
17
|
-
@font_size = [@font_size, @options[:min_font_size]].max
|
18
|
-
else
|
19
|
-
@font_size = @font_size.to_i
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
@font = @options[:font]
|
24
|
-
@x = @options[:x] || 0
|
25
|
-
@y = @options[:y] || @content_height
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
def render
|
30
|
-
case @options[:mode]
|
31
|
-
when :fill
|
32
|
-
fill_content
|
33
|
-
when :repeat
|
34
|
-
repeat_content
|
35
|
-
else
|
36
|
-
repeat_content
|
37
|
-
end
|
38
|
-
document.render
|
39
|
-
end
|
40
|
-
|
41
|
-
def fill_content
|
42
|
-
@max_text_width = @content_width
|
43
|
-
|
44
|
-
rad = degree_to_rad(@angle)
|
45
|
-
if Math.tan(rad) < @content_height.to_f/@content_width.to_f
|
46
|
-
@max_text_width = (@content_width/Math.cos(rad)).abs
|
47
|
-
else
|
48
|
-
@max_text_width = (@content_height/Math.sin(rad)).abs
|
49
|
-
end
|
50
|
-
@font_size ||= calculated_font_size(@mark_string, @options[:max_font_size], @max_text_width)
|
51
|
-
|
52
|
-
font(@options[:font]) do
|
53
|
-
bounding_box([@x, @y], width: @content_width, height: @content_height) do
|
54
|
-
rotate @angle, origin: [@content_width/2, @content_height/2] do
|
55
|
-
transparent(@options[:transparent]) do
|
56
|
-
formatted_text_box(
|
57
|
-
[{ text: @mark_string, color: @options[:font_color] }],
|
58
|
-
at: [@x - (@max_text_width - @content_width) / 2, @y],
|
59
|
-
width: @max_text_width, height: @content_height,
|
60
|
-
align: @options[:align], valign: @options[:valign],
|
61
|
-
size: @font_size,
|
62
|
-
)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def repeat_content
|
70
|
-
font(@font) do
|
71
|
-
transparent(@options[:transparent]) do
|
72
|
-
box_height = @font_size
|
73
|
-
box_width = text_width(@mark_string, @font_size)
|
74
|
-
temp_y = @y
|
75
|
-
indent = false
|
76
|
-
offset_x = box_width + @options[:repeat_offset] * @font_size
|
77
|
-
offset_y = box_height + @options[:repeat_offset] * @font_size
|
78
|
-
bounding_box([@x, @y], width: @content_width, height: @content_height) do
|
79
|
-
while temp_y > 0 do
|
80
|
-
rotate @angle, origin: [@content_width/2, @content_height/2] do
|
81
|
-
temp_x = indent ? (offset_x / 2.0) : 0
|
82
|
-
while temp_x <= @content_width
|
83
|
-
formatted_text_box(
|
84
|
-
[{ text: @mark_string, color: @options[:font_color] }],
|
85
|
-
at: [temp_x, temp_y],
|
86
|
-
width: box_width, height: box_height,
|
87
|
-
align: @options[:align], valign: @options[:valign],
|
88
|
-
size: @font_size,
|
89
|
-
)
|
90
|
-
temp_x += offset_x
|
91
|
-
end
|
92
|
-
end
|
93
|
-
temp_y -= offset_y
|
94
|
-
indent = !indent
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
|
102
|
-
protected
|
103
|
-
def text_width(text, size)
|
104
|
-
document.width_of(text, size: size, margin: 0, left_margin: 0, right_margin: 0).ceil
|
105
|
-
|
106
|
-
end
|
107
|
-
|
108
|
-
def calculated_font_size(text, size, max)
|
109
|
-
text_width = self.text_width(text, size)
|
110
|
-
if text_width > max
|
111
|
-
(max / text.size).floor
|
112
|
-
else
|
113
|
-
size
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def document
|
118
|
-
@document ||= Prawn::Document.new(page_size: @options[:source_size], margin: @options[:margin], font: @font)
|
119
|
-
end
|
120
|
-
|
121
|
-
def degree_to_rad(angle)
|
122
|
-
angle * Math::PI / 180
|
123
|
-
end
|
124
|
-
|
125
|
-
def rad_to_degree(rad)
|
126
|
-
rad * 180 / Math::PI
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|