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.