ちょうど、去年はこんなこと↓をやっていたんだぁ...
2006年01月25日
PDF出力習作(2)-Rawイメージ-
前回はJPEGからPDFとしていたが、今回はRawなイメージからPDFにする方法でJPEGと異なりロスレスなので前よりきれいになる。
下記サンプルは前回同様Form画像aFormからPDFを作成するものです。ちなみに遅いです。それは画素値をRGB値として取得するのに #colorAt:を使っているためでForm画像からBitmapを得てRGB値を取り出すようにすれば速くなると思うが、まぁサンプルと言うことで...
fileName aPDFStream aStream writer aForm objectIndex objectPosition pos length sx sy buffer zipped |
fileName := 'output.pdf'.
buffer := ByteArray new: 3.
objectPosition := OrderedCollection new.
objectIndex := 1.
aPDFStream := (FileStream newFileNamed: fileName) binary.
aForm := Display.
aStream := RWBinaryOrTextStream on: (String new).
aStream binary.
writer := ZLibWriteStream on: aStream.
Cursor write showWhile: [
0 to: (aForm height - 1) do: [:y |
0 to: (aForm width - 1) do: [:x |
color := aForm colorAt: x@y.
buffer at: 1 put: (color red * 255) asInteger.
buffer at: 2 put: (color green * 255) asInteger.
buffer at: 3 put: (color blue * 255) asInteger.
writer nextPutAll: buffer.]]].
writer close.
zipped := writer encodedStream contents.
"PDF Header"
aPDFStream nextPutAll: '%PDF-1.5', String crlf.
"Catalog"
objectPosition add: aPDFStream position.
aPDFStream nextPutAll: objectIndex asString, ' 0 obj', String crlf.
aPDFStream nextPutAll: '<<', String crlf.
aPDFStream nextPutAll: '/Type /Catalog', String crlf.
aPDFStream nextPutAll: '/Pages 2 0 R', String crlf.
aPDFStream nextPutAll: '>>', String crlf.
aPDFStream nextPutAll: 'endobj', String crlf.
objectIndex := objectIndex + 1.
"Pages"
objectPosition add: aPDFStream position.
aPDFStream nextPutAll: objectIndex asString, ' 0 obj', String crlf.
aPDFStream nextPutAll: '<<', String crlf.
aPDFStream nextPutAll: '/Type /Pages', String crlf.
aPDFStream nextPutAll: '/Kids [ 3 0 R ]', String crlf.
aPDFStream nextPutAll: '/Count 1', String crlf.
aPDFStream nextPutAll: '>>', String crlf.
aPDFStream nextPutAll: 'endobj', String crlf.
objectIndex := objectIndex + 1.
"Page"
objectPosition add: aPDFStream position.
aPDFStream nextPutAll: objectIndex asString, ' 0 obj', String crlf.
aPDFStream nextPutAll: '<<', String crlf.
aPDFStream nextPutAll: '/Type /Page', String crlf.
aPDFStream nextPutAll: '/Parent 2 0 R', String crlf.
aPDFStream nextPutAll: '/Resources', String crlf.
aPDFStream nextPutAll: '<<', String crlf.
aPDFStream nextPutAll: '/XObject << /Image0 4 0 R >>', String crlf.
aPDFStream nextPutAll: '/ProcSet [ /PDF /ImageC ]', String crlf.
aPDFStream nextPutAll: '>>', String crlf.
aPDFStream nextPutAll: '/MediaBox [ 0 0 595 842 ]', String crlf.
aPDFStream nextPutAll: '/Contents 5 0 R', String crlf.
aPDFStream nextPutAll: '>>', String crlf.
aPDFStream nextPutAll: 'endobj', String crlf.
objectIndex := objectIndex + 1.
"XObject"
objectPosition add: aPDFStream position.
aPDFStream nextPutAll: objectIndex asString, ' 0 obj', String crlf.
aPDFStream nextPutAll: '<<', String crlf.
aPDFStream nextPutAll: '/Type /XObject', String crlf.
aPDFStream nextPutAll: '/Subtype /Image', String crlf.
aPDFStream nextPutAll: '/Name /Image0', String crlf.
aPDFStream nextPutAll: '/Width ', aForm width asString, String crlf.
aPDFStream nextPutAll: '/Height ', aForm height asString, String crlf.
aPDFStream nextPutAll: '/BitsPerComponent 8', String crlf.
aPDFStream nextPutAll: '/Filter /FlateDecode', String crlf.
aPDFStream nextPutAll: '/ColorSpace /DeviceRGB', String crlf.
aPDFStream nextPutAll: '/Length ', zipped size asString, '>>', String crlf.
aPDFStream nextPutAll: 'stream', String crlf.
"Raw"
aPDFStream nextPutAll: zipped.
aPDFStream nextPutAll: String crlf.
aPDFStream nextPutAll: 'endstream', String crlf.
aPDFStream nextPutAll: 'endobj', String crlf.
objectIndex := objectIndex + 1.
"PageContents"
objectPosition add: aPDFStream position.
aPDFStream nextPutAll: objectIndex asString, ' 0 obj', String crlf.
aPDFStream nextPutAll: '<< /Length ', (objectIndex + 1) asString, ' 0 R >>', String crlf.
aPDFStream nextPutAll: 'stream', String crlf.
pos := aPDFStream position.
aPDFStream nextPutAll: 'q', String crlf.
aForm width > aForm height
ifTrue: [
sx := 595.
sy := 595 * (aForm height) / (aForm width).
]
ifFalse: [
sy := 842.
sx := 842 * (aForm width) / (aForm height).
].
aPDFStream nextPutAll: sx asFloat asString, ' 0 0 ', sy asFloat asString, ' 0 0 cm', String crlf.
aPDFStream nextPutAll: '/Image0 Do', String crlf.
aPDFStream nextPutAll: 'Q', String crlf.
length := aPDFStream position - pos.
aPDFStream nextPutAll: 'endstream', String crlf.
aPDFStream nextPutAll: 'endobj', String crlf.
objectIndex := objectIndex + 1.
"Stream length"
objectPosition add: aPDFStream position.
aPDFStream nextPutAll: objectIndex asString, ' 0 obj', String crlf.
aPDFStream nextPutAll: length asString, String crlf.
aPDFStream nextPutAll: 'endobj', String crlf.
objectIndex := objectIndex + 1.
objectPosition add: aPDFStream position. "xref"
"xref"
aPDFStream nextPutAll: 'xref', String crlf.
aPDFStream nextPutAll: '0 ', objectIndex asString, String crlf.
aPDFStream nextPutAll: '0000000000 65535 f', String crlf.
1 to: (objectPosition size - 1) do: [:idx |
aPDFStream nextPutAll: ((objectPosition at: idx) printPaddedWith: $0 to: 10 base: 10) asString ,' 00000 n', String crlf].
"trailer"
aPDFStream nextPutAll: 'trailer', String crlf.
aPDFStream nextPutAll: '<<', String crlf.
aPDFStream nextPutAll: '/Size ', (objectIndex -1)asString, String crlf.
aPDFStream nextPutAll: '/Root 1 0 R', String crlf.
aPDFStream nextPutAll: '>>', String crlf.
aPDFStream nextPutAll: 'startxref', String crlf.
aPDFStream nextPutAll: objectPosition last asString, String crlf.
aPDFStream nextPutAll: '%%EOF', String crlf.
aPDFStream close.