====== PDF Object Types ====== Objects in PDF have a type and attributes of PDF objects expect to hold objects of a specific type. The types form a hierarchy with **''Object''** as root. The PDF type hierarchy is independent of the Smalltalk class hierarchy. Often, the Smalltalk class hierarchy coincides with the PDF type hierarchy, but this is not required. Also, the name of the PDF type can be different from the name of the Smalltalk class, but often they are the same. PDF types and Smalltalk classes are connected by a 1 to 1 relationship: a class can implement only one type and a type can only be implemented by one class. A Smalltalk class is declared to represent a PDF type by implementing the class method **''pdfTypeDefinition''** which returns a PDFTypeDefinition object like: pdfTypeDefinition ^PDFTypeDefinition name: #Integer supertype: #Number section: '7.3.3' documentation: 'An integer shall be written as one or more decimal digits optionally preceded by a sign. The value shall be interpreted as a signed decimal integer and shall be converted to an integer object.' version: 0 * ''name'' is a symbol used as type for the type declarations of an attribute. The name should be identical or very similar to the name used in the PDF specification. * ''supertype'' denotes the parent type. It is ''nil'' for the top PDF type ''Object''. * ''section'' specifies the section of the PDF specification where the type is defined. This will allow the PDF specification to be opened on the documentation of the type. * ''documentation'' holds a short description of the type, usually copied (and slightly edited) from the first paragraph in the PDF specification. * ''version'' is optional and holds an integer specifying the minor PDF version (mayor version is 1) where the type was introduced. When omitted the version defaults to ''0'' (corresponding to PDF version 1.0). ''pdfTypeDefinition'' is a special method used to construct the PDF type hierarchy. ALL ''pdfTypeDefinition'' methods shall only construct and return a PDFTypeDefinition object. In order to do so, ALL implementers of ''pdfTypeDefinition'' are collected, evaluated and sorted into the type hierarchy. Therefore, none of the ''pdfTypeDefinition'' methods shall have any side effects. This allows to define a PDF object type independent of the Smalltalk class hierarchy. ===== Typed Attributes ===== Attributes of Dictionaries are typed. The definition of an Attribute specifies the class/type of the object and wheather the object is directly stored or a reference to it. The following pragmas are used for declaring a type: * **#type:** *aSymbol* The value (or referenced value) should be of type aSymbol * **#typeDirect:** *aSymbol* The value should be of type aSymbol * **#typeIndirect:** *aSymbol* The value should be a reference to an object of type aSymbol * **#typeArrayOf:** *aSymbol* The value should be an array with values (or referenced values) of type aSymbol * **#typeDictionaryOf:** *aSymbol* The value should be a dictionary with values (or referenced values) of type aSymbol The pragmas can occur several times. One of the given types should apply. Page>>Contents This declares that the attribute #Contents of a Page can hold either * a Contents object or * an array of Contents objects. A type of an object is used when it gets assigned to an attribute. With the type requirement of the attribute, the object is specialized to the attribute type if possible. If this is not possible, a TypeError is raised. ==== Example ==== The attribute /Root of /Trailer requires a reference to a /Catalog: Trailer>>Root When you assign a reference to a plain /Dictionary to it aTrailer at: #Root put: Dictionary new newReference the Dictionary is changed to be a /Catalog: aTrailer Root class name = #Catalog If something else gets assigned, a TypeError is raised. aTrailer at: #Root put: Trailer new newReference => TypeError ==== Arrays ==== As /Dictionary can be subclassed, so can /Array. The attributes are not named, but accessed positionally with their index. The attributes in subclasses of /Array should be typed and documented like dictionary attributes. For this, the same pragmas as in /Dictionary are used. In /Dictionary the pragma's #attribute:documentation:, the attribute number was only used for sorting. In /Array it is the index of the attribute. Example: /Rectangle (subclass of /Array) Rectangle>>llx ^self at: 1 Rectangle>>lly ^self at: 2 Rectangle>>urx ^self at: 3 Rectangle>>ury ^self at: 4 Every /Array subclass must implement #numberOfAttributes which is the size of the array. This allows further type checking and the creation of #empty instances with the right number of slots. ==== Specializing ==== From the pragmas above types (instances of Type) are created when sending #typesOf: to a Dictionary with the attribute name as argument. Example: Trailer new typesOf: #Root returns Array with: (IndirectType on: Catalog) === Extended typing === Typing is extended to be able to group several classes in different implementation hierarchies into an abstract PDF Type. **/ColourSpace** shall be the super type of all the different /Array and /Name subclasses. **/Function** shall be the super type of /FunctionDictionary and /FunctionStream. **/Shading** shall be the super type of /ShadingDictionary and /ShadingStream. === subsumes === PDFObject isType: aType and PDFObject class subsumes: aPDFObject First, we need to know if an object is already of a specific type. If this is true, we leave it alone, since it is already what we wanted. A PDF object class implements #subsumes: which is simply the test if the object #isKindOf: the class. The supertypes implement this with a list of top classes to which they delegate. === specializes === aPDFObject asType: aType and PDFObject class specializes: aPDFObject When an object is not a subclass of a type, it can be specialized if the objects class subsumes the type.