This is eTImageComponent.m in view mode; [Download] [Up]
/////////////////////////////////////////////////////////////////////////////// // FILENAME: eTImageComponent.m // SUMMARY: Implementation for a container of imageable data. // SUPERCLASS: Object // INTERFACE: None, but it "exports" eTImageComponentIcon. // PROTOCOLS: <ComponentData, // ETFDSupport,HTMDSupport,LaTeXSupport> // AUTHOR: Rohit Khare // COPYRIGHT: (c) 1994 California Institure of Technology, eText Project /////////////////////////////////////////////////////////////////////////////// // IMPLEMENTATION COMMENTS // The concept is that eText systems only access NXImages through this // component, which offers default services for image coercion and encoding. // // The UI has the responsibility for passing in the desired filespec. // Thus to keep a .pcx file as .pcx, pass in a complete path to the .pcx // on disk and eText will either reference it or copy it as-is into the // future (without filter-services, you will get eTImageComponentIcon.tiff) // If the file cannot be found (or isDirty), eText will generate a .tiff // and reset the names correctly. // // Since this component maps onto an IMG tag, the only format with // wide acceptance for IMG is GIF; so any non-gif file will be coerced. // Similarly, LaTeX only has provisions for eps, so it will, too. // // LaTeX and HTML representations will force the creation of local copies of // images (this can/will change in the future, cf HTML OODB ideas) // // shared images are currently envisioned for sysBitmaps like NXLinkButton // // Note on HTML calling convention: this object maps exclusively onto the // IMG tag, which can occur in the body of another anchor-like element. /////////////////////////////////////////////////////////////////////////////// // HISTORY // 01/22/95: Added call to handle caption strings. // 12/23/94: Patched to always reset etDoc on read/write // 07/19/94: Rearchitected // 07/14/94: Created. Aliases the NeXTSTEP NXImage API. /////////////////////////////////////////////////////////////////////////////// #import "eTImageComponent.h" #import "Kludges.subproj/EPSWriting.h" #import "Kludges.subproj/GIFWriting.h" #define _eTImageComponentVERSION 10 @implementation eTImageComponent // NXImage *theImage; // BOOL isShared; + newImageNamed:(const char *)newName { static id _imageComponentTable=nil; id newObj; id newImg; NXAtom theName; theName = NXUniqueString(newName); if (!_imageComponentTable) { _imageComponentTable = [[HashTable alloc] initKeyDesc:"%"]; } newObj = [_imageComponentTable valueForKey:theName]; if (!newObj) { if (newImg = [NXImage findImageNamed:theName]){ // system bitmap? [newImg setScalable:NO]; // this is a shared image! [newImg setDataRetained:YES]; // write TIFFs of sysBitmaps [newImg setEPSUsedOnResolutionMismatch:YES]; // Here's a hack for dealing with recalcitrant alpha channels: [newImg setBackgroundColor:NX_COLORWHITE]; } else { newImg = [[NXImage alloc] init]; if (![newImg useFromFile:theName]){ [newImg free]; newImg = [NXImage findImageNamed:"eTImageComponentIcon"]; } else { // WHAT Happens to naming if theName is an absolute path? [newImg setName:theName]; } } newObj = [[[eTImageComponent alloc] initInDoc:nil linked:NO] useImage:newImg name:theName path:"" shared:YES]; [_imageComponentTable insertKey:theName value:newObj]; } return newObj; } - theImage {return theImage;} - setComponentName:(const char*)newComponentName {return (isShared ? nil : [super setComponentName:newComponentName]);} - (BOOL)isShared {return isShared;} - (BOOL)isMutable {return (!isShared && [super isMutable]);} //////// begin semi-private API section /////// - initInDoc:newDoc linked: (BOOL) linked { [super initInDoc:newDoc linked:linked]; isShared = NO; shouldEdit = YES; theImage = nil; return self; } - free { if (isShared || [theImage name]) return self; // stop the free chain theImage = [theImage free]; return self = [super free]; } - useImage:(NXImage *)newImage name:(const char *) newComponentName path:(const char *) newCurrentPath shared:(BOOL) newShared; { theImage = newImage; componentName = NXUniqueString(newComponentName); currentPath = NXUniqueString(newCurrentPath); isShared = newShared; return self; } - readComponentFromPath:(const char *)newPath { if (newPath != currentPath) [super readComponentFromPath:newPath]; // now we have filled in componentName/currentPath // go out to disk and find the image theImage = [[NXImage alloc] init]; [theImage setScalable:YES]; [theImage setDataRetained:YES]; [theImage setEPSUsedOnResolutionMismatch:YES]; // Here's a hack for dealing with recalcitrant alpha channels: [theImage setBackgroundColor:NX_COLORWHITE]; if (![theImage loadFromFile:currentPath]){ char temp[MAXPATHLEN]; strcpy(temp, currentPath); strcat(temp, ".eps"); if (![theImage loadFromFile:temp]){ strcpy(temp, currentPath); strcat(temp, ".tiff"); if (![theImage loadFromFile:temp]){ strcpy(temp, currentPath); [theImage free]; // use eTImageComponentIcon.tiff to indicate an error theImage = [NXImage findImageNamed:"eTImageComponentIcon"]; isShared = YES; } } currentPath = NXUniqueString(temp); } return self; } - writeComponentToPath:(NXAtom)path inFormat:(int) theFormat { const char *tmp; char target[MAXPATHLEN]; if ((theFormat == ETFD_FMT) && (isShared || [theImage name])) return self; switch(theFormat) { case ETFD_FMT: // if it's not (a link) or (clean and the target is found), // if the (source is found and it's clean), copy // else write. if (isShared) break; // special case for etfds. sprintf(target,"%s/%s",path,componentName); if (!((isLinked) || ((!isDirty) && (!access(target,F_OK|R_OK))))){ if ((!isDirty) && *currentPath && (!access(currentPath, F_OK|R_OK))) { // copy char cmd[2*MAXPATHLEN]; sprintf(cmd,"cp -rp \"%s\" \"%s\"", currentPath, target); system(cmd); currentPath = NXUniqueString(target); } else { id repList; int i,j; BOOL foundEPS=NO; NXStream *stream; // choose format repList = [theImage representationList]; i = [repList count]; for(j=0; ((j<i) && !foundEPS); j++){ if ([[repList objectAt:j] isKindOf:[NXEPSImageRep class]]) foundEPS = YES; } stream = NXOpenMemory(NULL, 0, NX_READWRITE); if (foundEPS) { [theImage writeEPS:stream]; if (!rindex(target, '.') || strcasecmp(".eps", rindex(target, '.'))) strcat(target, ".eps"); } else { [theImage writeTIFF:stream allRepresentations:YES]; if (!rindex(target, '.') || strncasecmp(".tif", rindex(target, '.'),3)) strcat(target, ".tiff"); } NXSaveToFile(stream, target); NXCloseMemory(stream, NX_FREEBUFFER); currentPath = NXUniqueString(target); componentName = NXUniqueString(rindex(target,'/')+1); } isDirty=NO; } [etDoc registerComponent:componentName]; break; case HTMD_FMT: // Always is a gif. If it doesn't exist, copy a .gif or create one. if (componentName) tmp = componentName; else if ([theImage name]) tmp = [theImage name]; else tmp = [[self class] name]; sprintf(target,"%s/%s",path,tmp); if(!rindex(target, '.') || strcasecmp(".gif", rindex(target, '.'))) strcat(target, ".gif"); if (access(target,F_OK|R_OK) || isDirty) { // if currentPath is a gif, copy. if (rindex(currentPath, '.') && (!strcasecmp(".gif", rindex(currentPath, '.'))) && (!access(currentPath,F_OK|R_OK))) { char cmd[2*MAXPATHLEN]; sprintf(cmd,"cp -rp \"%s\" \"%s\"", currentPath, target); system(cmd); } else { [theImage writeGIFtoPath:target]; } } [etDoc registerComponent:(rindex(target,'/')+1)]; break; case TeXD_FMT: // Always is an eps. If it doesn't exist, copy a .eps or create one. if (componentName) tmp = componentName; else if ([theImage name]) tmp = [theImage name]; else tmp = [[self class] name]; sprintf(target,"%s/%s",path,tmp); if (!rindex(target, '.') || strcasecmp(".eps", rindex(target, '.'))) strcat(target, ".eps"); if (access(target,F_OK|R_OK) || isDirty) { // if currentPath is an eps, copy. if ((rindex(currentPath, '.')) && (!strcasecmp(".eps", rindex(currentPath, '.'))) && (!access(currentPath,F_OK|R_OK))) { char cmd[2*MAXPATHLEN]; sprintf(cmd,"cp -rp \"%s\" \"%s\"", currentPath, target); system(cmd); } else { NXStream *stream = NXOpenMemory(NULL, 0, NX_WRITEONLY); [theImage writeEPS:stream]; NXSaveToFile(stream, target); NXCloseMemory(stream, NX_FREEBUFFER); } } [etDoc registerComponent:(rindex(target,'/')+1)]; break; } return self; } - writeComponentToPboard:thePboard { // I don't know why yet, but I want to defeat dragging of shared images return (isShared ? nil : [super writeComponentToPboard:thePboard]); } - addToPboard:pboard { id repList; int i,j; BOOL foundEPS=NO; NXStream *stream; // we can let people copy them, though.??? if (!theImage) return nil; // choose format repList = [theImage representationList]; i = [repList count]; for(j=0; ((j<i) && !foundEPS); j++){ if ([[repList objectAt:j] isKindOf:[NXEPSImageRep class]]) foundEPS = YES; } stream = NXOpenMemory(NULL, 0, NX_READWRITE); if (foundEPS) { [theImage writeEPS:stream]; [pboard addTypes:&NXPostScriptPboardType num:1 owner:nil]; [pboard writeType:NXPostScriptPboardType fromStream:stream]; } else { [theImage writeTIFF:stream allRepresentations:YES]; [pboard addTypes:&NXTIFFPboardType num:1 owner:nil]; [pboard writeType:NXTIFFPboardType fromStream:stream]; } NXCloseMemory(stream, NX_FREEBUFFER); return self; } - readComponentFromPboard:thePboard { [super readComponentFromPboard:thePboard]; // ok, so now we have a quasi-valid entry in currentPath // If the image can init from thePboard, go right ahead. theImage = [[NXImage alloc] init]; [theImage setScalable:YES]; [theImage setDataRetained:YES]; [theImage setEPSUsedOnResolutionMismatch:YES]; // Here's a hack for dealing with recalcitrant alpha channels: [theImage setBackgroundColor:NX_COLORWHITE]; if ([NXImage canInitFromPasteboard:thePboard]) { // Patch for recalcitrant f*king appkit if([NXEPSImageRep canInitFromPasteboard:thePboard]) { id epsRep = [[NXEPSImageRep alloc] initFromPasteboard:thePboard]; [theImage useRepresentation:epsRep]; } else theImage = [theImage initFromPasteboard:thePboard]; if (!theImage){ theImage = [NXImage findImageNamed:"eTImageComponentIcon"]; isShared = YES; } // special case: If we paste raw image data and there's no path, // componentName is currently "Untitled-%d"; we need to cat an ext. // we should look at how this whole schmeer works/fails with RIBs. if (!(currentPath && *currentPath)) { char tmp[MAXPATHLEN]; strcpy(tmp, componentName); if([thePboard findAvailableTypeFrom:&NXPostScriptPboardType num:1]) strcat(tmp, ".eps"); else if([thePboard findAvailableTypeFrom:&N3DRIBPboardType num:1]) strcat(tmp, ".rib"); else strcat(tmp, ".tiff"); componentName = NXUniqueString(tmp); } } else if (currentPath && *currentPath) { if (![theImage loadFromFile:currentPath]){ [theImage free]; theImage = [NXImage findImageNamed:"eTImageComponentIcon"]; isShared = YES; } } else { theImage = [NXImage findImageNamed:"eTImageComponentIcon"]; isShared = YES; } return self; } - readRichText:(NXStream *)stream forView:view { int i; id temp; temp = [view etDoc]; if (temp && [temp respondsTo:@selector(registerComponent:)]) etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23 NXScanf(stream, "%d ", &i); if (i != _eTImageComponentVERSION) { // bad version block. NXLogError("eTImageComponent found unparseable version %d at position %d", i, NXTell(stream)); return nil; } NXScanf(stream, "%c ", &isShared); isShared -= 'A'; [super readRichText:stream forView:view]; if (isShared){ // we have a real problem here: we need to return the "uniq"d instance! id retval = [eTImageComponent newImageNamed:componentName]; [self free]; return retval; } if (!isLinked) { // derive a fresh currentPath. try to load. char buf[MAXPATHLEN]; sprintf(buf, "%s/%s",[[etDoc docInfo] docPath], componentName); currentPath = NXUniqueString(buf); } [self readComponentFromPath:currentPath]; return self; } - writeRichText:(NXStream *)stream forView:view { BOOL fakeShared; id temp; temp = [view etDoc]; if (temp && [temp respondsTo:@selector(registerComponent:)]) etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23 // this fixes a subtle bug related to images we can't locate at // read-time and are assigned the eTImageComponentIcon by default // (and thus set isShared) -- on reopen, it calls +newImageNamed with // the old componentName fakeShared = isShared; if (([theImage name] == NXUniqueString("eTImageComponentIcon")) && strcmp([theImage name], componentName)) fakeShared = NO; NXPrintf(stream, "%d %c ", _eTImageComponentVERSION, fakeShared+'A'); [super writeRichText:stream forView:view]; return self; } - writeHTML:(NXStream *)stream forView:view { return [self writeHTML:(NXStream *)stream forView:view withCaption:NULL];} - writeHTML:(NXStream *)stream forView:view withCaption:(NXAtom)caption { const char *tmp; id temp; temp = [view etDoc]; if (temp && [temp respondsTo:@selector(registerComponent:)]) etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23 if (componentName) tmp = componentName; else if ([theImage name]) tmp = [theImage name]; else tmp = [[self class] name]; NXPrintf(stream, "<IMG SRC=\"%s%s\" ALT=\"%v\">", tmp, ((!rindex(tmp, '.') || strcasecmp(".gif", rindex(tmp, '.')))?".gif":""), (caption && *caption) ? caption : tmp); return self; } - writeLaTeX:(NXStream *)stream forView:view { const char *tmp; id temp; temp = [view etDoc]; if (temp && [temp respondsTo:@selector(registerComponent:)]) etDoc = temp; // Always reset if possible; bugfix for shared images, 12/23 if (componentName) tmp = componentName; else if ([theImage name]) tmp = [theImage name]; else tmp = [[self class] name]; NXPrintf(stream, "\n\\centerline{\\epsffile{%s%s}}\n",tmp, ((!rindex(tmp, '.') || strcasecmp(".eps", rindex(tmp, '.')))?".eps":"")); return self; } // VERY PRIVATE API - setImage:newImg {theImage = newImg; return self;} - setShared:(BOOL)newState {isShared = newState; return self;} - registerError { theImage = [NXImage findImageNamed:"eTImageComponentIcon"]; isShared = YES; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.