mirror of
https://github.com/MacPaw/XADMaster.git
synced 2025-08-29 19:43:47 +02:00
728 lines
16 KiB
Objective-C
728 lines
16 KiB
Objective-C
|
|
/*
|
|
* PDFStream.m
|
|
*
|
|
* Copyright (c) 2017-present, MacPaw Inc. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301 USA
|
|
*/
|
|
#import "PDFStream.h"
|
|
#import "PDFParser.h"
|
|
#import "PDFEncryptionHandler.h"
|
|
|
|
#import "CCITTHandle.h"
|
|
#import "LZWHandle.h"
|
|
|
|
#import "../CSZlibHandle.h"
|
|
|
|
|
|
|
|
@implementation PDFStream
|
|
|
|
-(id)initWithDictionary:(NSDictionary *)dictionary fileHandle:(CSHandle *)filehandle
|
|
offset:(off_t)offset reference:(PDFObjectReference *)reference parser:(PDFParser *)owner
|
|
{
|
|
if(self=[super init])
|
|
{
|
|
dict=[dictionary retain];
|
|
fh=[filehandle retain];
|
|
offs=offset;
|
|
ref=[reference retain];
|
|
parser=owner;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
-(void)dealloc
|
|
{
|
|
[dict release];
|
|
[fh release];
|
|
[ref release];
|
|
[super dealloc];
|
|
}
|
|
|
|
|
|
|
|
|
|
-(NSDictionary *)dictionary { return dict; }
|
|
|
|
-(PDFObjectReference *)reference { return ref; }
|
|
|
|
|
|
|
|
-(BOOL)isImage
|
|
{
|
|
NSString *type=[dict objectForKey:@"Type"];
|
|
NSString *subtype=[dict objectForKey:@"Subtype"];
|
|
return (!type||[type isEqual:@"XObject"])&&subtype&&[subtype isEqual:@"Image"]; // kludge for broken Ghostscript PDFs
|
|
}
|
|
|
|
-(BOOL)isJPEGImage
|
|
{
|
|
return [[self finalFilter] isEqual:@"DCTDecode"]&&[self imageBitsPerComponent]==8;
|
|
}
|
|
|
|
-(BOOL)isJPEG2000Image
|
|
{
|
|
return [[self finalFilter] isEqual:@"JPXDecode"];
|
|
}
|
|
|
|
|
|
|
|
|
|
-(int)imageWidth
|
|
{
|
|
return [dict intValueForKey:@"Width" default:0];
|
|
}
|
|
|
|
-(int)imageHeight
|
|
{
|
|
return [dict intValueForKey:@"Height" default:0];
|
|
}
|
|
|
|
-(int)imageBitsPerComponent
|
|
{
|
|
if([dict boolValueForKey:@"ImageMask" default:NO]) return 1;
|
|
|
|
return [dict intValueForKey:@"BitsPerComponent" default:0];
|
|
}
|
|
|
|
|
|
|
|
|
|
-(int)imageType
|
|
{
|
|
if([dict boolValueForKey:@"ImageMask" default:NO]) return PDFMaskImageType;
|
|
|
|
id colourspace=[dict objectForKey:@"ColorSpace"];
|
|
return [self _typeForColourSpaceObject:colourspace];
|
|
}
|
|
|
|
-(int)numberOfImageComponents
|
|
{
|
|
if([dict boolValueForKey:@"ImageMask" default:NO]) return 1;
|
|
|
|
id colourspace=[dict objectForKey:@"ColorSpace"];
|
|
return [self _numberOfComponentsForColourSpaceObject:colourspace];
|
|
}
|
|
|
|
-(NSString *)imageColourSpaceName
|
|
{
|
|
id colourspace=[dict objectForKey:@"ColorSpace"];
|
|
return [self _nameForColourSpaceObject:colourspace];
|
|
}
|
|
|
|
|
|
|
|
|
|
-(int)imagePaletteType
|
|
{
|
|
id colourspace=[self _paletteColourSpaceObject];
|
|
if(!colourspace) return PDFUnsupportedImageType;
|
|
return [self _typeForColourSpaceObject:colourspace];
|
|
}
|
|
|
|
-(int)numberOfImagePaletteComponents
|
|
{
|
|
id colourspace=[self _paletteColourSpaceObject];
|
|
if(!colourspace) return 0;
|
|
return [self _numberOfComponentsForColourSpaceObject:colourspace];
|
|
}
|
|
|
|
-(NSString *)imagePaletteColourSpaceName
|
|
{
|
|
id colourspace=[self _paletteColourSpaceObject];
|
|
if(!colourspace) return nil;
|
|
return [self _nameForColourSpaceObject:colourspace];
|
|
}
|
|
|
|
-(int)numberOfImagePaletteColours
|
|
{
|
|
id colourspace=[dict objectForKey:@"ColorSpace"];
|
|
if(!colourspace) return 0;
|
|
|
|
if(![colourspace isKindOfClass:[NSArray class]]) return 0;
|
|
if([colourspace count]!=4) return 0;
|
|
if(![[colourspace objectAtIndex:0] isEqual:@"Indexed"]) return 0;
|
|
|
|
return [[colourspace objectAtIndex:2] intValue]+1;
|
|
}
|
|
|
|
-(NSData *)imagePaletteData
|
|
{
|
|
id colourspace=[dict objectForKey:@"ColorSpace"];
|
|
if(!colourspace) return nil;
|
|
|
|
if(![colourspace isKindOfClass:[NSArray class]]) return nil;
|
|
if([colourspace count]!=4) return nil;
|
|
if(![[colourspace objectAtIndex:0] isEqual:@"Indexed"]) return nil;
|
|
|
|
int numcomponents=[self numberOfImagePaletteComponents];
|
|
int numcolours=[self numberOfImagePaletteColours];
|
|
|
|
id palette=[colourspace objectAtIndex:3];
|
|
|
|
NSData *data;
|
|
if([palette isKindOfClass:[PDFStream class]])
|
|
{
|
|
data=[[palette handle] readDataOfLength:numcomponents*numcolours];
|
|
if(!data) return nil;
|
|
}
|
|
else if([palette isKindOfClass:[PDFString class]])
|
|
{
|
|
data=[palette data];
|
|
if([data length]<numcomponents*numcolours) return nil;
|
|
}
|
|
else
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
-(id)_paletteColourSpaceObject
|
|
{
|
|
id colourspace=[dict objectForKey:@"ColorSpace"];
|
|
if(!colourspace) return nil;
|
|
|
|
if(![colourspace isKindOfClass:[NSArray class]]) return nil;
|
|
if([colourspace count]!=4) return nil;
|
|
if(![[colourspace objectAtIndex:0] isEqual:@"Indexed"]) return nil;
|
|
|
|
return [colourspace objectAtIndex:1];
|
|
}
|
|
|
|
|
|
|
|
|
|
-(int)_typeForColourSpaceObject:(id)colourspace
|
|
{
|
|
NSString *name;
|
|
|
|
if([colourspace isKindOfClass:[NSString class]])
|
|
{
|
|
name=colourspace;
|
|
}
|
|
else if([colourspace isKindOfClass:[NSArray class]])
|
|
{
|
|
int count=[colourspace count];
|
|
if(count<1) return PDFUnsupportedImageType;
|
|
|
|
name=[colourspace objectAtIndex:0];
|
|
if([name isEqual:@"ICCBased"])
|
|
{
|
|
if(count<2) return PDFUnsupportedImageType;
|
|
|
|
PDFStream *def=[colourspace objectAtIndex:1];
|
|
if(![def isKindOfClass:[PDFStream class]]) return PDFUnsupportedImageType;
|
|
|
|
NSString *alternate=[[def dictionary] objectForKey:@"Alternate"];
|
|
if(alternate)
|
|
{
|
|
name=alternate;
|
|
}
|
|
else
|
|
{
|
|
int n=[[def dictionary] intValueForKey:@"N" default:0];
|
|
switch(n)
|
|
{
|
|
case 1: return PDFGrayImageType;
|
|
case 3: return PDFRGBImageType;
|
|
case 4: return PDFCMYKImageType;
|
|
default: return PDFUnsupportedImageType;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return PDFUnsupportedImageType;
|
|
}
|
|
|
|
if([name isEqual:@"DeviceGray"]||[name isEqual:@"CalGray"]) return PDFGrayImageType;
|
|
if([name isEqual:@"DeviceRGB"]||[name isEqual:@"CalRGB"]) return PDFRGBImageType;
|
|
if([name isEqual:@"Indexed"]) return PDFIndexedImageType;
|
|
if([name isEqual:@"DeviceCMYK"]) return PDFCMYKImageType;
|
|
if([name isEqual:@"Separation"]) return PDFSeparationImageType;
|
|
|
|
return PDFUnsupportedImageType;
|
|
}
|
|
|
|
-(int)_numberOfComponentsForColourSpaceObject:(id)colourspace
|
|
{
|
|
NSString *name;
|
|
|
|
if([colourspace isKindOfClass:[NSString class]])
|
|
{
|
|
name=colourspace;
|
|
}
|
|
else if([colourspace isKindOfClass:[NSArray class]])
|
|
{
|
|
int count=[colourspace count];
|
|
if(count<1) return 0;
|
|
|
|
name=[colourspace objectAtIndex:0];
|
|
if([name isEqual:@"ICCBased"])
|
|
{
|
|
if(count<2) return 0;
|
|
|
|
PDFStream *def=[colourspace objectAtIndex:1];
|
|
if(![def isKindOfClass:[PDFStream class]]) return 0;
|
|
|
|
return [[def dictionary] intValueForKey:@"N" default:0];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if([name isEqual:@"DeviceGray"]||[name isEqual:@"CalGray"]) return 1;
|
|
if([name isEqual:@"DeviceRGB"]||[name isEqual:@"CalRGB"]) return 3;
|
|
if([name isEqual:@"Indexed"]) return 1;
|
|
if([name isEqual:@"DeviceCMYK"]) return 4;
|
|
if([name isEqual:@"Separation"]) return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
-(NSString *)_nameForColourSpaceObject:(id)colourspace
|
|
{
|
|
if([colourspace isKindOfClass:[NSString class]])
|
|
{
|
|
return colourspace;
|
|
}
|
|
else if([colourspace isKindOfClass:[NSArray class]])
|
|
{
|
|
int count=[colourspace count];
|
|
if(count<1) return nil;
|
|
|
|
return [colourspace objectAtIndex:0];
|
|
}
|
|
else return nil;
|
|
}
|
|
|
|
|
|
|
|
|
|
-(NSData *)imageICCColourProfile
|
|
{
|
|
id colourspace=[dict objectForKey:@"ColorSpace"];
|
|
return [self _ICCColourProfileForColourSpaceObject:colourspace];
|
|
}
|
|
|
|
-(NSData *)_ICCColourProfileForColourSpaceObject:(id)colourspace
|
|
{
|
|
if([colourspace isKindOfClass:[NSString class]])
|
|
{
|
|
return nil; // TODO: Handle lab?
|
|
}
|
|
else if([colourspace isKindOfClass:[NSArray class]])
|
|
{
|
|
int count=[colourspace count];
|
|
if(count<1) return nil;
|
|
|
|
NSString *name=[colourspace objectAtIndex:0];
|
|
|
|
if([name isEqual:@"ICCBased"])
|
|
{
|
|
if(count!=2) return nil;
|
|
id stream=[colourspace objectAtIndex:1];
|
|
if([stream isKindOfClass:[PDFStream class]]) return [[stream handle] remainingFileContents];
|
|
else return nil;
|
|
}
|
|
else if([name isEqual:@"CalRGB"])
|
|
{
|
|
// TODO: Generate a profile.
|
|
return nil;
|
|
}
|
|
else if([name isEqual:@"CalGray"])
|
|
{
|
|
// TODO: Generate a profile.
|
|
return nil;
|
|
}
|
|
else if([name isEqual:@"Indexed"])
|
|
{
|
|
if(count!=4) return nil;
|
|
id palettespace=[colourspace objectAtIndex:1];
|
|
return [self _ICCColourProfileForColourSpaceObject:palettespace];
|
|
}
|
|
else if([name isEqual:@"Separation"])
|
|
{
|
|
// TODO: Generate an inverted gray profile.
|
|
return nil;
|
|
}
|
|
else
|
|
{
|
|
return nil;
|
|
}
|
|
}
|
|
else return nil;
|
|
}
|
|
|
|
|
|
|
|
|
|
-(NSString *)imageSeparationName
|
|
{
|
|
id colourspace=[dict objectForKey:@"ColorSpace"];
|
|
if(!colourspace) return nil;
|
|
|
|
if(![colourspace isKindOfClass:[NSArray class]]) return nil;
|
|
|
|
int count=[colourspace count];
|
|
if(count<2) return nil;
|
|
|
|
NSString *name=[colourspace objectAtIndex:0];
|
|
if(![name isEqual:@"Separation"]) return nil;
|
|
|
|
return [colourspace objectAtIndex:1];
|
|
}
|
|
|
|
-(NSArray *)imageDecodeArray
|
|
{
|
|
id decode=[dict objectForKey:@"Decode"];
|
|
if(!decode) return nil;
|
|
|
|
if(![decode isKindOfClass:[NSArray class]]) return nil;
|
|
|
|
int n=[self numberOfImageComponents];
|
|
if([decode count]!=n*2) return nil;
|
|
|
|
return decode;
|
|
}
|
|
|
|
|
|
|
|
-(BOOL)hasMultipleFilters
|
|
{
|
|
id filter=[dict objectForKey:@"Filter"];
|
|
|
|
if(!filter) return NO;
|
|
else if([filter isKindOfClass:[NSArray class]]) return [filter count]>1;
|
|
else return NO;
|
|
}
|
|
|
|
-(NSString *)finalFilter
|
|
{
|
|
id filter=[dict objectForKey:@"Filter"];
|
|
|
|
if(!filter) return nil;
|
|
else if([filter isKindOfClass:[NSArray class]]) return [filter lastObject];
|
|
else return filter;
|
|
}
|
|
|
|
|
|
|
|
|
|
-(CSHandle *)rawHandle
|
|
{
|
|
return [fh subHandleFrom:offs length:[dict intValueForKey:@"Length" default:0]];
|
|
}
|
|
|
|
-(CSHandle *)handle
|
|
{
|
|
return [self handleExcludingLast:NO decrypted:YES];
|
|
}
|
|
|
|
-(CSHandle *)JPEGHandle
|
|
{
|
|
return [self handleExcludingLast:YES decrypted:YES];
|
|
}
|
|
|
|
-(CSHandle *)handleExcludingLast:(BOOL)excludelast
|
|
{
|
|
return [self handleExcludingLast:excludelast decrypted:YES];
|
|
}
|
|
|
|
-(CSHandle *)handleExcludingLast:(BOOL)excludelast decrypted:(BOOL)decrypted
|
|
{
|
|
CSHandle *handle;
|
|
PDFEncryptionHandler *encryption=[parser encryptionHandler];
|
|
|
|
if(encryption && decrypted) handle=[encryption decryptStream:self];
|
|
else handle=[self rawHandle];
|
|
|
|
NSArray *filter=[dict arrayForKey:@"Filter"];
|
|
NSArray *decodeparms=[dict arrayForKey:@"DecodeParms"];
|
|
|
|
if(filter)
|
|
{
|
|
int count=[filter count];
|
|
if(excludelast) count--;
|
|
|
|
for(int i=0;i<count;i++)
|
|
{
|
|
handle=[self handleForFilterName:[filter objectAtIndex:i]
|
|
decodeParms:[decodeparms objectAtIndex:i] parentHandle:handle];
|
|
if(!handle) return nil;
|
|
}
|
|
}
|
|
|
|
return handle;
|
|
}
|
|
|
|
-(CSHandle *)handleForFilterName:(NSString *)filtername decodeParms:(NSDictionary *)decodeparms parentHandle:(CSHandle *)parent
|
|
{
|
|
if(!decodeparms) decodeparms=[NSDictionary dictionary];
|
|
|
|
if([filtername isEqual:@"FlateDecode"])
|
|
{
|
|
return [self predictorHandleForDecodeParms:decodeparms
|
|
parentHandle:[CSZlibHandle zlibHandleWithHandle:parent]];
|
|
}
|
|
else if([filtername isEqual:@"CCITTFaxDecode"])
|
|
{
|
|
int k=[decodeparms intValueForKey:@"K" default:0];
|
|
int cols=[decodeparms intValueForKey:@"Columns" default:1728];
|
|
int white=[decodeparms intValueForKey:@"BlackIs1" default:NO]?0:1;
|
|
|
|
if(k==0) return [[[CCITTFaxT41DHandle alloc] initWithHandle:parent columns:cols white:white] autorelease];
|
|
else if(k>0) return nil;
|
|
// else if(k>0) return [[[CCITTFaxT42DHandle alloc] initWithHandle:parent columns:cols white:white] autorelease];
|
|
else return [[[CCITTFaxT6Handle alloc] initWithHandle:parent columns:cols white:white] autorelease];
|
|
}
|
|
else if([filtername isEqual:@"LZWDecode"])
|
|
{
|
|
int early=[decodeparms intValueForKey:@"EarlyChange" default:1];
|
|
return [self predictorHandleForDecodeParms:decodeparms
|
|
parentHandle:[[[LZWHandle alloc] initWithHandle:parent earlyChange:early] autorelease]];
|
|
}
|
|
else if([filtername isEqual:@"ASCII85Decode"])
|
|
{
|
|
return [[[PDFASCII85Handle alloc] initWithHandle:parent] autorelease];
|
|
}
|
|
else if([filtername isEqual:@"Crypt"])
|
|
{
|
|
return parent; // Handled elsewhere.
|
|
}
|
|
|
|
return nil;
|
|
}
|
|
|
|
-(CSHandle *)predictorHandleForDecodeParms:(NSDictionary *)decodeparms parentHandle:(CSHandle *)parent
|
|
{
|
|
NSNumber *predictor=[decodeparms objectForKey:@"Predictor"];
|
|
if(!predictor) return parent;
|
|
|
|
int pred=[predictor intValue];
|
|
if(pred==1) return parent;
|
|
|
|
NSNumber *columns=[decodeparms objectForKey:@"Columns"];
|
|
NSNumber *colors=[decodeparms objectForKey:@"Colors"];
|
|
NSNumber *bitspercomponent=[decodeparms objectForKey:@"BitsPerComponent"];
|
|
|
|
int cols=columns?[columns intValue]:1;
|
|
int comps=colors?[colors intValue]:1;
|
|
int bpc=bitspercomponent?[bitspercomponent intValue]:8;
|
|
|
|
if(pred==2) return [[[PDFTIFFPredictorHandle alloc] initWithHandle:parent columns:cols components:comps bitsPerComponent:bpc] autorelease];
|
|
else if(pred>=10&&pred<=15) return [[[PDFPNGPredictorHandle alloc] initWithHandle:parent columns:cols components:comps bitsPerComponent:bpc] autorelease];
|
|
else [NSException raise:@"PDFStreamPredictorException" format:@"PDF Predictor %d not supported",pred];
|
|
return nil;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
-(NSString *)description { return [NSString stringWithFormat:@"<Stream with dictionary: %@>",dict]; }
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation PDFASCII85Handle
|
|
|
|
-(id)initWithHandle:(CSHandle *)handle
|
|
{
|
|
return [super initWithInputBufferForHandle:handle];
|
|
}
|
|
|
|
-(void)resetByteStream
|
|
{
|
|
finalbytes=0;
|
|
}
|
|
|
|
static uint8_t ASCII85NextByte(CSInputBuffer *input)
|
|
{
|
|
uint8_t b;
|
|
do { b=CSInputNextByte(input); }
|
|
while(!((b>=33&&b<=117)||b=='z'||b=='~'));
|
|
return b;
|
|
}
|
|
|
|
-(uint8_t)produceByteAtOffset:(off_t)pos
|
|
{
|
|
int byte=pos&3;
|
|
if(byte==0)
|
|
{
|
|
uint8_t c1=ASCII85NextByte(input);
|
|
|
|
if(c1=='z') val=0;
|
|
else if(c1=='~') CSByteStreamEOF(self);
|
|
else
|
|
{
|
|
uint8_t c2,c3,c4,c5;
|
|
|
|
c2=ASCII85NextByte(input);
|
|
if(c2!='~')
|
|
{
|
|
c3=ASCII85NextByte(input);
|
|
if(c3!='~')
|
|
{
|
|
c4=ASCII85NextByte(input);
|
|
if(c4!='~')
|
|
{
|
|
c5=ASCII85NextByte(input);
|
|
if(c5=='~') { c5=33; finalbytes=3; }
|
|
}
|
|
else { c4=c5=33; finalbytes=2; }
|
|
}
|
|
else { c3=c4=c5=33; finalbytes=1; }
|
|
}
|
|
else CSByteStreamEOF(self);
|
|
|
|
val=((((c1-33)*85+c2-33)*85+c3-33)*85+c4-33)*85+c5-33;
|
|
}
|
|
return val>>24;
|
|
}
|
|
else
|
|
{
|
|
if(finalbytes&&byte>=finalbytes) CSByteStreamEOF(self);
|
|
return val>>(24-byte*8);
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation PDFTIFFPredictorHandle
|
|
|
|
-(id)initWithHandle:(CSHandle *)handle columns:(int)columns
|
|
components:(int)components bitsPerComponent:(int)bitspercomp
|
|
{
|
|
if(self=[super initWithInputBufferForHandle:handle])
|
|
{
|
|
cols=columns;
|
|
comps=components;
|
|
bpc=bitspercomp;
|
|
if(bpc!=8) [NSException raise:@"PDFTIFFPredictorException" format:@"Bit depth %d not supported for TIFF predictor",bpc];
|
|
if(comps>4||comps<1) [NSException raise:@"PDFTIFFPredictorException" format:@"Color count %d not supported for TIFF predictor",bpc];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
-(uint8_t)produceByteAtOffset:(off_t)pos
|
|
{
|
|
if(bpc==8)
|
|
{
|
|
int comp=pos%comps;
|
|
if((pos/comps)%cols==0) prev[comp]=CSInputNextByte(input);
|
|
else prev[comp]+=CSInputNextByte(input);
|
|
return prev[comp];
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
static inline int iabs(int a) { return a>=0?a:-a; }
|
|
|
|
@implementation PDFPNGPredictorHandle
|
|
|
|
-(id)initWithHandle:(CSHandle *)handle columns:(int)columns
|
|
components:(int)components bitsPerComponent:(int)bitspercomp
|
|
{
|
|
if(self=[super initWithInputBufferForHandle:handle])
|
|
{
|
|
cols=columns;
|
|
comps=components;
|
|
bpc=bitspercomp;
|
|
if(bpc<8) comps=1;
|
|
if(bpc>8) [NSException raise:@"PDFPNGPredictorException" format:@"Bit depth %d not supported for PNG predictor",bpc];
|
|
|
|
prevbuf=malloc(cols*comps+2*comps);
|
|
}
|
|
return self;
|
|
}
|
|
|
|
-(void)dealloc
|
|
{
|
|
free(prevbuf);
|
|
[super dealloc];
|
|
}
|
|
|
|
-(void)resetByteStream
|
|
{
|
|
memset(prevbuf,0,cols*comps+2*comps);
|
|
}
|
|
|
|
-(uint8_t)produceByteAtOffset:(off_t)pos
|
|
{
|
|
if(bpc<=8)
|
|
{
|
|
int row=(int)(pos/(cols*comps));
|
|
int col=pos%(cols*comps);
|
|
int buflen=cols*comps+2*comps;
|
|
int bufoffs=((col-comps*row)%buflen+buflen)%buflen;
|
|
|
|
if(col==0)
|
|
{
|
|
type=CSInputNextByte(input);
|
|
for(int i=0;i<comps;i++) prevbuf[(i+cols*comps+comps+bufoffs)%buflen]=0;
|
|
}
|
|
|
|
int x=CSInputNextByte(input);
|
|
int a=prevbuf[(cols*comps+comps+bufoffs)%buflen];
|
|
int b=prevbuf[(comps+bufoffs)%buflen];
|
|
int c=prevbuf[bufoffs];
|
|
int val=0;
|
|
|
|
switch(type)
|
|
{
|
|
case 0: val=x; break;
|
|
case 1: val=x+a; break;
|
|
case 2: val=x+b; break;
|
|
case 3: val=x+(a+b)/2; break;
|
|
case 4:
|
|
{
|
|
int p=a+b-c;
|
|
int pa=iabs(p-a);
|
|
int pb=iabs(p-b);
|
|
int pc=iabs(p-c);
|
|
|
|
if(pa<=b&&pa<=pc) val=pa;
|
|
else if(pb<=pc) val=pb;
|
|
else val=pc;
|
|
}
|
|
break;
|
|
}
|
|
|
|
prevbuf[bufoffs]=val;
|
|
return val;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
@end
|
|
|