This is TiffManager.m in view mode; [Download] [Up]
#import "TiffManager.h"
#import "Thinker.h"
//I tested on 32Mb memory workstation
//it caused flicker if bigger than this
#define MAXIMAGESIZE 150 //scale down if bigger than this
#define SIZEINC 2 //increase image by number of pixels
// for each frame in animation
// this will affect how many images will
//be built for each animation
//the smaller the increment the smoother it is
//#define DEBUG
@implementation TiffManager
- init
{
char buf[MAXPATHLEN + 1];
buf[0] = (int)NULL;
[super init];
[self setHomeDirFile:buf]; //if there is a .Celestial folder in
//home directory - use it instead
[self setTiffDirectory :buf];
[self buildTiffStorage];
if (totalTiffCount < 1){ //no files in .Celestial folder
// get them from module folder
moduleDir = [[NXApp delegate] moduleDirectory:"StarShip"];
strcpy(buf, moduleDir);
strcat(buf,"/Celestial.bundle");
[self setTiffDirectory :buf];
[self buildTiffStorage];
}
else
printf("Using files in .Celestial folder\n");
tiffStorageIndex = 0;
animationIndex = 0;
numberProcessed = 0;
animFileIndex = 1;
maxAnimFiles = 0;
return self;
}
//looks in the tiffStorage and starts creating images one at a time
//and returns so that something else can be going on while this is
//happening - returns Done when they are created.
- (BOOL)createTiffs
{
char buf[MAXPATHLEN + 1];
char *imageName = 0;
char *animDirName = 0;
ImageStruct imageStruct;
int isSpin = 0;
int isAnim = 0;
int isMult = 0;
#ifdef DEBUG
NXRect DebugRect;
#endif
NXPoint bogusPoint = {0.0,0.0}; //composite image to create cache
NXRect bogusRect = {0.0,0.0,1.0,1.0}; //composite image to create cache
float increasePercent;
NXPoint offset;
NXPoint oldCenter;
NXPoint newCenter;
NXPoint newTrans;
float distance,origAngle,maxDiagonal;
// tiffStorageIndex = 0 to totalTiffCount-1
isSpin = ((ImageStruct *)[tiffStorage elementAt:
tiffStorageIndex])->isSpin;
isMult = ((ImageStruct *)[tiffStorage elementAt:
tiffStorageIndex])->isMult;
isAnim = ((ImageStruct *)[tiffStorage elementAt:
tiffStorageIndex])->isAnim;
maxAnimFiles = ((ImageStruct *)[tiffStorage elementAt:
tiffStorageIndex])->maxAnimFiles;
imageName = ((ImageStruct *)[tiffStorage elementAt:
tiffStorageIndex])->imageName;
animDirName = ((ImageStruct *)[tiffStorage elementAt:
tiffStorageIndex])->animDirName;
switch(animationIndex){
case 0: //create list - read in source Image
spinAdjustRect.origin.x = 0.0;
spinAdjustRect.origin.y = 0.0;
scaledImageRect.origin.x = 0.0;
scaledImageRect.origin.y = 0.0;
localImageList = [[List alloc] init];
if(isAnim){ // drop down another level
sprintf(buf,"%s/%s.anim/%s.%d.tiff",tiffDirectory, animDirName,
imageName,animFileIndex);
animFileIndex++;
if(animFileIndex > maxAnimFiles)
animFileIndex = 1;
}
else
sprintf(buf,"%s/%s.tiff",tiffDirectory,imageName);
sourceImage = [[NXBitmapImageRep alloc] initFromFile:buf];
if(sourceImage == nil){
printf("couldn't init NXBitmapImageRep from file %s\n",buf);
animationIndex = 0; //get next image if there is one
tiffStorageIndex++;
if(tiffStorageIndex > totalTiffCount)
tiffStorageIndex = 0;
numberProcessed++;
break;
}
else animationIndex++;
if(isSpin){
angle = 0.0;
angleInc = randBetween(5,10); // objects will spin
//at different speeds each time
}
break;
case 1: //create temp buffer size of original image unless spinning
// if spinning make buffer square
[sourceImage getSize: &sourceImageSize];
if(sourceImageSize.width > sourceImageSize.height){
widthIsSmaller = NO;
scaledImageRect.size.height = 1;
//get percentage that 1 pixel is
increasePercent = scaledImageRect.size.height /
sourceImageSize.height;
scaledImageRect.size.width = ceil(increasePercent *
sourceImageSize.width);
maxImageSize = (sourceImageSize.width > MAXIMAGESIZE) ?
MAXIMAGESIZE: sourceImageSize.width; // smallest number
}
else{
widthIsSmaller = YES;
scaledImageRect.size.width = 1;
//get percentage that 1 pixel is
increasePercent = scaledImageRect.size.width /
sourceImageSize.width;
scaledImageRect.size.height = ceil(increasePercent *
sourceImageSize.height);
maxImageSize = (sourceImageSize.height > MAXIMAGESIZE) ?
MAXIMAGESIZE: sourceImageSize.height; //smallest number
}
if(isSpin){ //use diagonal across original image to make a square
// big enough to handle the image rotating
maxDiagonal = sqrt((sourceImageSize.width *
sourceImageSize.width) +
(sourceImageSize.height * sourceImageSize.height));
spinAdjustRect.size.height = spinAdjustRect.size.width
= maxDiagonal;
//get center of the new buffer
spinCenter.x = spinAdjustRect.size.width / 2;
spinCenter.y = spinAdjustRect.size.height / 2;
buffer = [[NXImage allocFromZone:[self zone]]
initSize:&spinAdjustRect.size];
}
else{
buffer = [[NXImage allocFromZone:[self zone]]
initSize:&sourceImageSize];
}
animationIndex++;
break;
case 2: // scale and/or rotate - composite the image in buffer
// this will keep alpha info
// when you do the rotate, it rotates around origin
// have to do a translate to bring center of image
//back to the same place. drawIn method will do the
//scaling automatically
if([buffer lockFocus]){
if(isSpin){
//caculate the real size of the animation images
scaledDiagonal = sqrt((scaledImageRect.size.width *
scaledImageRect.size.width)
+ (scaledImageRect.size.height *
scaledImageRect.size.height));
spinScaledImageRect.size.width = scaledDiagonal;
spinScaledImageRect.size.height = scaledDiagonal;
//find the orgin of where the scaled image is in buffer
spinScaledImageRect.origin.x =(spinCenter.x -
(scaledDiagonal/2));
spinScaledImageRect.origin.y = (spinCenter.y -
(scaledDiagonal/2));
PSsetgray(0);// black out buffer
NXRectFill(&spinScaledImageRect);//black out part of buffer
oldCenter.x = scaledImageRect.size.width / 2;
oldCenter.y = scaledImageRect.size.height / 2;
origAngle = atan(oldCenter.y/oldCenter.x);
distance = sqrt((oldCenter.x * oldCenter.x) +
(oldCenter.y * oldCenter.y));
angle += angleInc; //increment the angle
// convert degrees to radians
newCenter.x = cos(origAngle + (angle/57.30)) * distance;
newCenter.y = sin(origAngle + (angle/57.30)) * distance;
newTrans.x = (oldCenter.x - newCenter.x);
newTrans.y = (oldCenter.y - newCenter.y);
//now adjust to center of square buffer
newTrans.x += (spinCenter.x - oldCenter.x);
newTrans.y += (spinCenter.y - oldCenter.y);
PStranslate(0.0 + newTrans.x,0.0 + newTrans.y);
PSrotate(angle);
if(![sourceImage drawIn:&scaledImageRect])
printf("resizing image didn't work\n");
[buffer unlockFocus];
}
else {
if(![sourceImage drawIn:&scaledImageRect])
printf("resizing image didn't work\n");
[buffer unlockFocus];
}
}
if(isAnim){
[sourceImage free];
}
animationIndex++;
break;
case 3: // create new image correct size
//build the image object with the actual image centered
//in a black rectangle 8 pixels bigger on all sides
// the stars have a max of width and height of 7
// and this guarantees that they will get blacked out
// as the image is moving
if(isSpin){
//calculate a square from the scaled image size
// using the diagonal across the scaled image
adjustedRect.origin.x = 0.0;
adjustedRect.origin.y = 0.0;
adjustedRect.size.width = scaledDiagonal+16;
adjustedRect.size.height = scaledDiagonal+16;
//create the actual image 16 pixels bigger
image = [[NXImage allocFromZone:[self zone]]
initSize:&adjustedRect.size];
//black it out
if([image lockFocus]){
PSsetgray(0);
NXRectFill(&adjustedRect); //black out new image
[image unlockFocus];
}
}
else{
adjustedRect.origin.x = 0.0;
adjustedRect.origin.y = 0.0;
adjustedRect.size.width = scaledImageRect.size.width+16;
adjustedRect.size.height = scaledImageRect.size.height+16;
//create the image
image = [[NXImage allocFromZone:[self zone]]
initSize:&adjustedRect.size];
if([image lockFocus]){
PSsetgray(0);
NXRectFill(&adjustedRect); //black out new image
[image unlockFocus];
}
}
animationIndex++;
break;
case 4: //composite into the image just created to get rid of alpha
//center in middle of slightly bigger black image if rotating
offset.x = 8.0;
offset.y = 8.0;
if([image lockFocus]){
if(isSpin){
[buffer composite:NX_SOVER fromRect:&spinScaledImageRect
toPoint:&offset];
}
else{
[buffer composite:NX_SOVER fromRect:&scaledImageRect
toPoint:&offset];
}
[image unlockFocus];
}
animationIndex++;
break;
case 5: //now do phony composite, to build
//offscreen cache - othewise a delay will happen
//when you composite the first one
#ifdef DEBUG
//special debug code to see actual images being generated
// set PSsetgray(1) on previous calls to see the buffers
PSsetgray(0);
bogusPoint.x = 250.0;
bogusPoint.y = 250.0;
DebugRect.origin.x = 0.0;
DebugRect.origin.y = 0.0;
[image getSize: &DebugRect.size];
[image composite:NX_SOVER fromRect:&DebugRect
toPoint:&bogusPoint];
bogusPoint.x = 50.0;
bogusPoint.y = 50.0;
[buffer getSize: &DebugRect.size];
[buffer composite:NX_SOVER fromRect:&DebugRect
toPoint:&bogusPoint];
if(isSpin){
PSmoveto(spinScaledImageRect.origin.x+50,
spinScaledImageRect.origin.y+50);
PSlineto(spinScaledImageRect.origin.x+50,
spinScaledImageRect.origin.y + spinScaledImageRect.size.height+50);
PSlineto(spinScaledImageRect.origin.x+50 + spinScaledImageRect.size.width,
spinScaledImageRect.origin.y + spinScaledImageRect.size.height+50);
PSlineto(spinScaledImageRect.origin.x + spinScaledImageRect.size.width+50,
spinScaledImageRect.origin.y+50);
PSlineto(spinScaledImageRect.origin.x+50,spinScaledImageRect.origin.y+50);
}
else {
PSmoveto(scaledImageRect.origin.x+50, scaledImageRect.origin.y+50);
PSlineto(scaledImageRect.origin.x+50, scaledImageRect.origin.y +
scaledImageRect.size.height+50);
PSlineto(scaledImageRect.origin.x+50 + scaledImageRect.size.width,
scaledImageRect.origin.y + scaledImageRect.size.height+50);
PSlineto(scaledImageRect.origin.x + scaledImageRect.size.width+50,
scaledImageRect.origin.y+50);
PSlineto(scaledImageRect.origin.x+50, scaledImageRect.origin.y+50);
}
PSstroke();
#else
[image composite:NX_DOVER fromRect:&bogusRect
toPoint:&bogusPoint];
#endif
[localImageList addObject:image]; //add to list
//calculate new size
if(widthIsSmaller){
scaledImageRect.size.width += SIZEINC;
scaledImageRect.size.width =
ceil(scaledImageRect.size.width);
scaledImageRect.size.height =
ceil((scaledImageRect.size.width /
sourceImageSize.width) * sourceImageSize.height);
}
else{
scaledImageRect.size.height += SIZEINC;
scaledImageRect.size.height =
ceil(scaledImageRect.size.height);
scaledImageRect.size.width =
ceil((scaledImageRect.size.height /
sourceImageSize.height) * sourceImageSize.width);
}
// if image is now bigger that max allowed size - exit on next pass
if (scaledImageRect.size.width <= maxImageSize &&
scaledImageRect.size.height <= maxImageSize){
animationIndex = 2;
if(isAnim){ // set source image to next one
sprintf(buf,"%s/%s.anim/%s.%d.tiff",
tiffDirectory, animDirName,imageName,animFileIndex);
animFileIndex++;
if(animFileIndex > maxAnimFiles)
animFileIndex = 1;
//create image for next pass if anim type
sourceImage = [[NXBitmapImageRep alloc] initFromFile:buf];
if(sourceImage == nil){//bad anim dir - go on to next image
printf("couldn't init image file %s\n",buf);
printf("skipping anim directory\n");
if([buffer free] != nil)
printf("buffer not freed\n");;
numberProcessed++;
tiffStorageIndex++;
if(tiffStorageIndex > totalTiffCount)
tiffStorageIndex = 0;
}
}
}
else{
animationIndex++;
}
break;
case 6: // finish image list
//printf("completing image # %d\n", tiffStorageIndex);
numberProcessed++;
if(!isAnim){
[sourceImage free];
}
if([buffer free] != nil)
printf("buffer not freed\n");
imageStruct.imageList = localImageList;
imageStruct.imageName = imageName;
imageStruct.isSpin = isSpin;
imageStruct.isMult = isMult;
imageStruct.isAnim = isAnim;
imageStruct.animDirName = animDirName;
imageStruct.maxAnimFiles = maxAnimFiles;
[tiffStorage replaceElementAt:(unsigned int)tiffStorageIndex
with:&imageStruct];
animationIndex = 0;
animFileIndex = 1;
tiffStorageIndex++;
if(tiffStorageIndex >= totalTiffCount)
tiffStorageIndex = 0;
break;
}
if(numberProcessed >= MAXANIMATIONS || numberProcessed >= totalTiffCount){
numberProcessed = 0;
return NO;
}
else{
return YES; //Tiffs still need to be built
}
}
- freeTiffs
{
// all the tiffs brought in
int ii;
List *imageList;
int count;
char *imageName = 0;
char *animDirName = 0;
ImageStruct imageStruct;
int isSpin = 0;
int isAnim = 0;
int isMult = 0;
for(ii=0; ii < (int)[tiffStorage count];ii++){
imageList = (List *)((ImageStruct *)[tiffStorage
elementAt:ii])->imageList;
if(imageList != nil){
count = [imageList count];
if(count){
[imageList freeObjects];
[imageList free];
//kind of ugly - all this to set the storage item
//imageStruct.imageList to nil - otherwise
// all other variables in storage record get wiped out
isSpin = ((ImageStruct *)[tiffStorage elementAt:
ii])->isSpin;
isMult = ((ImageStruct *)[tiffStorage elementAt:
ii])->isMult;
isAnim = ((ImageStruct *)[tiffStorage elementAt:
ii])->isAnim;
maxAnimFiles = ((ImageStruct *)[tiffStorage elementAt:
ii])->maxAnimFiles;
imageName = ((ImageStruct *)[tiffStorage elementAt:
ii])->imageName;
animDirName = ((ImageStruct *)[tiffStorage elementAt:
ii])->animDirName;
imageStruct.imageList = nil;
imageStruct.imageName = imageName;
imageStruct.isSpin = isSpin;
imageStruct.isMult = isMult;
imageStruct.isAnim = isAnim;
imageStruct.animDirName = animDirName;
imageStruct.maxAnimFiles = maxAnimFiles;
[tiffStorage replaceElementAt:(unsigned int)ii
with:&imageStruct];
}
}
}
return self;
}
// creates a tiff record in the tiffStorage for every tiff file encountered.
// the actual tiff lists are built in createTiffs
// looks in Celestial bundle or .Celestial directory in home directory
- buildTiffStorage
{
ImageStruct imageStruct;
tiffStorage = [[Storage allocFromZone:[self zone]] initCount:0
elementSize:sizeof(imageStruct) description:"{iiii@*}"];
totalTiffCount = [self searchDirectory]; //create list of filenames
return self;
}
- setTiffDirectory: (char *)directory
{
strcpy(tiffDirectory,directory);
return self;
}
- (BOOL)isOk:(char *)filename :(int *)isAnim :(int *)isMult :(int *)isSpin
//checks to make sure the filename is .tiff
//sets flags for rotate,anim and mult options
{
char *suffix;
*isSpin = 0;
*isMult = 0;
*isAnim = 0;
suffix = rindex(filename,'.');
if (suffix == 0)
return NO;
else if(strlen(suffix) != 5)
return NO;
else if(strncmp(suffix,".tiff",5) == 0){
*suffix = '\0'; /* strip tiff suffix */
if([self stringMatch:"mult" :filename])
*isMult = 1;
if([self stringMatch:"spin" :filename])
*isSpin = 1;
return YES;
}
else if(strncmp(suffix,".anim",5) == 0){
*suffix = '\0'; /* strip anim suffix */
*isAnim = 1;
if([self stringMatch:"mult" :filename])
*isMult = 1;
if([self stringMatch:"spin" :filename])
*isSpin = 1;
return YES;
}
else
return NO;
}
// look in the directory for all the tiff images
//if .anim directory encountered then get count and filename
// create a list of storage objects that will use them
- (int)searchDirectory
{
ImageStruct imageStruct;
char animDirectory[MAXPATHLEN + 1];
char filename[MAXPATHLEN + 1];
long basep;
char *buf;
struct direct *dp;
int cc, fd, fileCount = 0;
char dirbuf[8192];
int isAnim,isMult,isSpin,animCount;
if ((fd = open(tiffDirectory, O_RDONLY, 0644)) > 0) {
cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
while (cc) {
dp = (struct direct *)buf;
if ([self isOk:dp->d_name:&isAnim :&isMult :&isSpin]) {
imageStruct.isAnim = isAnim;
imageStruct.isMult = isMult;
imageStruct.isSpin = isSpin;
animCount = 0;
if(isAnim){
sprintf(animDirectory,"%s/%s.anim",
tiffDirectory,dp->d_name);
animCount = (int)[self isAnimOk:animDirectory :filename];
if(animCount > 0){
imageStruct.imageName = NXCopyStringBufferFromZone
(filename,[self zone]);
imageStruct.animDirName = NXCopyStringBufferFromZone
(dp->d_name,[self zone]);
imageStruct.imageList = NULL;
imageStruct.maxAnimFiles = animCount;
[tiffStorage addElement:&imageStruct];
fileCount++;
}
}
else {
imageStruct.imageName = NXCopyStringBufferFromZone(dp->d_name,
[self zone]);
imageStruct.maxAnimFiles = animCount;
imageStruct.imageList = NULL;
imageStruct.animDirName = NULL;
[tiffStorage addElement:&imageStruct];
fileCount++;
}
}
buf += dp->d_reclen;
if (buf >= dirbuf + cc) {
cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
}
}
close(fd);
}
return fileCount;
}
- (Storage *)returnTiffStorage
{
return tiffStorage;
}
- setHomeDirFile:(char *)path
{
char user[15];
char *getlogin();
char *ptr;
struct passwd *getpwuid(), *pwptr = NULL;
user[0] = 0;
if (((ptr = getlogin()) == NULL) || !user[0])
{
if ((pwptr = getpwuid(getuid())) == NULL)
sprintf(user, "%d", getuid());
else
strcpy(user, pwptr->pw_name);
}
if(user){
strcpy(path,pwptr->pw_dir);
strcat(path,"/.Celestial");
}
return self;
}
- (BOOL)stringMatch:(char *)string1 : (char *)string2
{
while(*string2 != '\0'){
if(strncasecmp(string1,string2,1) == 0){
if(strncasecmp(string1, string2, strlen(string1)) == 0){
return YES;
}
else{
string2++;
}
}
else
string2++;
}
return NO;
}
// look in the anim directory for all the tiff images
// it will return the name of the first file that is named filename.1.tiff
- (int)isAnimOk: (char *)directory :(char *)filename
{
// look in the anim directory for all the tiff images
// it will return the name of the file that is named filename.1.tiff
// otherwise return NULL
long basep;
char *buf;
struct direct *dp;
int cc = 0;
int fd = 0;
short found = 0;
int fileCount = 0;
char dirbuf[8192];
char *suffix = NULL;
if ((fd = open(directory, O_RDONLY, 0644)) > 0) {
cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
while (cc) {
dp = (struct direct *)buf;
suffix = rindex(dp->d_name,'.');
if(strncmp(suffix,".tiff",5) == 0){
if (!found && [self stringMatch:".1.tiff" :dp->d_name]){
found = 1; //if found don't look anymore
strncpy(filename,dp->d_name,
strlen(dp->d_name)-7);
filename[(strlen(dp->d_name)-7)] = '\0';
}
fileCount++;
}
buf += dp->d_reclen;
if (buf >= dirbuf + cc) {
cc = getdirentries(fd, (buf = dirbuf), 8192, &basep);
}
}
}
close(fd);
if(!found) // there was no file "file.1.tiff" in anim dir
fileCount = 0;
return fileCount;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.