#import "Aprica.h"
// Aprica2
// copyright Pirmin Braun 1997-2007 - pirmin@pirmin.de
// all Rights reserved;
#include <math.h>
#import "PDFAFM.h"
#define M_SOF0 0xC0 /* Start Of Frame N */
#define M_SOF1 0xC1 /* N indicates which compression process */
#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
#define M_SOF3 0xC3
#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
#define M_SOF6 0xC6
#define M_SOF7 0xC7
#define M_SOF9 0xC9
#define M_SOF10 0xCA
#define M_SOF11 0xCB
#define M_SOF13 0xCD
#define M_SOF14 0xCE
#define M_SOF15 0xCF
#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */
#define M_EOI 0xD9 /* End Of Image (end of datastream) */
#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
#define M_APP0 0xE0 /* Application-specific marker, type N */
#define M_APP12 0xEC /* (we don't bother to list all 16 APPn's) */
#define M_COM 0xFE /* COMment */
#define BOLDFACTOR 1.05
@implementation PBPDFPage
- init;
{ if(!(self = [super init]))return nil;
MA(imageFilenames);
MA(fontNames);
contents = [[NSMutableData alloc]initWithCapacity:1024 * 10];
return self;
}
- (void)dealloc;
{ [imageFilenames release];
[fontNames release];
[contents release];
[mediaBox release];
[super dealloc];
}
ACCESSm(mediaBox,setMediaBox);
- (int)objectIndex;
{ return objectIndex;
}
- (void)setObjectIndex:(int)i;
{ objectIndex=i;
}
- (int)rotate;
{ return rotate;
}
- (void)setRotate:(int)i;
{ rotate=i;
}
- (void)appendToContent:(NSData *)data;
{ if(data && [data length])[contents appendData:data];
}
- (NSMutableArray *)imageFilenames;
{ return imageFilenames;
}
- (NSMutableArray *)fontNames;
{ return fontNames;
}
- (NSMutableData *)contents;
{ return contents;
}
@end
@implementation PBPDFFont
ACCESSm(name,setName);
- init;
{ if(!(self = [super init]))return nil;
MD(widthDict);
widthArrayForPDF = nil;
return self;
}
- (void)dealloc;
{ [widthDict release];
[name release];
[widthArrayForPDF release];
[super dealloc];
}
- (NSDictionary *)widthDict;
{ return widthDict;
}
- (void)addToWidthDict:(NSString *)s;
{//pro unichar dessen breite merken
int i,j;
for(i=0,j=[s length];i<j;i++){ unichar uni = [s characterAtIndex:i];
unsigned short cid = [_APP cidForUnichar:uni];
float w = (float)[_APP widthForCid:cid];
if([name hasSecureSuffix:@"Bold"]){ w = w * BOLDFACTOR; //kleiner Aufschlag fuer Breite
}
[widthDict setObject:NSS((int)w) forKey:NSS(cid)];
}
}
- (int)objectIndex;
{ return objectIndex;
}
- (void)setObjectIndex:(int)i;
{ objectIndex=i;
}
- (int)afmIndex;
{ return afmIndex;
}
- (void)setAfmIndex:(int)i;
{ afmIndex=i;
}
- (NSString *)widthArrayForPDF;
{ if(afmIndex == -1)return @"/Widths [ ]";
if(!widthArrayForPDF){ short *chWidth;
int i;
LMA;
chWidth = pbpdf_charWidth[afmIndex];
for(i=0;i<=255;i++){ // LOGS(([NSSWF @"%03i %03i",i,chWidth[i]]));
[lma addObject:NSS(chWidth[i])];
}
widthArrayForPDF = [[NSSWF @"/Widths [%@]",[lma componentsJoinedByString:@" "]]retain];
}
return widthArrayForPDF;
}
@end
@implementation PBPDFImage
ACCESSm(fileName,setFileName);
ACCESSm(name,setName);
ACCESSClassm(data,setData,NSData);
- init;
{ if(!(self = [super init]))return nil;
return self;
}
- (void)dealloc;
{ [fileName release];
[name release];
[data release];
[super dealloc];
}
- (int)objectIndex;
{ return objectIndex;
}
- (void)setObjectIndex:(int)i;
{ objectIndex=i;
}
- (int)width;
{ return width;
}
- (int)height;
{ return height;
}
- (int)num_components;
{ return num_components;
}
- (int)bitsPerComponent;
{ return bitsPerComponent;
}
- (BOOL)checkForJpeg;
{ unsigned char *p =(unsigned char *)[data bytes];
unsigned char *p1 = p;
int j = [data length];
unsigned char *p2 = p + j;
int i1,i2,l;
unsigned char c1,c2,c;
if(j<2)return NO;
c1 = *p1++;
c2 = *p1++;
if (c1 != 0xFF || c2 != M_SOI)return NO;
while(p1 < p2) { c = *p1++;
while (c != 0xFF && p1 < p2) { //seek to FF LOGS(@"seeking to ff");
c = *p1++;
}
if(!(p1 < p2))break;
c = *p1++;
while (c == 0xFF && p1 < p2) { //seek to ! FF LOGS(@"seeking to non ff");
c = *p1++;
}
if(!(p1 < p2))break;
switch (c) { case M_SOF0: /* Baseline */
case M_SOF1: /* Extended sequential, Huffman */
case M_SOF2: /* Progressive, Huffman */
case M_SOF3: /* Lossless, Huffman */
case M_SOF5: /* Differential sequential, Huffman */
case M_SOF6: /* Differential progressive, Huffman */
case M_SOF7: /* Differential lossless, Huffman */
case M_SOF9: /* Extended sequential, arithmetic */
case M_SOF10: /* Progressive, arithmetic */
case M_SOF11: /* Lossless, arithmetic */
case M_SOF13: /* Differential sequential, arithmetic */
case M_SOF14: /* Differential progressive, arithmetic */
case M_SOF15: /* Differential lossless, arithmetic */
p1+=2; //laenge ueberspringen
if((p2 - p1) < 6)return NO;
bitsPerComponent = *p1++;
i1 = *p1++;
i2 = *p1++;
height = (((unsigned int) i1) << 8) + ((unsigned int) i2);
i1 = *p1++;
i2 = *p1++;
width = (((unsigned int) i1) << 8) + ((unsigned int) i2);
num_components = *p1++;
return YES;
case M_SOS: /* stop before hitting compressed data */
case M_EOI: /* in case it's a tables-only JPEG stream */
return NO;
default: /* Anything else just gets skipped */
i1 = *p1++;
i2 = *p1++;
l = (((unsigned int) i1) << 8) + ((unsigned int) i2);
if(l<2)return NO;
l-=2;
p1 += l;
}
}
return YES;
}
@end
@implementation PBPDFDoc
ACCESSm(mediaBox,setMediaBox);
ACCESSm(currentFontName,setCurrentFontName);
ACCESSClassm(currentPage,setCurrentPage,PBPDFPage);
ACCESSClassm(currentFont,setCurrentFont,PBPDFFont);
- init;
{ if(!(self = [super init]))return nil;
needsFontEmbedding = NO;
MD(imagesByFilename);
MD(fontInfos);
MA(pages);
[self setMediaBox:PBPDF_A4];
rotate = 0; //portrait
wasRendered = NO;
return self;
}
- (BOOL)needsFontEmbedding;
{ return needsFontEmbedding;
}
- (BOOL)wasRendered;
{ return wasRendered;
}
- (void)setWasRendered:(BOOL)yn;
{ wasRendered = yn;
}
+ (PBPDFDoc *)newPDF;
{ PBPDFDoc *pdf = [[[PBPDFDoc alloc]init]autorelease];
return pdf;
}
- (void)addPage;
{ PBPDFPage *p = [[[PBPDFPage alloc]init]autorelease];
if(p){ [pages addObject:p];
[p setMediaBox:mediaBox];
[p setRotate:rotate];
}
[self setCurrentPage:p];
}
- (NSData *)renderPDF;
{//liefert das PDF
// Catalog-Object,Pages-Object,Fonts u. Images Objects, Pages, pro Page 1 Stream
// appendData:
// appendBytes:length:
// dataUsingEncoding:allowLossyConversion:
// NSUnicodeStringEncoding
int objectCount = 4;
int i,j;
NSMutableData *mdt = [NSMutableData dataWithCapacity:50 * 1024];
NSString *kids = [NSSWF @"2 0 obj\n<<\n/Type /Pages\n/Count %i\n/Kids [ ",[pages count]];
NSString *pageFormatString = @"\n%i 0 obj\n<<\n/Type /Page\n/Parent 2 0 R\n/Resources <<\n%@\n%@\n/ProcSet 3 0 R >>\n/MediaBox [%@]\n/Rotate 0\n/Contents %i 0 R\n>>\nendobj\n";
NSString *streamFormatString = @"%i 0 obj\n<</Length %i>>\nstream\n";
NSString *fontInfoFormatString = @"%i 0 obj\n<<\n/Type /Font\n/Subtype /%@\n/BaseFont /%@\n/Encoding /WinAnsiEncoding\n>>\nendobj\n";
NSString *imgInfoFormatString = @"%i 0 obj\n<<\n/Type /XObject\n/Subtype /Image\n/Name /%@\n/Width %i\n/Height %i\n/Filter /DCTDecode\n/BitsPerComponent %i\n/ColorSpace /%@\n/Length %i\n>>\nstream\n";
NSArray *a;
LMDN(offsetByObj);
LMAN(xref);
int xrefOffset;
if(![pages count])return nil; // damit batch & print nicht verwirrt wird
needsFontEmbedding = NO;
[mdt appendData:NSD(@"%PDF-1.4\n")];
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:@"1"];
[mdt appendData:NSD(@"1 0 obj\n<<\n/Type /Catalog\n/Pages 2 0 R\n>>\nendobj\n")];
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:@"3"];
[mdt appendData:NSD(@"3 0 obj\n[/PDF /Text /ImageC ]\nendobj\n")];
a = [fontInfos allValues];
for(i=0,j=[a count];i<j;i++){ PBPDFFont *f = [a oai:i];
int afmIndex = [f afmIndex];
NSString *type;
[f setObjectIndex:objectCount];
///////////////////////////////////////////////////////////
// Arial#20Unicode#20MS Unicode
///////////////////////////////////////////////////////////
if([[f name]hasSecurePrefix:@"Arial#20Unicode#20MS"]){ //prefix, damit es auch mit ,Bold klappt int wdi,wdj;
NSArray *wdk=[[f widthDict] allKeys],*wdo=[[f widthDict] allObjects];
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
[mdt appendData:NSD(([NSSWF @"%i 0 obj\n<<\n/Type /Font\n/Subtype /Type0\n/BaseFont /%@\n/Encoding /Identity-H\n/DescendantFonts [%i 0 R]\n>>\nendobj\n",objectCount,[f name],objectCount+1]))];
objectCount+=1;
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
[mdt appendData:NSD(([NSSWF @"%i 0 obj\n<<\n/Type /Font\n/Subtype /CIDFontType2\n/BaseFont /%@\n/CIDSystemInfo <<\n/Registry (Adobe)\n/Ordering (Identity)\n/Supplement 0\n>>\n/FontDescriptor <<\n/Type /FontDescriptor\n/FontBBox [ 0 0 0 0 ]\n>>\n",objectCount++,[f name]]))];
// noch das widthDict schreiben
[mdt appendData:NSD((@"/W [\n"))];
for(wdi=0,wdj=[wdk count];wdi<wdj;wdi++){ NSString *k = [wdk oai:wdi];
[mdt appendData:NSD(([NSSWF @"%@ %@ %@\n",k,k,[wdo oai:wdi]]))];
}
[mdt appendData:NSD((@"]\n"))];
[mdt appendData:NSD((@">>\nendobj\n"))];
///////////////////////////////////////////////////////////
// WASP#2039 ttf
///////////////////////////////////////////////////////////
}else if([[f name]hasSecurePrefix:@"WASP#2039"]){ //prefix, gibt ein paar abwandlungen// das font-object; widths kriegt man aus afm: ttf2pt1 $fontfile.ttf $amfFile.txt
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
[mdt appendData:NSD(([NSSWF @"%i 0 obj\n"
@"<<\n"
@"/Type /Font\n"
@"/Subtype /TrueType\n"
@"/BaseFont /%@\n"
@"/FontDescriptor %i 0 R\n"
@"/Widths [ 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 720 1440 1440 1440 1440 1440 1440 1440 1440 1440 720 1440 1440 720 720 1440 720 720 720 720 720 720 720 720 720 720 1440 1440 1440 1440 1440 1440 1440 720 720 720 720 723 720 720 720 720 720 720 720 720 720 720 720 720 720 720 720 720 720 720 720 720 720 1440 1440 1440 1440 720 1170 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1170 500 500 500 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 500 500 500 500 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 500 500 500 720 1440 1440 1440 500 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 720 720 720 720 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 500 500 500 500 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 1440 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 500 ]\n"
@"/FirstChar 0\n"
@"/LastChar 255\n"
@"/Encoding /WinAnsiEncoding\n"
@">>\n"
@"endobj\n"
,objectCount,[f name],objectCount+1]))];
objectCount++; // wird innerhalb von NSSWF nicht mehrfach ausgewertet!!!
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
// hier noch der fontdescriptor; daten aus afm
[mdt appendData:NSD(([NSSWF @"%i 0 obj\n"
@"<<\n"
@"/Flags 4\n"
@"/FontBBox [ 0 -400 1410 600 ]\n"
@"/ItalicAngle 0\n"
@"/Ascent 600\n"
@"/Descent 400\n"
@"/CapHeight 600\n"
@"/StemV 80\n"
@"/Type /FontDescriptor\n"
@">>\n"
@"endobj\n"
,objectCount++]))];
}else if([[f name]hasSecurePrefix:@"Free#203#20of#209"]){///////////////////////////////////////////////////////////
// free 3 of 9
///////////////////////////////////////////////////////////
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
[mdt appendData:NSD(([NSSWF @"%i 0 obj\n"
@"<<\n"
@"/Type /Font\n"
@"/Subtype /TrueType\n"
@"/BaseFont /%@\n"
@"/FontDescriptor %i 0 R\n"
@"/Widths [ 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 383 ]\n"
@"/FirstChar 0\n"
@"/LastChar 255\n"
@"/Encoding /WinAnsiEncoding\n"
@">>\n"
@"endobj\n"
,objectCount,[f name],objectCount+1]))];
objectCount++; // wird innerhalb von NSSWF nicht mehrfach ausgewertet!!!
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
// hier noch der fontdescriptor; daten aus afm
[mdt appendData:NSD(([NSSWF @"%i 0 obj\n"
@"<<\n"
@"/Flags 4\n"
@"/FontBBox [ 0 0 357 752 ]\n"
@"/ItalicAngle 0\n"
@"/Ascent 600\n"
@"/Descent 400\n"
@"/CapHeight 600\n"
@"/StemV 80\n"
@"/Type /FontDescriptor\n"
@">>\n"
@"endobj\n"
,objectCount++]))];
}else if([[f name]hasSecurePrefix:@"Code128"]){ ///////////////////////////////////////////////////////////
// Code128bWin
///////////////////////////////////////////////////////////
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
[mdt appendData:NSD(([NSSWF @"%i 0 obj\n"
@"<<\n"
@"/Type /Font\n"
@"/Subtype /TrueType\n"
@"/BaseFont /%@\n"
@"/FontDescriptor %i 0 R\n"
@"/Widths [ 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 550 ]\n"
@"/FirstChar 0\n"
@"/LastChar 255\n"
@"/Encoding /WinAnsiEncoding\n"
@">>\n"
@"endobj\n"
,objectCount,[f name],objectCount+1]))];
objectCount++; // wird innerhalb von NSSWF nicht mehrfach ausgewertet!!!
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
// hier noch der fontdescriptor; daten aus afm
[mdt appendData:NSD(([NSSWF @"%i 0 obj\n"
@"<<\n"
@"/Flags 4\n"
@"/FontBBox [ 0 0 357 752 ]\n"
@"/ItalicAngle 0\n"
@"/Ascent 600\n"
@"/Descent 400\n"
@"/CapHeight 600\n"
@"/StemV 40\n"
@"/Type /FontDescriptor\n"
@">>\n"
@"endobj\n"
,objectCount++]))];
} if([[f name]hasSecurePrefix:@"Code#20EAN13"]){///////////////////////////////////////////////////////////
// Code ean13
///////////////////////////////////////////////////////////
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
[mdt appendData:NSD(([NSSWF @"%i 0 obj\n"
@"<<\n"
@"/Type /Font\n"
@"/Subtype /TrueType\n"
@"/BaseFont /%@\n"
@"/FontDescriptor %i 0 R\n"
@"/Widths [391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 220 391 391 391 391 391 391 391 391 391 122 244 391 391 391 391 342 342 342 342 342 342 342 342 342 342 73 391 391 391 391 391 391 171 171 171 171 171 171 171 171 171 171 171 171 171 171 171 171 171 171 171 171 391 391 391 391 391 391 98 49 391 391 391 391 171 171 171 171 171 171 171 171 171 171 269 269 269 269 269 269 269 269 269 269 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391 391]\n"
@"/FirstChar 0\n"
@"/LastChar 255\n"
@"/Encoding /WinAnsiEncoding\n"
@">>\n"
@"endobj\n"
,objectCount,[f name],objectCount+1]))];
objectCount++; // wird innerhalb von NSSWF nicht mehrfach ausgewertet!!!
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
// hier noch der fontdescriptor; daten aus afm
[mdt appendData:NSD(([NSSWF @"%i 0 obj\n"
@"<<\n"
@"/Flags 4\n"
@"/FontBBox [ 0 0 357 752 ]\n"
@"/ItalicAngle 0\n"
@"/Ascent 600\n"
@"/Descent 400\n"
@"/CapHeight 600\n"
@"/StemV 80\n"
@"/Type /FontDescriptor\n"
@">>\n"
@"endobj\n"
,objectCount++]))];
}else if(afmIndex == NSNotFound){ //nicht eingebaut; TrueType annehmen;///////////////////////////////////////////////////////////
// any TTF
///////////////////////////////////////////////////////////
type = @"TrueType";
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
[mdt appendData:NSD(([NSSWF fontInfoFormatString,objectCount++,type,[f name]]))];
///////////////////////////////////////////////////////////
// Frutiger Type1
///////////////////////////////////////////////////////////
}else if(afmIndex == 14){ needsFontEmbedding = YES;
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
[mdt appendData:NSD(([NSSWF @"%i 0 obj\n"
@"<<\n"
@"/Type /Font\n"
@"/Subtype /Type1\n"
@"/BaseFont /%@\n"
@"/FontDescriptor %i 0 R\n"
@"%@\n"
@"/FirstChar 0\n"
@"/LastChar 255\n"
@"/Encoding /StandardEncoding\n"
@">>\n"
@"endobj\n"
,objectCount,[f name],objectCount+1,[f widthArrayForPDF]]))];
objectCount++; // wird innerhalb von NSSWF nicht mehrfach ausgewertet!!!
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
// hier noch der fontdescriptor; daten aus afm
[mdt appendData:NSD(([NSSWF @"%i 0 obj\n"
@"<<\n"
@"/Flags 32\n"
@"/FontBBox [ -169 -226 1000 929 ]\n"
@"/ItalicAngle 0\n"
@"/Ascent 750\n"
@"/Descent -210\n"
@"/CapHeight 698\n"
@"/StemV 80\n"
@"/Type /FontDescriptor\n"
@">>\n"
@"endobj\n"
,objectCount++]))];
}else{///////////////////////////////////////////////////////////
// base14 Fonts Type1
///////////////////////////////////////////////////////////
type = @"Type1";
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
[mdt appendData:NSD(([NSSWF fontInfoFormatString,objectCount++,type,[f name]]))];
}
}
a = [imagesByFilename allValues];
for(i=0,j=[a count];i<j;i++){ PBPDFImage *img = [a oai:i];
int nc = [img num_components];
[img setObjectIndex:objectCount];
if(nc>4)nc=3;
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
[mdt appendData:NSD(([NSSWF imgInfoFormatString,objectCount,[img name],[img width],[img height],[img bitsPerComponent],[[_APP colorSpaces]oai:nc],[[img data]length]]))];
[mdt appendData:[img data]];
[mdt appendData:NSD(@"\nendstream\nendobj\n")];
objectCount++;
}
for(i=0,j=[pages count];i<j;i++){ PBPDFPage *p = [pages oai:i];
NSString *fonts = @"/Font <<\n";
NSString *imgs = @"/XObject <<\n";
int ii,jj;
kids = [kids stringByAppendingFormat:@"%i 0 R \n",objectCount];
[p setObjectIndex:objectCount++];
a = [p fontNames];
for(ii=0,jj=[a count];ii<jj;ii++){ NSString *s = [a oai:ii];
fonts = [fonts stringByAppendingFormat:@"/%@ %i 0 R\n",[s stringWithoutSpace],[[fontInfos ofk:s]objectIndex]];
}
fonts = [fonts stringByAppendingString:@">>\n"];
a = [p imageFilenames];
for(ii=0,jj=[a count];ii<jj;ii++){ NSString *s = [a oai:ii];
PBPDFImage *img = [imagesByFilename ofk:s];
if(img)imgs = [imgs stringByAppendingFormat:@"/%@ %i 0 R\n",[img name],[img objectIndex]];
}
imgs = [imgs stringByAppendingString:@">>\n"];
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS([p objectIndex])];
[mdt appendData:NSD(([NSSWF pageFormatString,[p objectIndex],fonts,imgs,[p mediaBox],objectCount]))]; //page
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(objectCount)];
[mdt appendData:NSD(([NSSWF streamFormatString,objectCount++,[[p contents] length]]))]; //stream der page
[mdt appendData:[p contents]];
[mdt appendData:NSD(@"\nendstream\nendobj\n")];
}
kids = [kids stringByAppendingString:@"\n]\n>>\nendobj\n"];
[offsetByObj setObject:[NSSWF @"%010i",[mdt length]] forKey:NSS(2)]; // Kids haben Objectnr. 2
[mdt appendData:NSD(kids)];
// xref
xrefOffset = [mdt length];
[xref addObject:@"0000000000 65535 f"]; // erstes dummy-objekt mit Versionsnr. 65535 und
[mdt appendData:NSD(([NSSWF @"xref\n0 %i\n",[offsetByObj count]+1]))];
a = [[offsetByObj allKeys]sortedArrayUsingSelector:@selector(compareNumeric:)];
for(i=0,j=[a count];i<j;i++){ NSString *k = [a oai:i];
NSString *s = [offsetByObj ofk:k];
[xref addObject:[NSSWF @"%@ 00000 n",s]];
}
[mdt appendData:NSD(([[xref componentsJoinedByString:@"\r\n"]stringByAppendingString:@"\r\n"]))];
[mdt appendData:NSD(([NSSWF @"trailer\n<<\n/Size %i\n/Root 1 0 R\n>>\nstartxref\n%i\n%%%%EOF\n",objectCount-1,xrefOffset]))];
wasRendered = YES;
return mdt;
}
- (void)setFont:(NSString *)fontName size:(float)size;
{ PBPDFFont *f;
// base14 Fonts: Type1; character widths bekannt
// Arial Unicode MS: type0, cid type 2; identity-H; cid-string
// sonst: TrueType; characterWidth wird die von Helvetica genommen
if(!FILLED(fontName))fontName=[[_APP fontList] firstObject];
if(size<=0.0)size=11.0;
currentAFMIndex = [[_APP fontList] indexOfObject:fontName];
// NSNotFound ist Merkmal fuer nicht eingebaute
// auch nicht eingebaute belassen fontName = [[_APP fontList] firstObject];
f = [fontInfos ofk:fontName];
if(!f){ //ist noch nicht vorgekommen f = [[[PBPDFFont alloc]init]autorelease];
if(f){ [fontInfos setObject:f forKey:fontName];
[f setName:fontName];
[f setAfmIndex:currentAFMIndex];
}
}
[self setCurrentFont:f];
[self setCurrentFontName:fontName];
currentSize = size;
[[currentPage fontNames]addObjectUniq:fontName];
[currentPage appendToContent:NSD(([NSSWF @"/%@ %.3f Tf\n", [fontName stringWithoutSpace], size]))];
}
- (NSString *)stringOfWidth:(int)maxWidth str:(NSString *)s;
{ float swid = 0.0;
float fsize = currentSize;
unsigned char c1,*p;
int effectiveIndex;
short *chWidth;
const char *str;
if([currentFontName hasSecurePrefix:@"Arial#20Unicode#20MS"]){ int i,j;
fsize *= 0.001; /* normalize here for 1000 unit grid */
for(i=0,j=[s length];i<j;i++){ float f;
unichar uni = [s characterAtIndex:i];
f = (float)[_APP widthForUnichar:uni];
if([currentFontName hasSecureSuffix:@"Bold"]){ f = f * BOLDFACTOR; //kleiner Aufschlag fuer Breite
}
swid += fsize * f;
if(swid >= maxWidth){ if(!i)return EON;
return [s secureSubstringToIndex:i];
}
}
return s;
}
if(currentAFMIndex == NSNotFound) { //kein base14; Helvetica als Annaeherung nehmen effectiveIndex = 0;
}else { effectiveIndex = currentAFMIndex;
}
chWidth = pbpdf_charWidth[effectiveIndex];
str = [[s description]lossyCString]; // nur um Breite festzustellen;
p = (unsigned char *)str;
fsize *= 0.001; /* normalize here for 1000 unit grid */
while((c1 = *p) != 0) { swid += fsize * (float)chWidth[c1];
if(swid >= maxWidth)break;
p++;
}
if(c1 != 0){ return [s secureSubstringToIndex:(p - (unsigned char *)str)]; //hier secure nehmen, weil str durch lossyConversion laenger geworden sein kann;
}
return s;
}
- (NSString *)stringOfWidthFullWord:(int)maxWidth str:(NSString *)s;
{ NSString *s1;
NSRange r;
LMA;
r = [s rangeOfString:@"\n"]; //line-separator; hier ist erstmal ende
if(r.length){ s = [s substringToIndex:r.location + 1];
}
s1 = [self stringOfWidth:maxWidth str:s];
if([s1 iE:s])return s; //hat komplett reingepasst
r = [s1 rangeOfString:@" "]; //word-separator
if(!(r.length))return s1; // kein Space drin, muss komplett bleiben
[lma addObjectsFromArray:[s1 componentsSeparatedByString:@" "]];
[lma secureRemoveLastObject];
return [[lma componentsJoinedByString:@" "]stringByAppendingString:@" "];
}
- (float)stringWidth:(NSString *)s;
{ float swid = 0.0;
float fsize = currentSize;
unsigned char c1, *p;
int effectiveIndex;
short *chWidth;
const char *str;
// sonderbehandlung arial unicode ms
if([currentFontName hasSecurePrefix:@"Arial#20Unicode#20MS"]){ int i,j;
fsize *= 0.001; /* normalize here for 1000 unit grid */
for(i=0,j=[s length];i<j;i++){ float f;
unichar uni = [s characterAtIndex:i];
f = (float)[_APP widthForUnichar:uni];
if([currentFontName hasSecureSuffix:@"Bold"]){ f = f * BOLDFACTOR; //kleiner Aufschlag fuer Breite
}
swid += fsize * f;
}
return(swid);
}
// restliche Fonts; widths sind in tabellen abgelegt
if(currentAFMIndex == NSNotFound) { //kein base14; Helvetica als Annaeherung nehmen effectiveIndex = 0;
}else { effectiveIndex = currentAFMIndex;
}
chWidth = pbpdf_charWidth[effectiveIndex];
str = [[s description]lossyCString]; // nur um Breite festzustellen;
p = (unsigned char *)str;
fsize *= 0.001; /* normalize here for 1000 unit grid */
while((c1 = *p++) != 0) { swid += fsize * (float)chWidth[c1];
}
return(swid);
}
- (void)setCTM:(float)a :(float)b :(float)c :(float)d :(float)x :(float)y;
{ [currentPage appendToContent:NSD(([NSSWF @"%.4f %.4f %.4f %.4f %.4f %.4f Tm\n", a, b, c, d, x, y]))];
}
- (void)concatCTM:(float)a :(float)b :(float)c :(float)d :(float)x :(float)y;
{ [currentPage appendToContent:NSD(([NSSWF @"%.4f %.4f %.4f %.4f %.4f %.4f cm\n", a, b, c, d, x, y]))];
}
- (void)translateCTM:(float)xt :(float)yt;
{ [currentPage appendToContent:NSD(([NSSWF @"1 0 0 1 %.4f %.4f cm\n", xt, yt]))];
}
- (void)text:(NSString *)s x:(float)x y:(float)y rotate:(float)r align:(int)align;
{ float a, b, c, d, angle, vcos, vsin;
float wd=0.0;
float xc, yc;
angle = PI*r/180.0;
vcos = cos(angle);
vsin = sin(angle);
s = [s description]; //kann auch dictionary oder array sein
if(align)wd = [self stringWidth:s];
if(align==2)wd/=2; // center
xc = x - (wd*vcos);
yc = y - (wd*vsin);
a = vcos;
b = vsin;
c = -vsin;
d = vcos;
[self setCTM:a :b :c :d :xc :yc];
if([currentFontName hasSecurePrefix:@"Arial#20Unicode#20MS"]){ [currentPage appendToContent:NSD([_APP cidStringFrom:s])];
[currentFont addToWidthDict:s];
}else if([currentFontName iE:@"FrutigerCE-Roman"]){ [currentPage appendToContent:[[s pdfEscapedString] dataUsingEncoding:(NSWindowsCP1250StringEncoding) allowLossyConversion:YES]];
}else{ [currentPage appendToContent:NSD([s pdfEscapedString])];
}
[currentPage appendToContent:NSD(@" Tj\n")];
}
- (void)jpeg:(NSString *)fn x:(float)x y:(float)y w:(float *)imgw h:(float *)imgh;
{ PBPDFImage *img;
float a, b=0.0, c=0.0, d, e, f;
if(!FILLED(fn))return;
img = [imagesByFilename ofk:fn];
if(!img){// noch nicht geladen; dann hier machen;
NSData *data = [NSData dataWithContentsOfFile:fn];
if(!data){ LOGS(([NSSWF @"jpeg in PDF not found: %@",fn]));
return;
}
img = [[[PBPDFImage alloc]init]autorelease];
[img setFileName:fn];
[img setName:[NSSWF @"img%03i",[imagesByFilename count]]]; //kurzname
[img setData:data];
if([img checkForJpeg]){ [imagesByFilename setObject:img forKey:fn];
}else{ LOGS(([NSSWF @"jpeg in PDF not correct: %@",fn]));
return;
}
if(![img width] || ![img height])return;
}
[[currentPage imageFilenames]addObjectUniq:fn];
e = x;
f = y;
if(fabs(*imgw) > 0.00001) { a = *imgw;
}else if( fabs(*imgh) > 0.00001) { a = (*imgh / [img height]) * [img width];
}else { a = (float)[img width];
*imgw = a;
}
if(fabs(*imgh) > 0.00001) { d = *imgh;
} else if( fabs(*imgw) > 0.00001) { d = (*imgw / [img width]) * [img height];
} else { d = (float)[img height];
*imgh = d;
}
[self gsave];
[self translateCTM:x :y];
[self concatCTM:a :b :c :d :0.0 :0.0];
[currentPage appendToContent:NSD(([NSSWF @"/%@ Do\n",[img name]]))];
[self grestore];
}
- (void)gsave;
{ [currentPage appendToContent:NSD(@"\nq\n")];
}
- (void)grestore;
{ [currentPage appendToContent:NSD(@"Q\n")];
}
- (void)dealloc;
{ [fontInfos release];
[pages release];
[currentFont release];
[mediaBox release];
[currentPage release];
[imagesByFilename release];
[currentFontName release];
[super dealloc];
}
@end