jpeg2pdf 0.12
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/LICENSE +37 -0
- data/README +162 -0
- data/bin/jpeg2pdf +102 -0
- data/bin/test.rb +111 -0
- data/install.rb +1360 -0
- data/jpeg2pdf.gemspec +18 -0
- data/lib/image_size.rb +291 -0
- data/lib/jpeg2pdf.rb +84 -0
- data/lib/rpdf.rb +48 -0
- data/lib/rpdf/crossreftable.rb +33 -0
- data/lib/rpdf/document.rb +61 -0
- data/lib/rpdf/documentcatalog.rb +18 -0
- data/lib/rpdf/imagedictionary.rb +23 -0
- data/lib/rpdf/page.rb +21 -0
- data/lib/rpdf/pagetree.rb +24 -0
- data/lib/rpdf/pdfarray.rb +35 -0
- data/lib/rpdf/pdfboolean.rb +28 -0
- data/lib/rpdf/pdfdictionary.rb +51 -0
- data/lib/rpdf/pdfinteger.rb +17 -0
- data/lib/rpdf/pdfname.rb +35 -0
- data/lib/rpdf/pdfnull.rb +19 -0
- data/lib/rpdf/pdfnumeric.rb +28 -0
- data/lib/rpdf/pdfobject.rb +60 -0
- data/lib/rpdf/pdfstream.rb +32 -0
- data/lib/rpdf/pdfstring.rb +38 -0
- data/lib/rpdf/rectangle.rb +15 -0
- data/lib/rpdf/trailer.rb +30 -0
- data/lib/rpdf/util.rb +41 -0
- data/lib/rpdf/version.rb +31 -0
- metadata +71 -0
data/jpeg2pdf.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{jpeg2pdf}
|
3
|
+
s.version = "0.12"
|
4
|
+
s.date = Time.now
|
5
|
+
s.summary = %q{jpeg2pdf is a free program that converts a directory of JPEG files to a PDF file.}
|
6
|
+
s.author = %q{Koen Vervloesem}
|
7
|
+
s.email = %q{koen.vervloesem@myrealbox.com}
|
8
|
+
s.homepage = %q{http://koan.studentenweb.org/software/jpeg2pdf.html}
|
9
|
+
s.autorequire = %q{jpeg2pdf}
|
10
|
+
s.require_path = %q{lib}
|
11
|
+
s.default_executable = %q{jpeg2pdf}
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.files = Dir.glob('**/*')
|
14
|
+
s.rdoc_options = ["--main", "README"]
|
15
|
+
s.extra_rdoc_files = ["README"]
|
16
|
+
s.executables = ["jpeg2pdf"]
|
17
|
+
s.bindir = %q{bin}
|
18
|
+
end
|
data/lib/image_size.rb
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
#!ruby
|
2
|
+
|
3
|
+
# This is an adapted version of the image_size library to support
|
4
|
+
# some extra information from the JPEG file format.
|
5
|
+
# Additions have a comment with the word 'koan'.
|
6
|
+
|
7
|
+
class ImageSize
|
8
|
+
|
9
|
+
# Image Type Constants
|
10
|
+
module Type
|
11
|
+
OTHER = "OTHER"
|
12
|
+
GIF = "GIF"
|
13
|
+
PNG = "PNG"
|
14
|
+
JPEG = "JPEG"
|
15
|
+
BMP = "BMP"
|
16
|
+
PPM = "PPM" # PPM is like PBM, PGM, & XV
|
17
|
+
PBM = "PBM"
|
18
|
+
PGM = "PGM"
|
19
|
+
# XV = "XV"
|
20
|
+
XBM = "XBM"
|
21
|
+
TIFF = "TIFF"
|
22
|
+
XPM = "XPM"
|
23
|
+
PSD = "PSD"
|
24
|
+
PCX = "PCX"
|
25
|
+
SWF = "SWF"
|
26
|
+
end
|
27
|
+
|
28
|
+
JpegCodeCheck = [
|
29
|
+
"\xc0", "\xc1", "\xc2", "\xc3",
|
30
|
+
"\xc5", "\xc6", "\xc7",
|
31
|
+
"\xc9", "\xca", "\xcb",
|
32
|
+
"\xcd", "\xce", "\xcf",
|
33
|
+
]
|
34
|
+
|
35
|
+
# image type list
|
36
|
+
def ImageSize.type_list
|
37
|
+
Type.constants
|
38
|
+
end
|
39
|
+
|
40
|
+
# receive image & make size
|
41
|
+
# argument is image String or IO
|
42
|
+
def initialize(img_data, img_type = nil)
|
43
|
+
@img_data = img_data.dup
|
44
|
+
@img_wedth = nil
|
45
|
+
@img_height = nil
|
46
|
+
|
47
|
+
if @img_data.is_a?(IO)
|
48
|
+
@img_top = @img_data.read(128)
|
49
|
+
@img_data.seek(0, 0)
|
50
|
+
# define Singleton-method definition to IO (byte, offset)
|
51
|
+
def @img_data.read_o(length = 1, offset = nil)
|
52
|
+
self.seek(offset, 0) if offset
|
53
|
+
ret = self.read(length)
|
54
|
+
raise "cannot read!!" unless ret
|
55
|
+
ret
|
56
|
+
end
|
57
|
+
elsif @img_data.is_a?(String)
|
58
|
+
@img_top = @img_data[0, 128]
|
59
|
+
# define Singleton-method definition to String (byte, offset)
|
60
|
+
def @img_data.read_o(length = 1, offset = nil)
|
61
|
+
@img_offset = 0 if !(defined?(@img_offset))
|
62
|
+
@img_offset = offset if offset
|
63
|
+
ret = self[@img_offset, length]
|
64
|
+
@img_offset += length
|
65
|
+
ret
|
66
|
+
end
|
67
|
+
else
|
68
|
+
raise "argument class error!! #{img_data.type}"
|
69
|
+
end
|
70
|
+
|
71
|
+
if img_type.nil?
|
72
|
+
@img_type = check_type()
|
73
|
+
else
|
74
|
+
match = false
|
75
|
+
Type.constants.each do |t|
|
76
|
+
match = true if img_type == t
|
77
|
+
end
|
78
|
+
raise("img_type is failed. #{img_type}\n") if match == false
|
79
|
+
@img_type = img_type
|
80
|
+
end
|
81
|
+
|
82
|
+
eval("@img_width, @img_height = measure_" + @img_type + "()") if @img_type != Type::OTHER
|
83
|
+
end
|
84
|
+
|
85
|
+
# get parameter
|
86
|
+
def get_type; @img_type; end
|
87
|
+
def get_height
|
88
|
+
if @img_type == Type::OTHER then nil else @img_height end
|
89
|
+
end
|
90
|
+
def get_width
|
91
|
+
if @img_type == Type::OTHER then nil else @img_width end
|
92
|
+
end
|
93
|
+
|
94
|
+
# koan: additions to get the precision and number of components of a JPEG file
|
95
|
+
def get_bpc
|
96
|
+
if @img_type == Type::JPEG then @img_bpc else nil end
|
97
|
+
end
|
98
|
+
def get_components
|
99
|
+
if @img_type == Type::JPEG then @img_components else nil end
|
100
|
+
end
|
101
|
+
|
102
|
+
def check_type()
|
103
|
+
if @img_top =~ /^GIF8[7,9]a/ then Type::GIF
|
104
|
+
elsif @img_top[0, 8] == "\x89PNG\x0d\x0a\x1a\x0a" then Type::PNG
|
105
|
+
elsif @img_top[0, 2] == "\xFF\xD8" then Type::JPEG
|
106
|
+
elsif @img_top[0, 2] == 'BM' then Type::BMP
|
107
|
+
elsif @img_top =~ /^P[1-7]/ then Type::PPM
|
108
|
+
elsif @img_top =~ /\#define\s+\S+\s+\d+/ then Type::XBM
|
109
|
+
elsif @img_top[0, 4] == "MM\x00\x2a" then Type::TIFF
|
110
|
+
elsif @img_top[0, 4] == "II\x2a\x00" then Type::TIFF
|
111
|
+
elsif @img_top =~ /\/\* XPM \*\// then Type::XPM
|
112
|
+
elsif @img_top[0, 4] == "8BPS" then Type::PSD
|
113
|
+
elsif @img_top[0, 3] == "FWS" then Type::SWF
|
114
|
+
elsif @img_top[0] == 10 then Type::PCX
|
115
|
+
else Type::OTHER
|
116
|
+
end
|
117
|
+
end
|
118
|
+
private(:check_type)
|
119
|
+
|
120
|
+
def measure_GIF()
|
121
|
+
@img_data.read_o(6)
|
122
|
+
@img_data.read_o(4).unpack('vv')
|
123
|
+
end
|
124
|
+
private(:measure_GIF)
|
125
|
+
|
126
|
+
def measure_PNG()
|
127
|
+
@img_data.read_o(12)
|
128
|
+
raise unless @img_data.read_o(4) == "IHDR"
|
129
|
+
@img_data.read_o(8).unpack('NN')
|
130
|
+
end
|
131
|
+
private(:measure_PNG)
|
132
|
+
|
133
|
+
def measure_JPEG()
|
134
|
+
c_marker = "\xFF" # Section marker.
|
135
|
+
@img_data.read_o(2)
|
136
|
+
while(true)
|
137
|
+
marker, code, length = @img_data.read_o(4).unpack('aan')
|
138
|
+
raise "JPEG marker not found!" if marker != c_marker
|
139
|
+
|
140
|
+
if JpegCodeCheck.include?(code)
|
141
|
+
# koan: additions to extract the precision (bits per component) and number of components
|
142
|
+
@img_bpc, height, width, @img_components = @img_data.read_o(6).unpack('CnnC')
|
143
|
+
return([width, height])
|
144
|
+
end
|
145
|
+
@img_data.read_o(length - 2)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
private(:measure_JPEG)
|
149
|
+
|
150
|
+
def measure_BMP()
|
151
|
+
@img_data.read_o(26).unpack("x18VV");
|
152
|
+
end
|
153
|
+
private(:measure_BMP)
|
154
|
+
|
155
|
+
def measure_PPM()
|
156
|
+
header = @img_data.read_o(1024)
|
157
|
+
header.gsub!(/^\#[^\n\r]*/m, "")
|
158
|
+
header =~ /^(P[1-6])\s+?(\d+)\s+?(\d+)/m
|
159
|
+
width = $2.to_i; height = $3.to_i
|
160
|
+
case $1
|
161
|
+
when "P1", "P4" then @img_type = "PBM"
|
162
|
+
when "P2", "P5" then @img_type = "PGM"
|
163
|
+
when "P3", "P6" then @img_type = "PPM"
|
164
|
+
# when "P7"
|
165
|
+
# @img_type = "XV"
|
166
|
+
# header =~ /IMGINFO:(\d+)x(\d+)/m
|
167
|
+
# width = $1.to_i; height = $2.to_i
|
168
|
+
end
|
169
|
+
[width, height]
|
170
|
+
end
|
171
|
+
private(:measure_PPM)
|
172
|
+
|
173
|
+
alias :measure_PGM :measure_PPM
|
174
|
+
private(:measure_PGM)
|
175
|
+
alias :measure_PBM :measure_PPM
|
176
|
+
private(:measure_PBM)
|
177
|
+
|
178
|
+
def measure_XBM()
|
179
|
+
@img_data.read_o(1024) =~ /^\#define\s*\S*\s*(\d+)\s*\n\#define\s*\S*\s*(\d+)/mi
|
180
|
+
[$1.to_i, $2.to_i]
|
181
|
+
end
|
182
|
+
private(:measure_XBM)
|
183
|
+
|
184
|
+
def measure_XPM()
|
185
|
+
width = height = nil
|
186
|
+
while(line = @img_data.read_o(1024))
|
187
|
+
if line =~ /"\s*(\d+)\s+(\d+)(\s+\d+\s+\d+){1,2}\s*"/m
|
188
|
+
width = $1.to_i; height = $2.to_i
|
189
|
+
break
|
190
|
+
end
|
191
|
+
end
|
192
|
+
[width, height]
|
193
|
+
end
|
194
|
+
private(:measure_XPM)
|
195
|
+
|
196
|
+
def measure_PSD()
|
197
|
+
@img_data.read_o(26).unpack("x14NN")
|
198
|
+
end
|
199
|
+
private(:measure_PSD)
|
200
|
+
|
201
|
+
def measure_TIFF()
|
202
|
+
endian = if (@img_data.read_o(4) =~ /II\x2a\x00/o) then 'v' else 'n' end
|
203
|
+
# 'v' little-endian 'n' default to big-endian
|
204
|
+
|
205
|
+
packspec = [
|
206
|
+
nil, # nothing (shouldn't happen)
|
207
|
+
'C', # BYTE (8-bit unsigned integer)
|
208
|
+
nil, # ASCII
|
209
|
+
endian, # SHORT (16-bit unsigned integer)
|
210
|
+
endian.upcase, # LONG (32-bit unsigned integer)
|
211
|
+
nil, # RATIONAL
|
212
|
+
'c', # SBYTE (8-bit signed integer)
|
213
|
+
nil, # UNDEFINED
|
214
|
+
endian, # SSHORT (16-bit unsigned integer)
|
215
|
+
endian.upcase, # SLONG (32-bit unsigned integer)
|
216
|
+
]
|
217
|
+
|
218
|
+
offset = @img_data.read_o(4).unpack(endian.upcase)[0] # Get offset to IFD
|
219
|
+
|
220
|
+
ifd = @img_data.read_o(2, offset)
|
221
|
+
num_dirent = ifd.unpack(endian)[0] # Make it useful
|
222
|
+
offset += 2
|
223
|
+
num_dirent = offset + (num_dirent * 12); # Calc. maximum offset of IFD
|
224
|
+
|
225
|
+
ifd = width = height = nil
|
226
|
+
while(width.nil? || height.nil?)
|
227
|
+
ifd = @img_data.read_o(12, offset) # Get first directory entry
|
228
|
+
break if (ifd.nil? || (offset > num_dirent))
|
229
|
+
offset += 12
|
230
|
+
tag = ifd.unpack(endian)[0] # ...and decode its tag
|
231
|
+
type = ifd[2, 2].unpack(endian)[0] # ...and the data type
|
232
|
+
|
233
|
+
# Check the type for sanity.
|
234
|
+
next if (type > packspec.size + 0) || (packspec[type].nil?)
|
235
|
+
if tag == 0x0100 # Decode the value
|
236
|
+
width = ifd[8, 4].unpack(packspec[type])[0]
|
237
|
+
elsif tag == 0x0101 # Decode the value
|
238
|
+
height = ifd[8, 4].unpack(packspec[type])[0]
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
raise "#{if width.nil? then 'width not defined.' end} #{if height.nil? then 'height not defined.' end}" if width.nil? || height.nil?
|
243
|
+
[width, height]
|
244
|
+
end
|
245
|
+
private(:measure_TIFF)
|
246
|
+
|
247
|
+
def measure_PCX()
|
248
|
+
header = @img_data.read_o(128)
|
249
|
+
head_part = header.unpack('C4S4')
|
250
|
+
width = head_part[6] - head_part[4] + 1
|
251
|
+
height = head_part[7] - head_part[5] + 1
|
252
|
+
[width, height]
|
253
|
+
end
|
254
|
+
private(:measure_PCX)
|
255
|
+
|
256
|
+
def measure_SWF()
|
257
|
+
header = @img_data.read_o(9)
|
258
|
+
raise("This file is not SWF.") unless header.unpack('a3')[0] == 'FWS'
|
259
|
+
|
260
|
+
bit_length = Integer("0b#{header.unpack('@8B5')}")
|
261
|
+
header << @img_data.read_o(bit_length*4/8+1)
|
262
|
+
str = header.unpack("@8B#{5+bit_length*4}")[0]
|
263
|
+
last = 5
|
264
|
+
x_min = Integer("0b#{str[last,bit_length]}")
|
265
|
+
x_max = Integer("0b#{str[(last += bit_length),bit_length]}")
|
266
|
+
y_min = Integer("0b#{str[(last += bit_length),bit_length]}")
|
267
|
+
y_max = Integer("0b#{str[(last += bit_length),bit_length]}")
|
268
|
+
width = (x_max - x_min)/20
|
269
|
+
height = (y_max - y_min)/20
|
270
|
+
[width, height]
|
271
|
+
end
|
272
|
+
private(:measure_PCX)
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
if __FILE__ == $0
|
277
|
+
print "TypeList: #{ImageSize.type.inspect}\n"
|
278
|
+
|
279
|
+
Dir.glob("*").each do |file|
|
280
|
+
print "#{file} (string)\n"
|
281
|
+
open(file, "rb") do |fh|
|
282
|
+
img = ImageSize.new(fh.read)
|
283
|
+
print <<-EOF
|
284
|
+
type: #{img.get_type.inspect}
|
285
|
+
width: #{img.get_width.inspect}
|
286
|
+
height: #{img.get_height.inspect}
|
287
|
+
EOF
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
data/lib/jpeg2pdf.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# License
|
2
|
+
#
|
3
|
+
# Copyright (c) 2004 Koen Vervloesem. All rights reserved.
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, and/or sell copies of the Software, and to permit persons
|
10
|
+
# to whom the Software is furnished to do so, provided that the above
|
11
|
+
# copyright notice(s) and this permission notice appear in all copies of
|
12
|
+
# the Software and that both the above copyright notice(s) and this
|
13
|
+
# permission notice appear in supporting documentation.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
18
|
+
# OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
19
|
+
# HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
|
20
|
+
# SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
|
21
|
+
# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
22
|
+
# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
23
|
+
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
24
|
+
#
|
25
|
+
# Except as contained in this notice, the name of a copyright holder
|
26
|
+
# shall not be used in advertising or otherwise to promote the sale, use
|
27
|
+
# or other dealings in this Software without prior written authorization
|
28
|
+
# of the copyright holder.
|
29
|
+
|
30
|
+
require 'rpdf'
|
31
|
+
require 'image_size'
|
32
|
+
|
33
|
+
class JPEG2PDF
|
34
|
+
include RPDF
|
35
|
+
|
36
|
+
def initialize(pdf)
|
37
|
+
@doc = Document.new(pdf)
|
38
|
+
@imagenumber = 0
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_jpeg(filename)
|
42
|
+
jpegfile = File.open(filename)
|
43
|
+
imagedata = jpegfile.read
|
44
|
+
jpegfile.close
|
45
|
+
size = ImageSize.new(imagedata)
|
46
|
+
if(size.get_type == 'JPEG')
|
47
|
+
width = size.get_width
|
48
|
+
height = size.get_height
|
49
|
+
bpc = size.get_bpc
|
50
|
+
components = size.get_components
|
51
|
+
if components == 1
|
52
|
+
colorspace = :DeviceGray
|
53
|
+
elsif components == 3
|
54
|
+
colorspace = :DeviceRGB
|
55
|
+
elsif components == 4
|
56
|
+
colorspace = :DeviceCMYK
|
57
|
+
else
|
58
|
+
raise Exception.new("Unsupported colorspace in image #{filename}")
|
59
|
+
end
|
60
|
+
|
61
|
+
imagestream = PDFStream.new(imagedata, @doc)
|
62
|
+
imagestream.dict[:Filter] = [:DCTDecode]
|
63
|
+
imagestream.dict[:Name] = "Image#{@imagenumber}".intern
|
64
|
+
|
65
|
+
imagedictionary = ImageDictionary.new(width, height, colorspace, bpc)
|
66
|
+
imagestream.dict.update(imagedictionary)
|
67
|
+
imagestream.invalidate # write jpeg as soon as possible
|
68
|
+
|
69
|
+
page = Page.new(@doc, @doc.pagetree)
|
70
|
+
page[:MediaBox] = [0, 0, width, height]
|
71
|
+
page[:Resources] = { :XObject => { "Image#{@imagenumber}".intern => imagestream } }
|
72
|
+
|
73
|
+
contentstream = PDFStream.new("q\n#{width} 0 0 #{height} 0 0 cm\n/Image#{@imagenumber} Do\nQ", @doc)
|
74
|
+
|
75
|
+
page[:Contents] = contentstream
|
76
|
+
@imagenumber = @imagenumber + 1
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def close
|
81
|
+
@doc.close_pdf
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
data/lib/rpdf.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# License
|
2
|
+
#
|
3
|
+
# Copyright (c) 2004 Koen Vervloesem. All rights reserved.
|
4
|
+
#
|
5
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
# a copy of this software and associated documentation files (the
|
7
|
+
# "Software"), to deal in the Software without restriction, including
|
8
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
# distribute, and/or sell copies of the Software, and to permit persons
|
10
|
+
# to whom the Software is furnished to do so, provided that the above
|
11
|
+
# copyright notice(s) and this permission notice appear in all copies of
|
12
|
+
# the Software and that both the above copyright notice(s) and this
|
13
|
+
# permission notice appear in supporting documentation.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
18
|
+
# OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
19
|
+
# HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
|
20
|
+
# SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
|
21
|
+
# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
22
|
+
# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
23
|
+
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
24
|
+
#
|
25
|
+
# Except as contained in this notice, the name of a copyright holder
|
26
|
+
# shall not be used in advertising or otherwise to promote the sale, use
|
27
|
+
# or other dealings in this Software without prior written authorization
|
28
|
+
# of the copyright holder.
|
29
|
+
|
30
|
+
require 'rpdf/document'
|
31
|
+
require 'rpdf/documentcatalog'
|
32
|
+
require 'rpdf/imagedictionary'
|
33
|
+
require 'rpdf/page'
|
34
|
+
require 'rpdf/pagetree'
|
35
|
+
require 'rpdf/pdfarray'
|
36
|
+
require 'rpdf/pdfboolean'
|
37
|
+
require 'rpdf/pdfdictionary'
|
38
|
+
require 'rpdf/pdfinteger'
|
39
|
+
require 'rpdf/pdfname'
|
40
|
+
require 'rpdf/pdfnull'
|
41
|
+
require 'rpdf/pdfnumeric'
|
42
|
+
require 'rpdf/pdfobject'
|
43
|
+
require 'rpdf/pdfstream'
|
44
|
+
require 'rpdf/pdfstring'
|
45
|
+
require 'rpdf/rectangle'
|
46
|
+
require 'rpdf/trailer'
|
47
|
+
require 'rpdf/util'
|
48
|
+
require 'rpdf/version'
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RPDF
|
2
|
+
|
3
|
+
# Cross-Reference Table
|
4
|
+
# This implementation uses only one cross-reference section
|
5
|
+
# and no free entries.
|
6
|
+
# [PDFRef15 p69]
|
7
|
+
class CrossRefTable
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@hash = Hash.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def addUsedEntry(position, objectnumber)
|
14
|
+
@hash[objectnumber] = position
|
15
|
+
end
|
16
|
+
|
17
|
+
def size
|
18
|
+
@hash.size + 1
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_pdf
|
22
|
+
bytes = "xref\n"
|
23
|
+
bytes << "0 #{size}\n"
|
24
|
+
bytes << "0000000000 65535 f \n"
|
25
|
+
@hash.keys.sort.each { |objectnumber|
|
26
|
+
bytes << ("%010d" % @hash[objectnumber]) << " 00000 n \n"
|
27
|
+
}
|
28
|
+
bytes << "\n"
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|