質問

I'm struggling with the problem to draw an eps file on a NSView. When I first load the eps file from a file and draw it with drawInRect: the image is displayed correctly. However, the image will not be drawn when I load it from an archive file.

I've prepared a dirty small example that you can copy/paste and try out. Create a new Cocoa App project and add this to the delegate method.

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
  // Just a sample eps file
  NSURL *url = [NSURL URLWithString: @"http://embedded.eecs.berkeley.edu/concurrency/latex/figure.eps"];
  NSImage *epsImage = [[[NSImage alloc] initWithContentsOfURL: url] autorelease];

  // Encode data
  NSMutableData *mutableData = [[[NSMutableData alloc] init] autorelease];
  NSKeyedArchiver *coder = [[[NSKeyedArchiver alloc] initForWritingWithMutableData: mutableData] autorelease];
  [coder encodeObject: epsImage forKey: @"image"];
  [coder finishEncoding];
  NSString *dataFile = [@"~/Desktop/image.data" stringByExpandingTildeInPath];
  [mutableData writeToFile: dataFile atomically: YES];

  // Decode data
  NSData *data = [NSData dataWithContentsOfFile: dataFile];
  NSKeyedUnarchiver *decoder = [[NSKeyedUnarchiver alloc] initForReadingWithData: data];
  NSImage *loadedImage = [decoder decodeObjectForKey: @"image"];

  // Draw image
  NSRect rect;
  rect.origin = NSZeroPoint;
  rect.size = loadedImage.size;

  NSView *view = [[NSApp mainWindow] contentView];
  [view lockFocus];
  [loadedImage drawInRect: rect fromRect: rect operation: NSCompositeSourceOver fraction: 1.0];
  [view unlockFocus];
}

To prove that the first loaded image draws correctly just change the line [loadedImage drawInRect:...] to [epsImage drawInRect:...].

I'm using NSKeyedArchiver and NSKeyedUnarchiver here for simulating encodeWithCoder: and initWithCoder:. So please focus on the fact that NSImage with NSEPSImageRep representation, which does not contain a preview (from a resource fork?) and loaded purely as eps commands, is not drawn on a NSView correctly.

Any help is appreciated.

役に立ちましたか?

解決

Due to the way that cacheing works on NSImage, I've often found it more effective to actually grab the NSImageRep if I know what the type is.

In our code, we found that the most reliable way to save off images is in their original format, but that requires either saving off the data in its original format somewhere else, or requesting the data from the NSImageRep. Unfortunately, there's not a generic -(NSData*)data method of NSImageRep, so we ended up specifically checking for various types of NSImageRep and saving them off depending on what we knew them to be.

Fortunately, loading is simple, as NSImage::initWithData: will figure out the type based on the data.

Here's our long-standing code for doing this. Basically, it prefers PDF then EPS then it makes a TIFF of anything it doesn't understand.

+ (NSData*) dataWithImage:(NSImage*)image kindString:( NSString**)kindStringPtr
{
    if (!image)
        return nil;

    NSData *pdfData=nil, *newData=nil, *epsData=nil, *imageData=nil;;
    NSString *kindString=nil;
    NSArray *reps = [image representations];
    for (NSImageRep *rep in reps) {
        if ([rep isKindOfClass: [NSPDFImageRep class]]) {
            // we have a PDF, so save that
            pdfData = [(NSPDFImageRep*)rep PDFRepresentation];
            PDFDocument *doc = [[PDFDocument alloc] initWithData:pdfData];
            newData = [doc dataRepresentation];
            if (newData && ([newData length]<[pdfData length])) {
                pdfData = newData;
            }
            break;
        }
        if ([rep isKindOfClass: [NSEPSImageRep class]]) {
            epsData = [(NSEPSImageRep*)rep EPSRepresentation];
            break;
        }
    }

    if (pdfData) {
        imageData=pdfData;
        kindString= @"pdfImage";
    } else if (epsData) {
        imageData=epsData;
        kindString=@"epsImage";
    } else {
        // make a big copy
        NSBitmapImageRep *rep0 = [reps objectAtIndex:0];
        if ([rep0 isKindOfClass: [NSBitmapImageRep class]]) {
            [image setSize: NSMakeSize( [rep0 pixelsWide], [rep0 pixelsHigh])];
        }

        imageData = [image TIFFRepresentation];
        kindString=@"tiffImage";
    }

    if (kindStringPtr)
        *kindStringPtr=kindString;
    return imageData;
}

Once we have the NSData*, it can be saved in a keyed archive, written to disk or whatever.

On the way back in, load in the NSData* and then

NSImage *image = [[NSImage alloc] initWithData: savedData];

and you should be all set.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top