pdftoruby 0.0.4
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/History.txt +8 -0
- data/Manifest.txt +8 -0
- data/README.txt +56 -0
- data/Rakefile +12 -0
- data/bin/pdftoruby.rb +632 -0
- data/lib/dumppdf.rb +21 -0
- data/lib/pdf-extended-ops.rb +151 -0
- data/lib/pdftoruby.rb +3 -0
- metadata +72 -0
data/History.txt
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
=== 0.0.4 / 2008-05-20
|
2
|
+
|
3
|
+
* 3 major enhancement
|
4
|
+
|
5
|
+
* Added support for SVN version of PDF::Reader using hash to get image parameters
|
6
|
+
* Added support for writing png files
|
7
|
+
* Added internal version of png library to allow fixes, changes, and hardwire it to pure ruby
|
8
|
+
|
data/Manifest.txt
ADDED
data/README.txt
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
= pdftoruby
|
2
|
+
|
3
|
+
* http://code.google.com/p/pdftoruby/
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Convert pdf files into ruby classes - allow creation of complex pdf files from existing pdf files
|
8
|
+
|
9
|
+
== FEATURES/PROBLEMS:
|
10
|
+
|
11
|
+
Support for text
|
12
|
+
Support for Line Graphics
|
13
|
+
Support for Images (Indexed Color)
|
14
|
+
|
15
|
+
Problems:
|
16
|
+
JPG Embedded Images not supported
|
17
|
+
|
18
|
+
== SYNOPSIS:
|
19
|
+
|
20
|
+
pdftoruby.rb mypdf.pdf mypdf.rb MyPdf
|
21
|
+
|
22
|
+
Will read mypdf.pdf and create mypdf.rb with a Class of MyPdf.
|
23
|
+
A subdirectory of the name MyPdf will be created with resources.
|
24
|
+
|
25
|
+
|
26
|
+
== REQUIREMENTS:
|
27
|
+
|
28
|
+
PDF::Reader (Currently from SVN as of May 20, 2008
|
29
|
+
PDF::Writer
|
30
|
+
|
31
|
+
== INSTALL:
|
32
|
+
|
33
|
+
gem install pdftoruby
|
34
|
+
|
35
|
+
== LICENSE:
|
36
|
+
|
37
|
+
Copyright (c) 2008
|
38
|
+
|
39
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
40
|
+
a copy of this software and associated documentation files (the
|
41
|
+
'Software'), to deal in the Software without restriction, including
|
42
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
43
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
44
|
+
permit persons to whom the Software is furnished to do so, subject to
|
45
|
+
the following conditions:
|
46
|
+
|
47
|
+
The above copyright notice and this permission notice shall be
|
48
|
+
included in all copies or substantial portions of the Software.
|
49
|
+
|
50
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
51
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
52
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
53
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
54
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
55
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
56
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/pdftoruby.rb'
|
6
|
+
|
7
|
+
Hoe.new('pdftoruby', Pdftoruby::VERSION) do |p|
|
8
|
+
p.rubyforge_name = 'pdftoruby' # if different than lowercase project name
|
9
|
+
p.developer('glennswest', 'glennswest@yahoo.com.sg')
|
10
|
+
end
|
11
|
+
|
12
|
+
# vim: syntax=Ruby
|
data/bin/pdftoruby.rb
ADDED
@@ -0,0 +1,632 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'pdf/reader'
|
3
|
+
require 'pdf/writer'
|
4
|
+
require 'base64'
|
5
|
+
require 'zlib'
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
$KCODE = 'u'
|
9
|
+
require 'jcode'
|
10
|
+
require 'iconv'
|
11
|
+
require 'base64'
|
12
|
+
|
13
|
+
class String # :nodoc:
|
14
|
+
##
|
15
|
+
# Calculates a CRC using the algorithm in the PNG specification.
|
16
|
+
def png_crc
|
17
|
+
unless defined? @@crc then
|
18
|
+
@@crc = Array.new(256)
|
19
|
+
256.times do |n|
|
20
|
+
c = n
|
21
|
+
8.times do
|
22
|
+
c = (c & 1 == 1) ? 0xedb88320 ^ (c >> 1) : c >> 1
|
23
|
+
end
|
24
|
+
@@crc[n] = c
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
c = 0xffffffff
|
29
|
+
each_byte do |b|
|
30
|
+
c = @@crc[(c^b) & 0xff] ^ (c >> 8)
|
31
|
+
end
|
32
|
+
return c ^ 0xffffffff
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
## gsw - Make sure we have version 1 - as version 2 will require major havoc - also fix the "binary" issue
|
38
|
+
# A pure Ruby Portable Network Graphics (PNG) writer.
|
39
|
+
#
|
40
|
+
# http://www.libpng.org/pub/png/spec/1.2/
|
41
|
+
#
|
42
|
+
# PNG supports:
|
43
|
+
# + 8 bit truecolor PNGs
|
44
|
+
#
|
45
|
+
# PNG does not support:
|
46
|
+
# + any other color depth
|
47
|
+
# + extra data chunks
|
48
|
+
# + filters
|
49
|
+
#
|
50
|
+
# = Example
|
51
|
+
#
|
52
|
+
# require 'png'
|
53
|
+
#
|
54
|
+
# canvas = PNG::Canvas.new 200, 200
|
55
|
+
# canvas[100, 100] = PNG::Color::Black
|
56
|
+
# canvas.line 50, 50, 100, 50, PNG::Color::Blue
|
57
|
+
# png = PNG.new canvas
|
58
|
+
# png.save 'blah.png'
|
59
|
+
|
60
|
+
class PNG
|
61
|
+
|
62
|
+
##
|
63
|
+
# Creates a PNG chunk of type +type+ that contains +data+.
|
64
|
+
|
65
|
+
def self.chunk(type, data="")
|
66
|
+
[data.size, type, data, (type + data).png_crc].pack("Na*a*N")
|
67
|
+
end
|
68
|
+
|
69
|
+
##
|
70
|
+
# Creates a new PNG object using +canvas+
|
71
|
+
|
72
|
+
def initialize(canvas)
|
73
|
+
@height = canvas.height
|
74
|
+
@width = canvas.width
|
75
|
+
@bits = 8
|
76
|
+
@data = canvas.data
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Writes the PNG to +path+.
|
81
|
+
|
82
|
+
def save(path)
|
83
|
+
File.open(path, "wb") do |f|
|
84
|
+
f.write [137, 80, 78, 71, 13, 10, 26, 10].pack("C*") # PNG signature
|
85
|
+
f.write PNG.chunk('IHDR',
|
86
|
+
[ @height, @width, @bits, 2, 0, 0, 0 ].pack("N2C5"))
|
87
|
+
# 0 == filter type code "none"
|
88
|
+
data = @data.map { |row| [0] + row.map { |p| [p.values[0], p.values[1], p.values[2]] } }.flatten
|
89
|
+
#data = @data.map { |row| [0] + row.map { |p| p.values } }.flatten
|
90
|
+
f.write PNG.chunk('IDAT', Zlib::Deflate.deflate(data.pack("C*"), 9))
|
91
|
+
f.write PNG.chunk('IEND', '')
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
##
|
96
|
+
# RGBA colors
|
97
|
+
|
98
|
+
class Color
|
99
|
+
|
100
|
+
attr_reader :values
|
101
|
+
|
102
|
+
##
|
103
|
+
# Creates a new color with values +red+, +green+, +blue+, and +alpha+.
|
104
|
+
|
105
|
+
def initialize(red, green, blue, alpha)
|
106
|
+
@values = [red, green, blue, alpha]
|
107
|
+
end
|
108
|
+
|
109
|
+
##
|
110
|
+
# Transparent white
|
111
|
+
|
112
|
+
Background = Color.new 0xFF, 0xFF, 0xFF, 0x00
|
113
|
+
|
114
|
+
White = Color.new 0xFF, 0xFF, 0xFF, 0xFF
|
115
|
+
Black = Color.new 0x00, 0x00, 0x00, 0xFF
|
116
|
+
Gray = Color.new 0x7F, 0x7F, 0x7F, 0xFF
|
117
|
+
|
118
|
+
Red = Color.new 0xFF, 0x00, 0x00, 0xFF
|
119
|
+
Orange = Color.new 0xFF, 0xA5, 0x00, 0xFF
|
120
|
+
Yellow = Color.new 0xFF, 0xFF, 0x00, 0xFF
|
121
|
+
Green = Color.new 0x00, 0xFF, 0x00, 0xFF
|
122
|
+
Blue = Color.new 0x00, 0x00, 0xFF, 0xFF
|
123
|
+
Purple = Color.new 0XFF, 0x00, 0xFF, 0xFF
|
124
|
+
|
125
|
+
##
|
126
|
+
# Red component
|
127
|
+
|
128
|
+
def r; @values[0]; end
|
129
|
+
|
130
|
+
##
|
131
|
+
# Green component
|
132
|
+
|
133
|
+
def g; @values[1]; end
|
134
|
+
|
135
|
+
##
|
136
|
+
# Blue component
|
137
|
+
|
138
|
+
def b; @values[2]; end
|
139
|
+
|
140
|
+
##
|
141
|
+
# Alpha transparency component
|
142
|
+
|
143
|
+
def a; @values[3]; end
|
144
|
+
|
145
|
+
##
|
146
|
+
# Blends +color+ into this color returning a new blended color.
|
147
|
+
|
148
|
+
def blend(color)
|
149
|
+
return Color.new((r * (0xFF - color.a) + color.r * color.a) >> 8,
|
150
|
+
(g * (0xFF - color.a) + color.g * color.a) >> 8,
|
151
|
+
(b * (0xFF - color.a) + color.b * color.a) >> 8,
|
152
|
+
(a * (0xFF - color.a) + color.a * color.a) >> 8)
|
153
|
+
end
|
154
|
+
|
155
|
+
##
|
156
|
+
# Returns a new color with an alpha value adjusted by +i+.
|
157
|
+
|
158
|
+
def intensity(i)
|
159
|
+
return Color.new(r,b,g,(a*i) >> 8)
|
160
|
+
end
|
161
|
+
|
162
|
+
def inspect # :nodoc:
|
163
|
+
"#<%s %02x %02x %02x %02x>" % [self.class, *@values]
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
##
|
169
|
+
# PNG canvas
|
170
|
+
|
171
|
+
class Canvas
|
172
|
+
|
173
|
+
##
|
174
|
+
# Height of the canvas
|
175
|
+
|
176
|
+
attr_reader :height
|
177
|
+
|
178
|
+
##
|
179
|
+
# Width of the canvas
|
180
|
+
|
181
|
+
attr_reader :width
|
182
|
+
|
183
|
+
##
|
184
|
+
# Raw data
|
185
|
+
|
186
|
+
attr_reader :data
|
187
|
+
|
188
|
+
def initialize(height, width, background = Color::White)
|
189
|
+
@height = height
|
190
|
+
@width = width
|
191
|
+
@data = Array.new(@width) { |x| Array.new(@height) { background } }
|
192
|
+
end
|
193
|
+
|
194
|
+
##
|
195
|
+
# Retrieves the color of the pixel at (+x+, +y+).
|
196
|
+
|
197
|
+
def [](x, y)
|
198
|
+
raise "bad x value #{x} >= #{@height}" if x >= @height
|
199
|
+
raise "bad y value #{y} >= #{@width}" if y >= @width
|
200
|
+
@data[y][x]
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# Sets the color of the pixel at (+x+, +y+) to +color+.
|
205
|
+
|
206
|
+
def []=(x, y, color)
|
207
|
+
raise "bad x value #{x} >= #{@height}" if x >= @height
|
208
|
+
raise "bad y value #{y} >= #{@width}" if y >= @width
|
209
|
+
@data[y][x] = color
|
210
|
+
end
|
211
|
+
|
212
|
+
##
|
213
|
+
# Iterates over each pixel in the canvas.
|
214
|
+
|
215
|
+
def each
|
216
|
+
@data.each_with_index do |row, y|
|
217
|
+
row.each_with_index do |pixel, x|
|
218
|
+
yield x, y, color
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
##
|
224
|
+
# Blends +color+ onto the color at point (+x+, +y+).
|
225
|
+
|
226
|
+
def point(x, y, color)
|
227
|
+
self[x,y] = self[x,y].blend(color)
|
228
|
+
end
|
229
|
+
|
230
|
+
##
|
231
|
+
# Draws a line using Xiaolin Wu's antialiasing technique.
|
232
|
+
#
|
233
|
+
# http://en.wikipedia.org/wiki/Xiaolin_Wu's_line_algorithm
|
234
|
+
|
235
|
+
def line(x0, y0, x1, y1, color)
|
236
|
+
dx = x1 - x0
|
237
|
+
sx = dx < 0 ? -1 : 1
|
238
|
+
dx *= sx # TODO: abs?
|
239
|
+
dy = y1 - y0
|
240
|
+
|
241
|
+
# 'easy' cases
|
242
|
+
if dy == 0 then
|
243
|
+
Range.new(*[x0,x1].sort).each do |x|
|
244
|
+
point(x, y0, color)
|
245
|
+
end
|
246
|
+
return
|
247
|
+
end
|
248
|
+
|
249
|
+
if dx == 0 then
|
250
|
+
(y0..y1).each do |y|
|
251
|
+
point(x0, y, color)
|
252
|
+
end
|
253
|
+
return
|
254
|
+
end
|
255
|
+
|
256
|
+
if dx == dy then
|
257
|
+
Range.new(*[x0,x1].sort).each do |x|
|
258
|
+
point(x, y0, color)
|
259
|
+
y0 += 1
|
260
|
+
end
|
261
|
+
return
|
262
|
+
end
|
263
|
+
|
264
|
+
# main loop
|
265
|
+
point(x0, y0, color)
|
266
|
+
e_acc = 0
|
267
|
+
if dy > dx then # vertical displacement
|
268
|
+
e = (dx << 16) / dy
|
269
|
+
(y0...y1-1).each do |i|
|
270
|
+
e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xFFFF
|
271
|
+
x0 = x0 + sx if (e_acc <= e_acc_temp)
|
272
|
+
w = 0xFF-(e_acc >> 8)
|
273
|
+
point(x0, y0, color.intensity(w))
|
274
|
+
y0 = y0 + 1
|
275
|
+
point(x0 + sx, y0, color.intensity(0xFF-w))
|
276
|
+
end
|
277
|
+
point(x1, y1, color)
|
278
|
+
return
|
279
|
+
end
|
280
|
+
|
281
|
+
# horizontal displacement
|
282
|
+
e = (dy << 16) / dx
|
283
|
+
(x0...(x1-sx)).each do |i|
|
284
|
+
e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xFFFF
|
285
|
+
y0 += 1 if (e_acc <= e_acc_temp)
|
286
|
+
w = 0xFF-(e_acc >> 8)
|
287
|
+
point(x0, y0, color.intensity(w))
|
288
|
+
x0 += sx
|
289
|
+
point(x0, y0 + 1, color.intensity(0xFF-w))
|
290
|
+
end
|
291
|
+
point(x1, y1, color)
|
292
|
+
end
|
293
|
+
|
294
|
+
end
|
295
|
+
|
296
|
+
end
|
297
|
+
|
298
|
+
|
299
|
+
|
300
|
+
class PDFReceiver < PDF::Reader
|
301
|
+
# def init_xref(xref)
|
302
|
+
# @xref = xref
|
303
|
+
# end
|
304
|
+
|
305
|
+
def initextclass(thefile, theclass)
|
306
|
+
@ruby = thefile
|
307
|
+
@rubyclass = theclass
|
308
|
+
@text_position_x = 0.0
|
309
|
+
@text_position_y = 0.0
|
310
|
+
@text_font = "F1"
|
311
|
+
@text_size = 10.0
|
312
|
+
@ruby.printf("require 'pdf/writer'\n")
|
313
|
+
@ruby.printf("if File.exists?(\"../lib/pdf-extended-ops.rb\")\n")
|
314
|
+
@ruby.printf(" require '../lib/pdf-extended-ops.rb'\n")
|
315
|
+
@ruby.printf(" else \n")
|
316
|
+
@ruby.printf(" require 'pdf-extended-ops.rb'\n")
|
317
|
+
@ruby.printf(" end\n")
|
318
|
+
@ruby.printf("class %s\n",@rubyclass.capitalize)
|
319
|
+
@ruby.printf("def initialize()\n")
|
320
|
+
@ruby.printf("end\n")
|
321
|
+
@ruby.printf("\n\n")
|
322
|
+
@ruby.printf("def rendertofile(thename)\n")
|
323
|
+
@ruby.printf(" File.open(thename,\"wb\"){ |f| f.write @pdf.render }\n")
|
324
|
+
@ruby.printf(" end\n\n")
|
325
|
+
@ruby.printf("def createpage()\n")
|
326
|
+
end
|
327
|
+
|
328
|
+
def begin_document(args)
|
329
|
+
end
|
330
|
+
|
331
|
+
def begin_page(values)
|
332
|
+
pp values
|
333
|
+
rotate_value = values[:Rotate]
|
334
|
+
media_box = values[:MediaBox]
|
335
|
+
pp rotate_value
|
336
|
+
if rotate_value == 90.0
|
337
|
+
mypaper = ":paper => [#{media_box[0]}, #{media_box[1]}, #{media_box[2]}, #{media_box[3]}]"
|
338
|
+
pp mypaper
|
339
|
+
# @ruby.printf(" @pdf = PDF::Writer.new(:orientation => :landscape,#{mypaper})\n")
|
340
|
+
@ruby.printf(" @pdf = PDF::Writer.new(#{mypaper})\n")
|
341
|
+
else
|
342
|
+
mypaper = ":paper => [#{media_box[0]}, #{media_box[1]}, #{media_box[2]}, #{media_box[3]}]"
|
343
|
+
pp mypaper
|
344
|
+
@ruby.printf(" @pdf = PDF::Writer.new(#{mypaper})\n")
|
345
|
+
end
|
346
|
+
#@ruby.printf(" @pdf = PDF::Writer.new\n")
|
347
|
+
#@ruby.printf(" @pdf.select_font (\"Helvetica\", { :encoding => \"WinAnsiEncoding\" })\n")
|
348
|
+
|
349
|
+
#thefile = File.open("test.img","w")
|
350
|
+
#ithefile.write(therawbytes)
|
351
|
+
#thefile.close
|
352
|
+
end
|
353
|
+
|
354
|
+
def begin_page_container(values)
|
355
|
+
@pagemediabox = values["MediaBox"]
|
356
|
+
@pageresources = values["Resources"]
|
357
|
+
@pagekids = values["Kids"]
|
358
|
+
@pagetype = values["Type"]
|
359
|
+
end
|
360
|
+
|
361
|
+
def begin_marked_content_with_pl(flag,mcid)
|
362
|
+
mcid.each do |key, value|
|
363
|
+
@ruby.printf(" @pdf.begin_marked_content_with_p1(\"#{flag}\",\"#{key}\",\"#{value}\")\n")
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
#{:name=>:set_gray_for_stroking, :args=>[0.0]}
|
368
|
+
def set_gray_for_stroking(value)
|
369
|
+
@ruby.printf(" @pdf.set_gray_for_stroking(#{value})\n")
|
370
|
+
end
|
371
|
+
|
372
|
+
#{:name=>:set_line_width, :args=>[0.72]}
|
373
|
+
def set_line_width(value)
|
374
|
+
@ruby.printf(" @pdf.set_line_width(#{value})\n")
|
375
|
+
end
|
376
|
+
|
377
|
+
#{:name=>:set_miter_limit, :args=>[10.0]}
|
378
|
+
def set_miter_limit(value)
|
379
|
+
@ruby.printf(" @pdf.set_miter_limit(#{value})\n")
|
380
|
+
end
|
381
|
+
|
382
|
+
#{:name=>:set_line_join_style, :args=>[0.0]}
|
383
|
+
def set_line_join_style(value)
|
384
|
+
@ruby.printf(" @pdf.set_line_join_style(#{value})\n")
|
385
|
+
end
|
386
|
+
|
387
|
+
#{:name=>:set_line_cap_style, :args=>[1.0]}
|
388
|
+
def set_line_cap_style(value)
|
389
|
+
@ruby.printf(" @pdf.set_line_cap_style(#{value})\n")
|
390
|
+
end
|
391
|
+
|
392
|
+
#{:name=>:set_line_dash, :args=>[[], 0.0]}
|
393
|
+
def set_line_dash(values,widths)
|
394
|
+
@ruby.printf(" @pdf.set_line_dash(#{values.inspect},#{widths})\n")
|
395
|
+
end
|
396
|
+
|
397
|
+
#{:name=>:close_subpath, :args=>[]}
|
398
|
+
def close_subpath()
|
399
|
+
@ruby.printf(" @pdf.close_subpath()\n")
|
400
|
+
end
|
401
|
+
|
402
|
+
#{:name=>:stroke_path, :args=>[]}
|
403
|
+
def stroke_path()
|
404
|
+
@ruby.printf(" @pdf.stroke_path()\n")
|
405
|
+
end
|
406
|
+
|
407
|
+
def begin_marked_content(value)
|
408
|
+
@ruby.printf(" @pdf.begin_marked_content(\"#{value}\")\n")
|
409
|
+
end
|
410
|
+
|
411
|
+
|
412
|
+
def end_marked_content()
|
413
|
+
@ruby.printf(" @pdf.end_marked_content()\n")
|
414
|
+
end
|
415
|
+
|
416
|
+
def begin_text_object()
|
417
|
+
@ruby.printf(" @pdf.begin_text_object()\n")
|
418
|
+
end
|
419
|
+
|
420
|
+
def end_text_object()
|
421
|
+
@ruby.printf(" @pdf.end_text_object()\n")
|
422
|
+
end
|
423
|
+
|
424
|
+
def set_character_spacing(space_value)
|
425
|
+
@ruby.printf(" @pdf.set_character_spacing(#{space_value})\n")
|
426
|
+
end
|
427
|
+
|
428
|
+
def move_text_position(x,y)
|
429
|
+
if x
|
430
|
+
@text_position_x = x
|
431
|
+
end
|
432
|
+
if y
|
433
|
+
@text_position_y = y
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
def set_text_font_and_size(thefont,thesize)
|
438
|
+
@ruby.printf(" @pdf.set_text_font_and_size(\"%s\", %.3f)\n", thefont, thesize)
|
439
|
+
end
|
440
|
+
|
441
|
+
def set_character_spacing(value)
|
442
|
+
@ruby.printf(" @pdf.set_character_spacing(#{value})\n",value)
|
443
|
+
end
|
444
|
+
|
445
|
+
def set_word_spacing(value)
|
446
|
+
@ruby.printf(" @pdf.set_word_spacing(#{value})\n",value)
|
447
|
+
end
|
448
|
+
|
449
|
+
# there's a few text callbacks, so make sure we process them all
|
450
|
+
def show_text(string)
|
451
|
+
#string = string.chomp.rstrip
|
452
|
+
#if string.empty?
|
453
|
+
# return
|
454
|
+
# end
|
455
|
+
string = string.chomp
|
456
|
+
@ruby.printf(" @pdf.show_text(\"#{string}\")\n")
|
457
|
+
end
|
458
|
+
|
459
|
+
def super_show_text(string, *params)
|
460
|
+
string.chomp!
|
461
|
+
if string.empty?
|
462
|
+
return
|
463
|
+
end
|
464
|
+
@ruby.printf(" @pdf.show_text \"%s\"\n", string)
|
465
|
+
end
|
466
|
+
|
467
|
+
def move_to_next_line_and_show_text (string)
|
468
|
+
string.chomp!
|
469
|
+
if string.empty?
|
470
|
+
return
|
471
|
+
end
|
472
|
+
@ruby.printf(" @pdf.add_text %f, %f, \"%s\"\n",
|
473
|
+
@text_position_x, @text_position_y, string)
|
474
|
+
end
|
475
|
+
|
476
|
+
def set_spacing_next_line_show_text (aw, ac, string)
|
477
|
+
string.chomp!
|
478
|
+
if string.empty?
|
479
|
+
return
|
480
|
+
end
|
481
|
+
@ruby.printf(" @pdf.add_text %f, %f, \"%s\"\n",
|
482
|
+
@text_position_x, @text_position_y, string)
|
483
|
+
end
|
484
|
+
|
485
|
+
def set_text_matrix_and_text_line_matrix (a,b,c,d,e,f)
|
486
|
+
@text_position_x = f
|
487
|
+
@text_position_y = e
|
488
|
+
@ruby.printf(" @pdf.set_text_matrix_and_text_line_matrix(%f,%f,%f,%f,%f,%f)\n",
|
489
|
+
a,b,c,d,e,f)
|
490
|
+
end
|
491
|
+
|
492
|
+
def append_rectangle(a,b,c,d)
|
493
|
+
@ruby.printf(" @pdf.append_rectangle(#{a},#{b},#{c},#{d})\n")
|
494
|
+
end
|
495
|
+
|
496
|
+
def fill_path_with_nonzero()
|
497
|
+
@ruby.printf(" @pdf.fill_path_with_nonzero()\n")
|
498
|
+
end
|
499
|
+
|
500
|
+
def begin_new_subpath(a,b)
|
501
|
+
@ruby.printf(" @pdf.begin_new_subpath(#{a},#{b})\n")
|
502
|
+
end
|
503
|
+
|
504
|
+
def append_line(a,b)
|
505
|
+
@ruby.printf(" @pdf.append_line(#{a},#{b})\n")
|
506
|
+
end
|
507
|
+
|
508
|
+
def end_document()
|
509
|
+
@ruby.printf(" end\n")
|
510
|
+
@ruby.printf("end\n")
|
511
|
+
@ruby.printf("\n\n#Class Test\n")
|
512
|
+
@ruby.printf("doc = %s.new\n",@rubyclass)
|
513
|
+
@ruby.printf("doc.createpage\n")
|
514
|
+
@ruby.printf("doc.rendertofile(\"%s_test.pdf\")\n",@rubyclass)
|
515
|
+
@ruby.close
|
516
|
+
end
|
517
|
+
|
518
|
+
def save_graphics_state()
|
519
|
+
@ruby.printf(" @pdf.save_graphics_state()\n")
|
520
|
+
end
|
521
|
+
|
522
|
+
def restore_graphics_state()
|
523
|
+
@ruby.printf(" @pdf.restore_graphics_state()\n")
|
524
|
+
end
|
525
|
+
|
526
|
+
def concatenate_matrix(a,b,c,d,e,f)
|
527
|
+
@ruby.printf(" @pdf.concatenate_matrix(#{a},#{b},#{c},#{d},#{e},#{f})\n")
|
528
|
+
end
|
529
|
+
|
530
|
+
def resource_xobject(name,image_data)
|
531
|
+
specs = image_data.hash
|
532
|
+
colorspace = specs[:ColorSpace]
|
533
|
+
colorspacetype = colorspace[0]
|
534
|
+
if colorspacetype.to_s == "Indexed"
|
535
|
+
cdata = String.new(colorspace[3])
|
536
|
+
end
|
537
|
+
filename = String.new(name.to_s)
|
538
|
+
width = specs[:Width]
|
539
|
+
height = specs[:Height]
|
540
|
+
external_image(filename,image_data,width,height,cdata)
|
541
|
+
end
|
542
|
+
|
543
|
+
def resource_colorspace(name,val)
|
544
|
+
return
|
545
|
+
type = val[0]
|
546
|
+
specs = val[1]
|
547
|
+
csdef = specs[0]
|
548
|
+
#pp "csdef= ", csdef
|
549
|
+
length = csdef["Length"]
|
550
|
+
data = specs[1]
|
551
|
+
dir_name = @rubyclass.to_s
|
552
|
+
FileUtils.mkdir_p dir_name
|
553
|
+
space_name = dir_name + "/" + name + ".colorspace"
|
554
|
+
raw = File.open(space_name,"wb")
|
555
|
+
raw.write data
|
556
|
+
raw.close
|
557
|
+
end
|
558
|
+
|
559
|
+
def invoke_xobject(name)
|
560
|
+
@ruby.printf(" @pdf.invoke_xobject(\"#{@rubyclass.to_s}\",\"#{name}\")\n")
|
561
|
+
end
|
562
|
+
|
563
|
+
|
564
|
+
|
565
|
+
def external_image(name,data,width,height,cdata)
|
566
|
+
dir_name = @rubyclass.to_s
|
567
|
+
FileUtils.mkdir_p dir_name
|
568
|
+
pp dir_name
|
569
|
+
raw_name = dir_name + "/" + name + ".raw"
|
570
|
+
cs_name = dir_name + "/" + name + ".cs"
|
571
|
+
png_name = dir_name + "/" + name + ".png"
|
572
|
+
raw = File.open(cs_name,"w")
|
573
|
+
raw.write cdata
|
574
|
+
raw.close
|
575
|
+
raw = File.open(raw_name,"w")
|
576
|
+
idx = 0
|
577
|
+
data.each_byte do |c|
|
578
|
+
offset = c * 3
|
579
|
+
raw.write(cdata[offset ].chr)
|
580
|
+
raw.write(cdata[offset+1].chr)
|
581
|
+
raw.write(cdata[offset+2].chr)
|
582
|
+
idx + 1
|
583
|
+
end
|
584
|
+
raw.close
|
585
|
+
#need to convert the RGB file to PNG
|
586
|
+
canvas = PNG::Canvas.new width, height
|
587
|
+
position = 0
|
588
|
+
for x in (0..height-1)
|
589
|
+
for y in (0..width-1)
|
590
|
+
c = data[position]
|
591
|
+
offset = c * 3
|
592
|
+
canvas[y,x] = PNG::Color.new cdata[offset], cdata[offset+1], cdata[offset+2], 0x00
|
593
|
+
position = position + 1
|
594
|
+
end
|
595
|
+
end
|
596
|
+
png = PNG.new canvas
|
597
|
+
pp png_name
|
598
|
+
png.save png_name
|
599
|
+
end
|
600
|
+
|
601
|
+
def inline_image_raw(data)
|
602
|
+
ccnt = 0
|
603
|
+
@ruby.printf(" image_data = String.new\n")
|
604
|
+
image_data.each_byte do |c|
|
605
|
+
if ccnt == 0
|
606
|
+
@ruby.printf(" image_data << \"")
|
607
|
+
end
|
608
|
+
@ruby.printf("\\x%2.2x", c)
|
609
|
+
ccnt = ccnt + 1
|
610
|
+
if ccnt == 32
|
611
|
+
@ruby.printf("\"\n")
|
612
|
+
ccnt = 0
|
613
|
+
end
|
614
|
+
end
|
615
|
+
if ccnt > 0
|
616
|
+
@ruby.printf("\"\n")
|
617
|
+
end
|
618
|
+
@ruby.printf(" @pdf.xobject(id,name,image_specs,image_data)\n")
|
619
|
+
end
|
620
|
+
|
621
|
+
end
|
622
|
+
|
623
|
+
pdf_filename = ARGV[0]
|
624
|
+
ruby_filename = ARGV[1]
|
625
|
+
methodname = ARGV[2]
|
626
|
+
|
627
|
+
rubyfile = File.open(ruby_filename, "w")
|
628
|
+
|
629
|
+
receiver = PDFReceiver.new
|
630
|
+
receiver.initextclass(rubyfile,methodname)
|
631
|
+
|
632
|
+
pdf = PDF::Reader.file(pdf_filename, receiver)
|
data/lib/dumppdf.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'pdf/reader'
|
3
|
+
require 'pdf/writer'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
$KCODE = 'u'
|
7
|
+
require 'jcode'
|
8
|
+
require 'iconv'
|
9
|
+
require 'base64'
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
pdf_filename = ARGV[0]
|
14
|
+
|
15
|
+
receiver = PDF::Reader::RegisterReceiver.new
|
16
|
+
pdf = PDF::Reader.file(pdf_filename, receiver)
|
17
|
+
receiver.callbacks.each do |cb|
|
18
|
+
pp cb
|
19
|
+
end
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# Extensions by Glenn S. West
|
2
|
+
# Extra methods to allow a more "direct" mapping" from pdf-reader
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
class PDF::Writer
|
6
|
+
#Hacked add image to not mess up coordinate space - gsw
|
7
|
+
def myimage(image, label)
|
8
|
+
|
9
|
+
if image.respond_to?(:read)
|
10
|
+
data = image.read
|
11
|
+
else
|
12
|
+
open(image, 'rb') { |ff| data = ff.read }
|
13
|
+
end
|
14
|
+
|
15
|
+
image_info ||= PDF::Writer::Graphics::ImageInfo.new(data)
|
16
|
+
tt = Time.now
|
17
|
+
@images << tt
|
18
|
+
id = @images.index(tt)
|
19
|
+
image_obj = PDF::Writer::External::Image.new(self, data, image_info, label)
|
20
|
+
@images[id] = image_obj
|
21
|
+
|
22
|
+
image_obj
|
23
|
+
end
|
24
|
+
|
25
|
+
def save_graphics_state()
|
26
|
+
add_content("\nq")
|
27
|
+
end
|
28
|
+
|
29
|
+
def restore_graphics_state()
|
30
|
+
add_content("\nQ")
|
31
|
+
end
|
32
|
+
|
33
|
+
def concatenate_matrix(a,b,c,d,e,f)
|
34
|
+
add_content("\n%f %f %f %f %f %f cm" % [ a, b, c, d, e, f])
|
35
|
+
@pdfeo_matrix = Array.[](a,b,c,d,e,f)
|
36
|
+
end
|
37
|
+
|
38
|
+
def invoke_xobject(form,name)
|
39
|
+
dir_name = @rubyclass.to_s
|
40
|
+
png_name = form + "/" + name + ".png"
|
41
|
+
myimage(png_name, name)
|
42
|
+
add_content("\n/#{name} Do")
|
43
|
+
end
|
44
|
+
|
45
|
+
# Page 405 - PDF Reference
|
46
|
+
def begin_text_object()
|
47
|
+
add_content("\nBT")
|
48
|
+
end
|
49
|
+
|
50
|
+
def set_character_spacing(value)
|
51
|
+
add_content("\n #{value} Tc")
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_word_spacing(value)
|
55
|
+
add_content("\n #{value} Tw")
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_text_font_and_size(fontabbr,fontsize)
|
59
|
+
add_content("\n/#{fontabbr} #{fontsize} Tf")
|
60
|
+
end
|
61
|
+
|
62
|
+
def end_text_object()
|
63
|
+
add_content("\nET")
|
64
|
+
end
|
65
|
+
|
66
|
+
def show_text(txt)
|
67
|
+
thetxt = txt.gsub('\\','\\\\')
|
68
|
+
thetxt = thetxt.gsub('(','\(')
|
69
|
+
thetxt = thetxt.gsub(')','\)')
|
70
|
+
add_content("\n(#{thetxt})Tj")
|
71
|
+
end
|
72
|
+
|
73
|
+
# set_line_matrix_and_text_line_matrix
|
74
|
+
def set_text_matrix_and_text_line_matrix(a, b, c, d, e, f)
|
75
|
+
add_content("\n%f %f %f %f %f %f Tm" % [ a, b, c, d, e, f ])
|
76
|
+
end
|
77
|
+
|
78
|
+
def begin_marked_content(value)
|
79
|
+
add_content("\n/#{value} BMC")
|
80
|
+
end
|
81
|
+
|
82
|
+
def begin_marked_content_with_p1(flag, mcid_type, mcid_value)
|
83
|
+
add_content("\n/#{flag} << /#{mcid_type} #{mcid_value} >>\nBDC")
|
84
|
+
end
|
85
|
+
|
86
|
+
#Page 679 - PDF Reference
|
87
|
+
def end_marked_content()
|
88
|
+
add_content("\nEMC")
|
89
|
+
end
|
90
|
+
|
91
|
+
def append_rectangle(a,b,c,d)
|
92
|
+
add_content("\n#{a} #{b} #{c} #{d} re")
|
93
|
+
end
|
94
|
+
|
95
|
+
def fill_path_with_nonzero()
|
96
|
+
add_content("\nf")
|
97
|
+
end
|
98
|
+
|
99
|
+
def begin_new_subpath(a,b)
|
100
|
+
add_content("\n#{a} #{b} m")
|
101
|
+
end
|
102
|
+
|
103
|
+
def append_line(a,b)
|
104
|
+
add_content("\n#{a} #{b} l")
|
105
|
+
end
|
106
|
+
|
107
|
+
#{:name=>:set_gray_for_stroking, :args=>[0.0]}
|
108
|
+
def set_gray_for_stroking(value)
|
109
|
+
add_content("\n#{value} G")
|
110
|
+
end
|
111
|
+
|
112
|
+
#{:name=>:set_line_width, :args=>[0.72]}
|
113
|
+
def set_line_width(value)
|
114
|
+
add_content("\n#{value} w")
|
115
|
+
end
|
116
|
+
|
117
|
+
#{:name=>:set_miter_limit, :args=>[10.0]}
|
118
|
+
def set_miter_limit(value)
|
119
|
+
add_content("\n#{value} M")
|
120
|
+
end
|
121
|
+
|
122
|
+
#{:name=>:set_line_join_style, :args=>[0.0]}
|
123
|
+
def set_line_join_style(value)
|
124
|
+
thevalue = value.to_i
|
125
|
+
add_content("\n#{thevalue} j")
|
126
|
+
end
|
127
|
+
|
128
|
+
#{:name=>:set_line_cap_style, :args=>[1.0]}
|
129
|
+
def set_line_cap_style(value)
|
130
|
+
thevalue = value.to_i
|
131
|
+
add_content("\n#{thevalue} J")
|
132
|
+
end
|
133
|
+
|
134
|
+
#{:name=>:set_line_dash, :args=>[[], 0.0]}
|
135
|
+
def set_line_dash(values,width)
|
136
|
+
hash_values = values.inspect
|
137
|
+
thecontent = "\n#{hash_values} #{width} d"
|
138
|
+
add_content(thecontent)
|
139
|
+
end
|
140
|
+
|
141
|
+
#{:name=>:close_subpath, :args=>[]}
|
142
|
+
def close_subpath()
|
143
|
+
add_content("\n h")
|
144
|
+
end
|
145
|
+
|
146
|
+
#{:name=>:stroke_path, :args=>[]}
|
147
|
+
def stroke_path()
|
148
|
+
add_content("\n S")
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
data/lib/pdftoruby.rb
ADDED
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pdftoruby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- glennswest
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-05-20 00:00:00 +08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.5.1
|
23
|
+
version:
|
24
|
+
description: Convert pdf files into ruby classes - allow creation of complex pdf files from existing pdf files
|
25
|
+
email:
|
26
|
+
- glennswest@yahoo.com.sg
|
27
|
+
executables:
|
28
|
+
- pdftoruby.rb
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- History.txt
|
33
|
+
- Manifest.txt
|
34
|
+
- README.txt
|
35
|
+
files:
|
36
|
+
- History.txt
|
37
|
+
- Manifest.txt
|
38
|
+
- README.txt
|
39
|
+
- Rakefile
|
40
|
+
- bin/pdftoruby.rb
|
41
|
+
- lib/dumppdf.rb
|
42
|
+
- lib/pdf-extended-ops.rb
|
43
|
+
- lib/pdftoruby.rb
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: http://code.google.com/p/pdftoruby/
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options:
|
48
|
+
- --main
|
49
|
+
- README.txt
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project: pdftoruby
|
67
|
+
rubygems_version: 1.1.1
|
68
|
+
signing_key:
|
69
|
+
specification_version: 2
|
70
|
+
summary: Convert pdf files into ruby classes - allow creation of complex pdf files from existing pdf files
|
71
|
+
test_files: []
|
72
|
+
|