1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
use core:io;
/**
* An object in a PDF file.
*
* A PDF file consists of multiple objects, each describing a part of the document. These are then
* linked to each other through their unique identifier.
*/
class PdfObject {
// The ID of this object. Set when we're added to a File instance.
package Nat id;
// Called just after this object has been attached to a File instance.
void addedTo(File f) {}
// Output ourself to a stream. Adds the mandatory 'obj' and 'endobj' text around the object.
// Override 'output' to provide custom output.
void write(OStream to) : final {
var text = textOutput(to);
text.write("${id} 0 obj ");
text.flush();
output(to, text);
text.write("\nendobj\n");
text.flush();
}
// Output the contents of this object. Use either 'text' or 'to' depending on what is appropriate.
void output(OStream to, TextOutput text) : abstract;
}
/**
* An object that is expressed as a string (like most objects in a PDF).
*
* Makes the string output a bit more convenient by providing a string buffer that can be used to
* emit the data.
*/
class StrObject extends PdfObject {
// Simplify the output of text. Calls 'output(StrBuf)' to acquire the text to be outputted.
void output(OStream to, TextOutput text) : final {
StrBuf out;
output(out);
text.write(out.toS);
}
// Called to get the text to output.
void output(StrBuf to) : abstract;
}
/**
* An object that is stored as a stream.
*
* Keeps track of the length of the stream and writes it properly to the file.
*/
class StreamObject extends PdfObject {
// Calls 'output(OStream)' to acquire the data.
void output(OStream to, TextOutput text) : final {
MemOStream out;
output(out);
text.write("<</Length ${out.buffer.filled} ");
outputHeader(text);
text.write(">>\nstream\n");
text.flush();
to.write(out.buffer);
text.write("\nendstream");
}
// Output additional parameters in the header.
void outputHeader(TextOutput to) {}
// Create the output.
void output(OStream to) : abstract;
}
/**
* An object that could be a stream.
*
* Override 'outputStream' to output the contents, and return true to indicate that the stream is used.
*/
class MaybeStreamObject extends PdfObject {
void output(OStream to, TextOutput text) : final {
text.write("<<");
StrBuf header;
output(header);
MemOStream s;
if (outputStream(s)) {
text.write(header.toS);
text.write("/Length ${s.buffer.filled} ");
text.write(">>\nstream\n");
text.flush();
to.write(s.buffer);
text.write("\nendstream");
} else {
text.write(header.toS);
text.write(">>");
}
}
// Output the text of the header.
void output(StrBuf to) : abstract;
// Output the stream (if any). Return 'true' if the stream shall be used.
Bool outputStream(OStream to) { false; }
}
|