This is Gif.m in view mode; [Download] [Up]
/* File name: Gif.m Written by Georges CHAN Purpose: demonstrate how to use the GifDecode class with NXBitmapImageRep/NXImage as receiver. Since the purpose of this program is to show how to use the GifDecode class therefore, users may found that some of the techniques used here may not be the most efficient ones. Example showing on how to use the GifDecode class is mainly in the demo method. Copyright, All right reserved. Feel free to use or distribute this application. Date: July 92. Note: The author disclaims all warranties with regard to this software, including all implied warranties or merchantability, in no event shall the author be liable for any special, indirect or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortuous action, arising out of or in connection with the use of this software. GIF is the copyright property of CompuServe Inc., GIF (sm) is a service mark property of CompuServe Inc. */ /* The DEMOBITMAP definition tells the compiler to compile codes for demonstration with NXBitmapImageRep as a recipient of the images in the GIF file. If you want to run the demo with NXImage as recipient then simply comment the following def line */ #define DEMOBITMAP 1 /* Generated by Interface Builder */ #import "GifDecode.h" // lib for getting GIF files #import "Gif.h" // header file of example prog #import <appkit/NXBitmapImageRep.h> // lib for bitmaps #import <appkit/NXImage.h> // lib for images #import <string.h> // lib for string manipulations #import <libc.h> // lib for unix command, e.g. getwd() #import <appkit/Window.h> // lib for windows #import <appkit/OpenPanel.h> // lib for open panel #import <appkit/SavePanel.h> // lib for save panel #import <streams/streams.h> // lib for streams output #import <appkit/Application.h> // lib for application #import <appkit/tiff.h> // lib for tiff constant, e.g. NX_TIFF_COMPRESSION_LZW #import <appkit/View.h> // lib for view #import <dpsclient/wraps.h> // lib for displaying PS command #import <appkit/Matrix.h> // lib for matrix of button @implementation Gif /* * * demo method demonstrate how to use the GifDecode class, i.e. * how to load a series of bitmaps which are the decompressed * images obtained from a specified GIF file. * */ - demo:(char *) filename { id view, // view in a window to display images of a GIF file gif; // GIF object currently being read NXSize windowSize; // minimum size of the display window NXRect bounds; // bounds of the displayed window int counter, // loop counter noImage = 0; // number of images obtained from decompression of GIF file #ifndef DEMOBITMAP NXPoint place = {0., 0.}; // hold position to composite picture in demo window gif = [[GifDecode alloc] initFromFile :filename imageList :picture[winNum] maxiNo :MAXIPERGIF noOfFrame :&noImage winSize :&windowSize useOrCoord :useOrigin]; #else gif = [[GifDecode alloc] initFromFile :filename bitList :picture[winNum] maxiNo :MAXIPERGIF noOfFrame :&noImage winSize :&windowSize useOrCoord :useOrigin]; #endif if (gif == nil) // error in reading or decoding GIF file { if (!NXRunAlertPanel("WARNING", "ERROR OCURRED: do you still want to see it?", "YES", "NO", NULL)) return self; // return to editor without doing anything } // adjust origin of the display window so that the window will be visible if (winX + windowSize.width >= screamSize.width) winX = 100; if (winY + windowSize.height >= screamSize.height) winY = 150; if (useScreenSize) NXSetRect(&bounds, winX, winY,windowSize.width,windowSize.height); else { // use size of the image [picture[winNum][0] getSize:&windowSize]; NXSetRect(&bounds, winX, winY,windowSize.width,windowSize.height); } // allocate the display window win[winNum] = [Window newContent: &bounds style: NX_TITLEDSTYLE backing: NX_BUFFERED buttonMask: NX_CLOSEBUTTONMASK defer: NO]; view = [win[winNum] contentView]; [win[winNum] setTitle: filename]; // put file name as title of window [win[winNum] display]; [win[winNum] setDelegate:self]; [view lockFocus]; // clears the demo window [view getBounds: &bounds]; PSsetgray(NX_BLACK); NXRectFill(&bounds); [view display]; [win[winNum] orderFront:nil]; // move demo window up to front of screen for (counter = 0; counter < noImage; counter++) { // display picture #ifdef DEMOBITMAP [picture[winNum][counter] draw]; NXPing(); // flush display buffer #else [picture[winNum][counter] composite:command toPoint: &place]; NXPing(); // flush display buffer sleep(1); // composite is too fast! slow it down #endif [view display]; } [view unlockFocus]; cuNo[winNum] = noImage-1; // adjust origin position so that next time, pictures won't totally overlap winX += 50; winY += 50; noIm[winNum] = noImage; if (winNum+1 < MAXWIN) winNum++; return self; } #ifdef DEMOBITMAP /* disable the pop up list button for composite mode since using NXBitmapImageRep only. */ - setComposeBut:sender { return [sender setEnabled:NO]; } #endif /* * * init method will initialize the window. Initialization is * achieved by overriding the superclass's initFrame method * */ - init { [super init]; // run superclass init method from class object getwd(home); // get current working directory // first window is stuck at (100,200) winX = 100; winY = 150; // get limit of screen size [NXApp getScreenSize: &screamSize]; screamSize.width -= 100; screamSize.height -= 100; useOrigin = 1; useScreenSize = 1; command = NX_COPY; return self; } /* * * method for getting the name of the input data file through the use of the open panel * */ - getlfname:(char *) fname :(int *) goon { char **files, *typo[] = {"gif", "GIF", NULL}; // get only files with "map" extension id openwin = [OpenPanel new]; [openwin allowMultipleFiles:YES]; *goon = 1; if (![openwin runModalForDirectory:home file:NULL types:typo]) { // cancel action selected *goon = 0; return self; } *goon = 1; // yes! user selected an input file files = (char **) [openwin filenames]; strcpy(home, [openwin directory]); strcpy(fname, files[0]); return self; } /* * * method for performing a retrievement of a data file for mapping * */ - load:sender { char fname[FNAMELEN], // hold name of the input file full[MAXLEN]; // hold full path name + file name int goon; // flag for continue loading action [self getlfname:fname :&goon]; // get the name of the input file if (goon && strlen(fname)) { // have selected a file strcpy(full,home); // find the full path to the selected file strcat(full,"/"); strcat(full,fname); // stick the name of the file at the end [self demo: full]; } return self; } /* * * save method will save the content of a window to * a file by using TIFF format. * Note: ONLY save the LAST bitmap displayed in the * specified display window. * */ - save:sender { NXRect rect; // hold size of screen rectangle id bitmap, // hold bitmap of screen view; // view to save char fname[MAXLEN]; // hold name of the output file SavePanel *saveWin = [SavePanel new]; // open save panel [saveWin setRequiredFileType: "tiff"]; // add tiff extension to file name if (![saveWin runModalForDirectory: home file:NULL]) return self; // nothing selected strcpy(fname, [saveWin filename]); // stick the name of the file view = [[NXApp keyWindow] contentView]; [view lockFocus]; [view getBounds: &rect]; // get size of the map bitmap = [[NXBitmapImageRep alloc] initData:NULL fromRect:&rect]; // get bitmap [view unlockFocus]; if (bitmap) { // save bitmap as TIFF file in /tmp directory NXStream *s = NXOpenMemory(NULL, 0, NX_READWRITE); if (s) { // save bitmap screen to tiff file [bitmap writeTIFF:s usingCompression: NX_TIFF_COMPRESSION_LZW]; NXFlush(s); if (NXSaveToFile (s, fname)) fprintf(stderr, "Cannot save to %s\n", fname); NXCloseMemory (s, NX_FREEBUFFER); } [bitmap free]; } return self; } /* * * forward method will display the next picture (if exists) * of the GIF file in the key window. * */ - forward:sender { id view; // view of the key window int counter = 0; // window number of the key window #ifndef DEMOBITMAP NXPoint place = {0., 0.}; // hold position to composite picture in demo window NXRect bounds; // bounds of the displayed window #endif // find key window window number while (counter < MAXWIN && counter < winNum && [win[counter] isKeyWindow] == NO) counter++; if (counter >= MAXWIN || counter >= winNum) // can't find key window's number return self; if ([win[counter] isKeyWindow]) { // go forward #ifdef DEMOBITMAP if (noIm[counter] < 2) // only one picture return self; #else if (noIm[counter] < 2) // only one picture { // clears the demo window view = [win[counter] contentView]; [view lockFocus]; [view getBounds: &bounds]; PSsetgray(NX_BLACK); NXRectFill(&bounds); [picture[counter][0] composite:command toPoint: &place]; [view unlockFocus]; return [view display]; } #endif // show next picture view = [win[counter] contentView]; [view lockFocus]; if (cuNo[counter]+1 >= noIm[counter]) cuNo[counter] = 0; else cuNo[counter]++; #ifdef DEMOBITMAP [picture[counter][cuNo[counter]] draw]; #else [picture[counter][cuNo[counter]] composite:command toPoint: &place]; #endif [view display]; [view unlockFocus]; } return self; } /* * * backward method will display the previous picture (if exists) * of the GIF file in the key window. * */ - backward:sender { id view; int counter = 0; #ifndef DEMOBITMAP NXPoint place = {0., 0.}; // hold position to composite picture in demo window NXRect bounds; // bounds of the displayed window #endif // find key window window number while (counter < MAXWIN && counter < winNum && [win[counter] isKeyWindow] == NO) counter++; if (counter >= MAXWIN || counter >= winNum) // can't find key window's number return self; if ([win[counter] isKeyWindow]) { // go backward #ifdef DEMOBITMAP if (noIm[counter] < 2) // only one picture return self; #else if (noIm[counter] < 2) // only one picture { // clears the demo window view = [win[counter] contentView]; [view lockFocus]; [view getBounds: &bounds]; PSsetgray(NX_BLACK); NXRectFill(&bounds); [picture[counter][0] composite:command toPoint: &place]; [view unlockFocus]; return [view display]; } #endif // show previous picture view = [win[counter] contentView]; [view lockFocus]; if (cuNo[counter]-1 < 0) cuNo[counter] = noIm[counter]-1; else cuNo[counter]--; #ifdef DEMOBITMAP [picture[counter][cuNo[counter]] draw]; #else [picture[counter][cuNo[counter]] composite:command toPoint: &place]; #endif [view display]; [view unlockFocus]; } return self; } /* * * animate method will display all the pictures (if exist) * of the GIF file in the key window. * */ - animate:sender { id view; int counter = 0, i; #ifndef DEMOBITMAP NXPoint place = {0., 0.}; // hold position to composite picture in demo window NXRect bounds; // bounds of the displayed window #endif // find key window window number while (counter < MAXWIN && counter < winNum && [win[counter] isKeyWindow] == NO) counter++; if (counter >= MAXWIN || counter >= winNum) // can't find key window's number return self; if ([win[counter] isKeyWindow]) { // animate #ifdef DEMOBITMAP if (noIm[counter] < 2) // only one picture return self; #else if (noIm[counter] < 2) // only one picture { // clears the demo window view = [win[counter] contentView]; [view lockFocus]; [view getBounds: &bounds]; PSsetgray(NX_BLACK); NXRectFill(&bounds); [picture[counter][0] composite:command toPoint: &place]; [view unlockFocus]; return [view display]; } #endif // animate it! view = [win[counter] contentView]; [view lockFocus]; for (i = 0; i < noIm[counter]; i++) { // display picture #ifdef DEMOBITMAP [picture[counter][i] draw]; NXPing(); // flush display buffer #else [picture[counter][i] composite:command toPoint: &place]; NXPing(); // flush display buffer sleep(1); // composite is too fast, slow it down! #endif [view display]; } [view unlockFocus]; } return self; } /* * * changeOrigin will switch between forced origin mode (i.e. * origin of picture is set at (0,0)) and image origin * mode (i.e. origin is set the same as the ones described in the * picture). Note that the switch has effect only on the next * gif files opened. * */ - changeOrigin:sender { if (useOrigin) useOrigin = NO; else useOrigin = YES; return self; } /* changeMode method will change the new composite mode that the user has selected. All subsequent pictures will be composited with the new mode. */ - changeMode:sender { #ifndef DEMOBITMAP int option[] = { NX_COPY, NX_SOVER, NX_DOVER, NX_SIN, NX_DIN, NX_SOUT, NX_DOUT, NX_SATOP, NX_DATOP, NX_XOR, NX_PLUSD, NX_PLUSL }; command = option[[sender selectedRow]]; #endif return self; } /* windowWillClose method will released the window closed by the user. All NXBitmapImageRep (NXImage) are shifted down. */ - windowWillClose:sender { int counter = 0, i, j; // find key window window number while (counter < MAXWIN && counter < winNum && win[counter] != sender) counter++; if (counter >= MAXWIN || counter >= winNum) // can't find key window's number return self; if (sender == win[counter]) // check if the window to be closed is right one { // yes! shift array down for (i = 0; i < noIm[counter]; i++) [picture[counter][i] free]; for (i = counter; i < winNum; i++) { win[i] = win[i+1]; cuNo[i] = cuNo[i+1]; for (j = 0; j < noIm[i+1]; j++) picture[i][j] = picture[i+1][j]; noIm[i] = noIm[i+1]; } --winNum; } return self; // kill the window } /* changeSize will swicth between screen size (as described in the GIF file) and image size (the exact size as described in the GIF file). */ - changeSize:sender { useScreenSize = [sender selectedRow]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.