pdf-writer 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|