pdf-writer 1.0.1 → 1.1.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.
- data/ChangeLog +34 -5
- data/LICENCE +17 -10
- data/demo/demo.rb +5 -5
- data/demo/gettysburg.rb +2 -2
- data/demo/qr-language.rb +3 -4
- data/demo/qr-library.rb +3 -2
- data/images/bluesmoke.jpg +0 -0
- data/lib/pdf/charts/stddev.rb +7 -7
- data/lib/pdf/quickref.rb +4 -4
- data/lib/pdf/simpletable.rb +8 -7
- data/lib/pdf/techbook.rb +14 -12
- data/lib/pdf/writer.rb +177 -53
- data/lib/pdf/writer/fontmetrics.rb +2 -1
- data/lib/pdf/writer/graphics.rb +97 -11
- data/lib/pdf/writer/lang/en.rb +23 -2
- data/lib/pdf/writer/object/font.rb +20 -28
- data/lib/pdf/writer/object/fontencoding.rb +11 -10
- data/manual.pwd +623 -176
- metadata +3 -6
- data/bin/techbook.bat +0 -2
- data/images/pdfwriter-icon.jpg +0 -0
- data/images/pdfwriter-small.jpg +0 -0
- data/images/pdfwriter-tiny.jpg +0 -0
data/lib/pdf/writer.rb
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
# Licensed under a MIT-style licence. See LICENCE in the main distribution
|
7
7
|
# for full licensing information.
|
8
8
|
#
|
9
|
-
# $Id: writer.rb,v 1.
|
9
|
+
# $Id: writer.rb,v 1.37 2005/06/28 21:32:17 austin Exp $
|
10
10
|
#++
|
11
11
|
require 'thread'
|
12
12
|
require 'open-uri'
|
@@ -19,7 +19,7 @@ require 'color'
|
|
19
19
|
module PDF
|
20
20
|
class Writer
|
21
21
|
# The version of PDF::Writer.
|
22
|
-
VERSION = '1.0
|
22
|
+
VERSION = '1.1.0'
|
23
23
|
|
24
24
|
# Escape the text so that it's safe for insertion into the PDF
|
25
25
|
# document.
|
@@ -433,8 +433,12 @@ class PDF::Writer
|
|
433
433
|
# external clients.
|
434
434
|
attr_accessor :procset #:nodoc:
|
435
435
|
# Sets the document to compressed (+true+) or uncompressed (+false+).
|
436
|
-
# Defaults to uncompressed.
|
436
|
+
# Defaults to uncompressed. This can ONLY be set once and should be set
|
437
|
+
# as early as possible in the document creation process.
|
437
438
|
attr_accessor :compressed
|
439
|
+
def compressed=(cc) #:nodoc:
|
440
|
+
@compressed = cc if @compressed.nil?
|
441
|
+
end
|
438
442
|
# Returns +true+ if the document is compressed.
|
439
443
|
def compressed?
|
440
444
|
@compressed == true
|
@@ -804,20 +808,21 @@ class PDF::Writer
|
|
804
808
|
def load_font(font, encoding = nil)
|
805
809
|
metrics = load_font_metrics(font)
|
806
810
|
|
807
|
-
name
|
811
|
+
name = File.basename(font).gsub(/\.afm$/o, "")
|
808
812
|
|
809
813
|
encoding_diff = nil
|
810
814
|
case encoding
|
811
815
|
when Hash
|
812
816
|
encoding_name = encoding[:encoding]
|
813
817
|
encoding_diff = encoding[:differences]
|
818
|
+
encoding = PDF::Writer::Object::FontEncoding.new(self, encoding_name, encoding_diff)
|
814
819
|
when NilClass
|
815
|
-
encoding_name = 'WinAnsiEncoding'
|
820
|
+
encoding_name = encoding = 'WinAnsiEncoding'
|
816
821
|
else
|
817
822
|
encoding_name = encoding
|
818
823
|
end
|
819
824
|
|
820
|
-
wfo = PDF::Writer::Object::Font.new(self, name,
|
825
|
+
wfo = PDF::Writer::Object::Font.new(self, name, encoding)
|
821
826
|
|
822
827
|
# We have an Adobe Font Metrics (.afm) file. We need to find the
|
823
828
|
# associated Type1 (.pfb) or TrueType (.ttf) files (we do not yet
|
@@ -853,7 +858,6 @@ class PDF::Writer
|
|
853
858
|
# Adjust the widths for the differences array.
|
854
859
|
if encoding_diff
|
855
860
|
encoding_diff.each do |cnum, cname|
|
856
|
-
# warn "Differences is ignored for now."
|
857
861
|
(cnum - last_char).times { widths << 0 } if cnum > last_char
|
858
862
|
last_char = cnum
|
859
863
|
widths[cnum - firstchar] = fonts.c[cname]['WX'] if metrics.c[cname]
|
@@ -872,10 +876,40 @@ class PDF::Writer
|
|
872
876
|
widthid << "]"
|
873
877
|
|
874
878
|
# Load the pfb file, and put that into an object too. Note that PDF
|
875
|
-
# supports only binary format
|
876
|
-
# simple utility to convert
|
877
|
-
data =
|
878
|
-
|
879
|
+
# supports only binary format Type1 font files and TrueType font
|
880
|
+
# files. There is a simple utility to convert Type1 from pfa to pfb.
|
881
|
+
data = File.open(fbfile, "rb") { |ff| ff.read }
|
882
|
+
|
883
|
+
# Check to see if the font licence allows embedding.
|
884
|
+
if fbtype =~ /\.ttf$/o
|
885
|
+
offset = 4
|
886
|
+
tables = data[offset, 2].unpack('n')[0]
|
887
|
+
offset += 8
|
888
|
+
|
889
|
+
found = false
|
890
|
+
tables.times do
|
891
|
+
if data[offset, 4] == 'OS/2'
|
892
|
+
found = true
|
893
|
+
break
|
894
|
+
end
|
895
|
+
offset += 4 + 12
|
896
|
+
end
|
897
|
+
|
898
|
+
if found
|
899
|
+
offset += 4
|
900
|
+
newoff = data[offset, 4].unpack('N')[0]
|
901
|
+
offset = newoff + 8
|
902
|
+
licence = data[offset, 2].unpack('n')[0]
|
903
|
+
|
904
|
+
rl = ((licence & 0x02) != 0)
|
905
|
+
pp = ((licence & 0x04) != 0)
|
906
|
+
ee = ((licence & 0x08) != 0)
|
907
|
+
|
908
|
+
if rl and pp and ee
|
909
|
+
warn PDF::Writer::Lang[:ttf_licence_no_embedding] % name
|
910
|
+
end
|
911
|
+
end
|
912
|
+
end
|
879
913
|
|
880
914
|
# Create the font descriptor.
|
881
915
|
fdsc = PDF::Writer::Object::FontDescriptor.new(self)
|
@@ -885,9 +919,42 @@ class PDF::Writer
|
|
885
919
|
# Determine flags (more than a little flakey, hopefully will not
|
886
920
|
# matter much).
|
887
921
|
flags = 0
|
888
|
-
|
889
|
-
|
890
|
-
|
922
|
+
if encoding == "none"
|
923
|
+
flags += 2 ** 2
|
924
|
+
else
|
925
|
+
flags += 2 ** 6 if metrics.italicangle.nonzero?
|
926
|
+
flags += 2 ** 0 if metrics.isfixedpitch == "true"
|
927
|
+
flags += 2 ** 5 # Assume a non-symbolic font
|
928
|
+
end
|
929
|
+
|
930
|
+
# 1: FixedPitch: All glyphs have the same width (as opposed to
|
931
|
+
# proportional or variable-pitch fonts, which have
|
932
|
+
# different widths).
|
933
|
+
# 2: Serif: Glyphs have serifs, which are short strokes drawn
|
934
|
+
# at an angle on the top and bottom of glyph stems.
|
935
|
+
# (Sans serif fonts do not have serifs.)
|
936
|
+
# 3: Symbolic Font contains glyphs outside the Adobe standard
|
937
|
+
# Latin character set. This flag and the Nonsymbolic
|
938
|
+
# flag cannot both be set or both be clear (see
|
939
|
+
# below).
|
940
|
+
# 4: Script: Glyphs resemble cursive handwriting.
|
941
|
+
# 6: Nonsymbolic: Font uses the Adobe standard Latin character set
|
942
|
+
# or a subset of it (see below).
|
943
|
+
# 7: Italic: Glyphs have dominant vertical strokes that are
|
944
|
+
# slanted.
|
945
|
+
# 17: AllCap: Font contains no lowercase letters; typically used
|
946
|
+
# for display purposes, such as for titles or
|
947
|
+
# headlines.
|
948
|
+
# 18: SmallCap: Font contains both uppercase and lowercase
|
949
|
+
# letters. The uppercase letters are similar to
|
950
|
+
# those in the regular version of the same typeface
|
951
|
+
# family. The glyphs for the lowercase letters have
|
952
|
+
# the same shapes as the corresponding uppercase
|
953
|
+
# letters, but they are sized and their proportions
|
954
|
+
# adjusted so that they have the same size and
|
955
|
+
# stroke weight as lowercase glyphs in the same
|
956
|
+
# typeface family.
|
957
|
+
# 19: ForceBold: See below.
|
891
958
|
|
892
959
|
list = {
|
893
960
|
'Ascent' => 'Ascender',
|
@@ -1029,8 +1096,11 @@ class PDF::Writer
|
|
1029
1096
|
@current_contents << cc
|
1030
1097
|
end
|
1031
1098
|
|
1032
|
-
# Return the height in units of the current font in the given size.
|
1033
|
-
|
1099
|
+
# Return the height in units of the current font in the given size. Uses
|
1100
|
+
# the current #font_size if size is not provided.
|
1101
|
+
def font_height(size = nil)
|
1102
|
+
size = @font_size if size.nil? or size <= 0
|
1103
|
+
|
1034
1104
|
select_font("Helvetica") if @fonts.empty?
|
1035
1105
|
hh = @fonts[@current_font].fontbbox[3].to_f - @fonts[@current_font].fontbbox[1].to_f
|
1036
1106
|
(size * hh / 1000.0)
|
@@ -1038,8 +1108,11 @@ class PDF::Writer
|
|
1038
1108
|
|
1039
1109
|
# Return the font descender, this will normally return a negative
|
1040
1110
|
# number. If you add this number to the baseline, you get the level of
|
1041
|
-
# the bottom of the font it is in the PDF user units.
|
1042
|
-
|
1111
|
+
# the bottom of the font it is in the PDF user units. Uses the current
|
1112
|
+
# #font_size if size is not provided.
|
1113
|
+
def font_descender(size = nil)
|
1114
|
+
size = @font_size if size.nil? or size <= 0
|
1115
|
+
|
1043
1116
|
select_font("Helvetica") if @fonts.empty?
|
1044
1117
|
hi = @fonts[@current_font].fontbbox[1].to_f
|
1045
1118
|
(size * hi / 1000.0)
|
@@ -1047,13 +1120,13 @@ class PDF::Writer
|
|
1047
1120
|
|
1048
1121
|
# Given a start position and information about how text is to be laid
|
1049
1122
|
# out, calculate where on the page the text will end.
|
1050
|
-
def
|
1051
|
-
width = text_width(
|
1123
|
+
def text_end_position(x, y, angle, size, wa, text)
|
1124
|
+
width = text_width(text, size)
|
1052
1125
|
width += wa * (text.count(" "))
|
1053
1126
|
rad = PDF::Math.deg2rad(angle)
|
1054
1127
|
[Math.cos(rad) * width + x, ((-Math.sin(rad)) * width + y)]
|
1055
1128
|
end
|
1056
|
-
private :
|
1129
|
+
private :text_end_position
|
1057
1130
|
|
1058
1131
|
# Wrapper function for #text_tags
|
1059
1132
|
def quick_text_tags(text, ii, font_change)
|
@@ -1205,7 +1278,8 @@ class PDF::Writer
|
|
1205
1278
|
|
1206
1279
|
if tag
|
1207
1280
|
text[pos, tag_size] = tag[self, params]
|
1208
|
-
tag_size, text, font_change, x, y = text_tags(text, pos,
|
1281
|
+
tag_size, text, font_change, x, y = text_tags(text, pos,
|
1282
|
+
font_change,
|
1209
1283
|
final, x, y, size,
|
1210
1284
|
angle,
|
1211
1285
|
word_space_adjust)
|
@@ -1230,8 +1304,8 @@ class PDF::Writer
|
|
1230
1304
|
if final
|
1231
1305
|
# Only call the function if this is the "final" call. Assess
|
1232
1306
|
# the text position. Calculate the text width to this point.
|
1233
|
-
x, y =
|
1234
|
-
|
1307
|
+
x, y = text_end_position(x, y, angle, size, word_space_adjust,
|
1308
|
+
text[0, pos])
|
1235
1309
|
info = {
|
1236
1310
|
:x => x,
|
1237
1311
|
:y => y,
|
@@ -1275,8 +1349,8 @@ class PDF::Writer
|
|
1275
1349
|
if final
|
1276
1350
|
# Only call the function if this is the "final" call. Assess
|
1277
1351
|
# the text position. Calculate the text width to this point.
|
1278
|
-
x, y =
|
1279
|
-
|
1352
|
+
x, y = text_end_position(x, y, angle, size, word_space_adjust,
|
1353
|
+
text[0, pos])
|
1280
1354
|
info = {
|
1281
1355
|
:x => x,
|
1282
1356
|
:y => y,
|
@@ -1345,9 +1419,22 @@ class PDF::Writer
|
|
1345
1419
|
end
|
1346
1420
|
private :parse_tag_params
|
1347
1421
|
|
1348
|
-
# Add text to the document at
|
1349
|
-
#
|
1350
|
-
|
1422
|
+
# Add +text+ to the document at <tt>(x, y)</tt> location at +size+ and
|
1423
|
+
# +angle+. The +word_space_adjust+ parameter is an internal parameter
|
1424
|
+
# that should not be used.
|
1425
|
+
#
|
1426
|
+
# As of PDF::Writer 1.1, +size+ and +text+ have been reversed and +size+
|
1427
|
+
# is now optional, defaulting to the current #font_size if unset.
|
1428
|
+
def add_text(x, y, text, size = nil, angle = 0, word_space_adjust = 0)
|
1429
|
+
if text.kind_of?(Numeric) and size.kind_of?(String)
|
1430
|
+
text, size = size, text
|
1431
|
+
warn PDF::Writer::Lang[:add_text_parameters_reversed] % caller[0]
|
1432
|
+
end
|
1433
|
+
|
1434
|
+
if size.nil? or size <= 0
|
1435
|
+
size = @font_size
|
1436
|
+
end
|
1437
|
+
|
1351
1438
|
select_font("Helvetica") if @fonts.empty?
|
1352
1439
|
|
1353
1440
|
text = text.to_s
|
@@ -1368,7 +1455,7 @@ class PDF::Writer
|
|
1368
1455
|
else
|
1369
1456
|
rad = PDF::Math.deg2rad(angle)
|
1370
1457
|
tt = "\nBT %.3f %.3f %.3f %.3f %.3f %.3f Tm"
|
1371
|
-
tt = tt % [Math.cos(rad),
|
1458
|
+
tt = tt % [ Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), x, y ]
|
1372
1459
|
add_content(tt)
|
1373
1460
|
end
|
1374
1461
|
|
@@ -1408,7 +1495,7 @@ class PDF::Writer
|
|
1408
1495
|
else
|
1409
1496
|
rad = PDF::Math.deg2rad(angle)
|
1410
1497
|
tt = "\nBT %.3f %.3f %.3f %.3f %.3f %.3f Tm"
|
1411
|
-
tt = tt % [Math.cos(rad),
|
1498
|
+
tt = tt % [ Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), xp, yp ]
|
1412
1499
|
add_content(tt)
|
1413
1500
|
end
|
1414
1501
|
|
@@ -1460,9 +1547,21 @@ class PDF::Writer
|
|
1460
1547
|
private :char_width
|
1461
1548
|
|
1462
1549
|
# Calculate how wide a given text string will be on a page, at a given
|
1463
|
-
# size. This
|
1464
|
-
#
|
1465
|
-
|
1550
|
+
# size. This may be called externally, but is alse used by #text_width.
|
1551
|
+
# If +size+ is not specified, PDF::Writer will use the current
|
1552
|
+
# #font_size.
|
1553
|
+
#
|
1554
|
+
# The argument list is reversed from earlier versions.
|
1555
|
+
def text_line_width(text, size = nil)
|
1556
|
+
if text.kind_of?(Numeric) and size.kind_of?(String)
|
1557
|
+
text, size = size, text
|
1558
|
+
warn PDF::Writer::Lang[:text_width_parameters_reversed] % caller[0]
|
1559
|
+
end
|
1560
|
+
|
1561
|
+
if size.nil? or size <= 0
|
1562
|
+
size = @font_size
|
1563
|
+
end
|
1564
|
+
|
1466
1565
|
# This function should not change any of the settings, though it will
|
1467
1566
|
# need to track any tag which change during calculation, so copy them
|
1468
1567
|
# at the start and put them back at the end.
|
@@ -1511,13 +1610,27 @@ class PDF::Writer
|
|
1511
1610
|
(width * size / 1000.0)
|
1512
1611
|
end
|
1513
1612
|
|
1514
|
-
#
|
1515
|
-
#
|
1516
|
-
|
1613
|
+
# Calculate how wide a given text string will be on a page, at a given
|
1614
|
+
# size. If +size+ is not specified, PDF::Writer will use the current
|
1615
|
+
# #font_size. The difference between this method and #text_line_width is
|
1616
|
+
# that this method will iterate over lines separated with newline
|
1617
|
+
# characters.
|
1618
|
+
#
|
1619
|
+
# The argument list is reversed from earlier versions.
|
1620
|
+
def text_width(text, size = nil)
|
1621
|
+
if text.kind_of?(Numeric) and size.kind_of?(String)
|
1622
|
+
text, size = size, text
|
1623
|
+
warn PDF::Writer::Lang[:text_width_parameters_reversed] % caller[0]
|
1624
|
+
end
|
1625
|
+
|
1626
|
+
if size.nil? or size <= 0
|
1627
|
+
size = @font_size
|
1628
|
+
end
|
1629
|
+
|
1517
1630
|
max = 0
|
1518
1631
|
|
1519
1632
|
text.to_s.each do |line|
|
1520
|
-
width = text_line_width(
|
1633
|
+
width = text_line_width(line, size)
|
1521
1634
|
max = width if width > max
|
1522
1635
|
end
|
1523
1636
|
max
|
@@ -1554,7 +1667,16 @@ class PDF::Writer
|
|
1554
1667
|
# remainder of the text.
|
1555
1668
|
#
|
1556
1669
|
# +justification+:: :left, :right, :center, or :full
|
1557
|
-
def add_text_wrap(x, y, width,
|
1670
|
+
def add_text_wrap(x, y, width, text, size = nil, justification = :left, angle = 0, test = false)
|
1671
|
+
if text.kind_of?(Numeric) and size.kind_of?(String)
|
1672
|
+
text, size = size, text
|
1673
|
+
warn PDF::Writer::Lang[:add_textw_parameters_reversed] % caller[0]
|
1674
|
+
end
|
1675
|
+
|
1676
|
+
if size.nil? or size <= 0
|
1677
|
+
size = @font_size
|
1678
|
+
end
|
1679
|
+
|
1558
1680
|
# Need to store the initial text state, as this will change during the
|
1559
1681
|
# width calculation, but will need to be re-set before printing, so
|
1560
1682
|
# that the chars work out right
|
@@ -1594,7 +1716,7 @@ class PDF::Writer
|
|
1594
1716
|
# Reset the text state
|
1595
1717
|
@current_text_state = t_CTS.dup
|
1596
1718
|
current_font!
|
1597
|
-
add_text(x, y,
|
1719
|
+
add_text(x, y, tmp, size, angle, adjust) unless test
|
1598
1720
|
return text[brk + 1..-1]
|
1599
1721
|
else # just break before the current character
|
1600
1722
|
tmp = text[0, pos]
|
@@ -1604,7 +1726,7 @@ class PDF::Writer
|
|
1604
1726
|
# Reset the text state
|
1605
1727
|
@current_text_state = t_CTS.dup
|
1606
1728
|
current_font!
|
1607
|
-
add_text(x, y,
|
1729
|
+
add_text(x, y, tmp, size, angle, adjust) unless test
|
1608
1730
|
return text[pos..-1]
|
1609
1731
|
end
|
1610
1732
|
end
|
@@ -1631,7 +1753,7 @@ class PDF::Writer
|
|
1631
1753
|
# reset the text state
|
1632
1754
|
@current_text_state = t_CTS.dup
|
1633
1755
|
current_font!
|
1634
|
-
add_text(x, y,
|
1756
|
+
add_text(x, y, text, size, angle, adjust) unless test
|
1635
1757
|
return ""
|
1636
1758
|
end
|
1637
1759
|
|
@@ -2184,7 +2306,11 @@ class PDF::Writer
|
|
2184
2306
|
if tmp[page_num].kind_of?(Hash) # This must be the starting page #s
|
2185
2307
|
status = 1
|
2186
2308
|
info = tmp[page_num]
|
2187
|
-
|
2309
|
+
if info[:starting]
|
2310
|
+
info[:delta] = info[:starting] - page_num
|
2311
|
+
else
|
2312
|
+
info[:delta] = page_num
|
2313
|
+
end
|
2188
2314
|
# Also check for the special case of the numbering stopping
|
2189
2315
|
# and starting on the same page.
|
2190
2316
|
status = 2 if info["stopn"] or info["stoptn"]
|
@@ -2209,11 +2335,11 @@ class PDF::Writer
|
|
2209
2335
|
when :right
|
2210
2336
|
w = 0
|
2211
2337
|
when :left
|
2212
|
-
w = text_width(info[:size]
|
2338
|
+
w = text_width(pat, info[:size])
|
2213
2339
|
when :center
|
2214
|
-
w = text_width(info[:size]
|
2340
|
+
w = text_width(pat, info[:size]) / 2.0
|
2215
2341
|
end
|
2216
|
-
add_text(info[:x] + w, info[:y], info[:size]
|
2342
|
+
add_text(info[:x] + w, info[:y], pat, info[:size])
|
2217
2343
|
close_object
|
2218
2344
|
status = 0 if status == 2
|
2219
2345
|
end
|
@@ -2242,6 +2368,8 @@ class PDF::Writer
|
|
2242
2368
|
# <tt>:font_size</tt>:: The font size to be used. If not
|
2243
2369
|
# specified, is either the last font size or
|
2244
2370
|
# the default font size of 12 points.
|
2371
|
+
# Setting this value *changes* the current
|
2372
|
+
# #font_size.
|
2245
2373
|
# <tt>:left</tt>:: number, gap to leave from the left margin
|
2246
2374
|
# <tt>:right</tt>:: number, gap to leave from the right margin
|
2247
2375
|
# <tt>:absolute_left</tt>:: number, absolute left position (overrides
|
@@ -2340,7 +2468,7 @@ class PDF::Writer
|
|
2340
2468
|
end
|
2341
2469
|
end
|
2342
2470
|
|
2343
|
-
line = add_text_wrap(left, @y, right - left,
|
2471
|
+
line = add_text_wrap(left, @y, right - left, line, size, just, 0, options[:test])
|
2344
2472
|
end
|
2345
2473
|
end
|
2346
2474
|
|
@@ -2583,7 +2711,7 @@ class PDF::Writer
|
|
2583
2711
|
ss.cap = :butt
|
2584
2712
|
ss.join = :miter
|
2585
2713
|
pdf.stroke_style! ss
|
2586
|
-
pdf.stroke_color @
|
2714
|
+
pdf.stroke_color @color
|
2587
2715
|
pdf.circle_at(xpos, ypos, 1).stroke
|
2588
2716
|
pdf.restore_state
|
2589
2717
|
end
|
@@ -2651,11 +2779,7 @@ class PDF::Writer
|
|
2651
2779
|
end
|
2652
2780
|
|
2653
2781
|
# Save the PDF as a file to disk.
|
2654
|
-
def save_as(name
|
2655
|
-
old_compressed = self.compressed
|
2656
|
-
self.compressed = compressed
|
2782
|
+
def save_as(name)
|
2657
2783
|
File.open(name, "wb") { |f| f.write self.render }
|
2658
|
-
ensure
|
2659
|
-
self.compressed = old_compressed
|
2660
2784
|
end
|
2661
2785
|
end
|
@@ -6,8 +6,9 @@
|
|
6
6
|
# Licensed under a MIT-style licence. See LICENCE in the main distribution
|
7
7
|
# for full licensing information.
|
8
8
|
#
|
9
|
-
# $Id: fontmetrics.rb,v 1.
|
9
|
+
# $Id: fontmetrics.rb,v 1.4 2005/06/16 04:28:25 austin Exp $
|
10
10
|
#++
|
11
|
+
|
11
12
|
class PDF::Writer::FontMetrics
|
12
13
|
METRICS_PATH = [ File.join(File.dirname(File.expand_path(__FILE__)), 'fonts') ]
|
13
14
|
|
data/lib/pdf/writer/graphics.rb
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
# Licensed under a MIT-style licence. See LICENCE in the main distribution
|
7
7
|
# for full licensing information.
|
8
8
|
#
|
9
|
-
# $Id: graphics.rb,v 1.
|
9
|
+
# $Id: graphics.rb,v 1.12 2005/06/28 21:32:17 austin Exp $
|
10
10
|
#++
|
11
11
|
# Points for use in the drawing of polygons.
|
12
12
|
class PDF::Writer::PolygonPoint
|
@@ -525,7 +525,19 @@ module PDF::Writer::Graphics
|
|
525
525
|
# The +image+ parameter may be a filename or an object that returns the
|
526
526
|
# full image data when #read is called with no parameters (such as an IO
|
527
527
|
# object). If 'open-uri' is loaded, then the image name may be an URI.
|
528
|
-
|
528
|
+
#
|
529
|
+
# In PDF::Writer 1.1 or later, the new +link+ parameter is a hash with
|
530
|
+
# two keys:
|
531
|
+
#
|
532
|
+
# <tt>:type</tt>:: The type of link, either <tt>:internal</tt> or
|
533
|
+
# <tt>:external</tt>.
|
534
|
+
# <tt>:target</tt>:: The destination of the link. For an
|
535
|
+
# <tt>:internal</tt> link, this is an internal
|
536
|
+
# cross-reference destination. For an
|
537
|
+
# <tt>:external</tt> link, this is an URI.
|
538
|
+
#
|
539
|
+
# This will automatically make the image a clickable link if set.
|
540
|
+
def add_image_from_file(image, x, y, width = nil, height = nil, link = nil)
|
529
541
|
data = nil
|
530
542
|
|
531
543
|
if image.respond_to?(:read)
|
@@ -534,15 +546,31 @@ module PDF::Writer::Graphics
|
|
534
546
|
open(image, 'rb') { |ff| data = ff.read }
|
535
547
|
end
|
536
548
|
|
537
|
-
add_image(data, x, y, width, height)
|
549
|
+
add_image(data, x, y, width, height, nil, link)
|
538
550
|
end
|
539
551
|
|
540
552
|
# Add an image from a loaded image (JPEG or PNG) resource at position
|
541
553
|
# <tt>(x, y)</tt> (the upper left-hand corner of the image) and scaled
|
542
554
|
# to +width+ by +height+ units. If provided, +image_info+ is a
|
543
555
|
# PDF::Writer::Graphics::ImageInfo object.
|
544
|
-
|
545
|
-
|
556
|
+
#
|
557
|
+
# In PDF::Writer 1.1 or later, the new +link+ parameter is a hash with
|
558
|
+
# two keys:
|
559
|
+
#
|
560
|
+
# <tt>:type</tt>:: The type of link, either <tt>:internal</tt> or
|
561
|
+
# <tt>:external</tt>.
|
562
|
+
# <tt>:target</tt>:: The destination of the link. For an
|
563
|
+
# <tt>:internal</tt> link, this is an internal
|
564
|
+
# cross-reference destination. For an
|
565
|
+
# <tt>:external</tt> link, this is an URI.
|
566
|
+
#
|
567
|
+
# This will automatically make the image a clickable link if set.
|
568
|
+
def add_image(image, x, y, width = nil, height = nil, image_info = nil, link = nil)
|
569
|
+
if image.kind_of?(PDF::Writer::External::Image)
|
570
|
+
label = image.label
|
571
|
+
image_obj = image
|
572
|
+
image_info ||= image.image_info
|
573
|
+
else
|
546
574
|
image_info ||= PDF::Writer::Graphics::ImageInfo.new(image)
|
547
575
|
|
548
576
|
tt = Time.now
|
@@ -551,10 +579,6 @@ module PDF::Writer::Graphics
|
|
551
579
|
label = "I#{id}"
|
552
580
|
image_obj = PDF::Writer::External::Image.new(self, image, image_info, label)
|
553
581
|
@images[id] = image_obj
|
554
|
-
else
|
555
|
-
label = image.label
|
556
|
-
image_obj = image
|
557
|
-
image_info ||= image.image_info
|
558
582
|
end
|
559
583
|
|
560
584
|
if width.nil? and height.nil?
|
@@ -567,6 +591,16 @@ module PDF::Writer::Graphics
|
|
567
591
|
|
568
592
|
tt = "\nq\n%.3f 0 0 %.3f %.3f %.3f cm\n/%s Do\nQ"
|
569
593
|
add_content(tt % [ width, height, x, y, label ])
|
594
|
+
|
595
|
+
if link
|
596
|
+
case link[:type]
|
597
|
+
when :internal
|
598
|
+
add_internal_link(link[:target], x, y, x + width, y + height)
|
599
|
+
when :external
|
600
|
+
add_link(link[:target], x, y, x + width, y + height)
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
570
604
|
image_obj
|
571
605
|
end
|
572
606
|
|
@@ -595,18 +629,29 @@ module PDF::Writer::Graphics
|
|
595
629
|
# <tt>:border</tt>:: The border options. No default border. If
|
596
630
|
# specified, must be either +true+, which uses
|
597
631
|
# the default border, or a Hash.
|
632
|
+
# <tt>:link</tt>:: Makes the image a clickable link.
|
598
633
|
#
|
599
634
|
# Image borders are specified as a hash with two options:
|
600
635
|
#
|
601
636
|
# <tt>:color</tt>:: The colour of the border. Defaults to 50% grey.
|
602
637
|
# <tt>:style</tt>:: The stroke style of the border. This must be a
|
603
638
|
# StrokeStyle object and defaults to the default line.
|
639
|
+
#
|
640
|
+
# Image links are defined as a hash with two options:
|
641
|
+
#
|
642
|
+
# <tt>:type</tt>:: The type of link, either <tt>:internal</tt> or
|
643
|
+
# <tt>:external</tt>.
|
644
|
+
# <tt>:target</tt>:: The destination of the link. For an
|
645
|
+
# <tt>:internal</tt> link, this is an internal
|
646
|
+
# cross-reference destination. For an
|
647
|
+
# <tt>:external</tt> link, this is an URI.
|
604
648
|
def image(image, options = {})
|
605
649
|
width = options[:width]
|
606
650
|
pad = options[:pad] || 5
|
607
651
|
resize = options[:resize]
|
608
652
|
just = options[:justification] || :left
|
609
653
|
border = options[:border]
|
654
|
+
link = options[:link]
|
610
655
|
|
611
656
|
if image.kind_of?(PDF::Writer::External::Image)
|
612
657
|
info = image.image_info
|
@@ -691,6 +736,15 @@ module PDF::Writer::Graphics
|
|
691
736
|
restore_state
|
692
737
|
end
|
693
738
|
|
739
|
+
if link
|
740
|
+
case link[:type]
|
741
|
+
when :internal
|
742
|
+
add_internal_link(link[:target], x, y - pad, x + width, y + height - pad)
|
743
|
+
when :external
|
744
|
+
add_link(link[:target], x, y - pad, x + width, y + height - pad)
|
745
|
+
end
|
746
|
+
end
|
747
|
+
|
694
748
|
@y = @y - pad - height
|
695
749
|
|
696
750
|
image_obj
|
@@ -707,7 +761,9 @@ module PDF::Writer::Graphics
|
|
707
761
|
# angle.
|
708
762
|
def rotate_axis(angle)
|
709
763
|
rad = PDF::Math.deg2rad(angle)
|
710
|
-
|
764
|
+
tt = "\n%.3f %.3f %.3f %.3f 0 0 cm"
|
765
|
+
tx = [ Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad) ]
|
766
|
+
add_content(tt % tx)
|
711
767
|
self
|
712
768
|
end
|
713
769
|
|
@@ -721,7 +777,37 @@ module PDF::Writer::Graphics
|
|
721
777
|
def skew_axis(xangle = 0, yangle = 0)
|
722
778
|
xr = PDF::Math.deg2rad(xangle)
|
723
779
|
yr = PDF::Math.deg2rad(yangle)
|
724
|
-
|
780
|
+
|
781
|
+
xr = Math.tan(xr) if xangle != 0
|
782
|
+
yr = Math.tan(yr) if yangle != 0
|
783
|
+
|
784
|
+
add_content("\n1 %.3f %.3f 1 0 0 cm" % [ xr, yr ])
|
725
785
|
self
|
726
786
|
end
|
787
|
+
|
788
|
+
# Transforms the coordinate axis with the appended matrix. All
|
789
|
+
# transformations (including those above) are performed with this
|
790
|
+
# matrix. The transformation matrix is:
|
791
|
+
#
|
792
|
+
# +- -+
|
793
|
+
# | a c e |
|
794
|
+
# | b d f |
|
795
|
+
# | 0 0 1 |
|
796
|
+
# +- -+
|
797
|
+
#
|
798
|
+
# The six values are represented as a six-digit vector: [ a b c d e f ]
|
799
|
+
#
|
800
|
+
# * Axis translation uses [ 1 0 0 1 x y ] where x and y are the new
|
801
|
+
# (0,0) coordinates in the old axis system.
|
802
|
+
# * Scaling uses [ sx 0 0 sy 0 0 ] where sx and sy are the scaling
|
803
|
+
# factors.
|
804
|
+
# * Rotation uses [ cos(a) sin(a) -sin(a) cos(a) 0 0 ] where a is the
|
805
|
+
# angle, measured in radians.
|
806
|
+
# * X axis skewing uses [ 1 0 tan(a) 1 0 0 ] where a is the angle,
|
807
|
+
# measured in radians.
|
808
|
+
# * Y axis skewing uses [ 1 tan(a) 0 1 0 0 ] where a is the angle,
|
809
|
+
# measured in radians.
|
810
|
+
def transform_matrix(a, b, c, d, e, f)
|
811
|
+
add_content("\n%.3f %.3f %.3f %.3f %3.f %.3f cm" % [ a, b, c, d, e, f ])
|
812
|
+
end
|
727
813
|
end
|