discuss-gnustep
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Problem with image scaling with back-art


From: Tima Vaisburd
Subject: Problem with image scaling with back-art
Date: Mon, 22 Sep 2003 01:43:15 -0700
User-agent: KMail/1.4.3

Hello everybody,

After making some progress with PhotoClip application I'm stuck with something 
that looks to me like a bug in back-art.

I have to use back-art since back-xlib does not currently support rotation,
and I like back-art for some other reasons, too. However, with back-art
I cannot reliably show a scaled and clipped portion of an image.

I try to draw into small destination image from a source image of a larger
size applying the scaling transformation. The transformed source image is 
still bigger than the destination image and I expect the destination to cut 
off the pieces that fall outside.

Here is the code (rotation part does not contribute to the problem and has 
been removed):

// Category
@implementation NSImage (PhotoClip)

- (NSImage *) imageFromRect: (NSRect) rect scaledBy: (float) scale
{
    // Create nesessary transformation
    NSAffineTransform * xform = [NSAffineTransform transform];
    [xform scaleBy: scale];

    NSSize canvas_size = [xform transformSize: rect.size];

    // Translate reference frame to map rectangle 'rect' into rectangle
    // (0, 0, canvas_size.width, canvas_size.height)
    
    // In the case of no rotation we just need to map the transformed origin
    // of the rectangle to the point (0, 0).
    
    NSPoint transformed_origin = [xform transformPoint: rect.origin];
    [xform translateXBy: -transformed_origin.x
                    yBy: -transformed_origin.y];

    // Create canvas to draw upon
    NSImage * canvas = [[NSImage alloc] initWithSize: canvas_size];
    [canvas lockFocus];

    // apply transform
    [xform concat];
    
    // Get NSImageRep of image
    NSImageRep * rep = [self bestRepresentationForDevice: nil];

    // draw the rep onto canvas
    [rep drawAtPoint: NSZeroPoint];
    
    [canvas unlockFocus];
    return AUTORELEASE(canvas);
}

@end // implementation NSImage (PhotoClip)

My first question is whether this approach is semantically correct,
i.e. is this supposed to work?

It seems to work fine with xlib, but with back-art I often get garbage in the 
scale range 0.5 < scale < 1.0 if the image to clip from is large enough.
For instance, the following call produced garbage for 2272 x 1704 source
image:

NSImage * clipped =
    [image imageFromRect: NSMakeRect(502, 369, 1167, 937) scaledBy: 0.655];

Do you have any ideas what could it be?
My system is make/base 1.7.3, gui/back 0.8.9, libwraster, gcc 3.2,
Mandrake 9.0.

I've prepared a test case, and since I cannot contact my 0-cost web
hosting site ;( I'm attaching it right here. You need jpeg image 2272x1704
in the file "testimg.jpg".


Cheers,
Tima.

----------------------------- begin -----------------------------------------
#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h>

// Method -imageFromRect:scaledBy: that is being tested

@interface NSImage (MyTest)
- (NSImage *) imageFromRect: (NSRect) rect scaledBy: (float) scale;
@end

@implementation NSImage (MyTest)

- (NSImage *) imageFromRect: (NSRect) rect
                   scaledBy: (float) scale
{
    NSLog(@"imageFromRect:\n  address@hidden  scaledBy:%.3f\n",
          NSStringFromRect(rect), scale);

    // Create nesessary transformation
    NSAffineTransform * xform = [NSAffineTransform transform];
    [xform scaleBy: scale];

    NSSize canvas_size = [xform transformSize: rect.size];

    // Translate reference frame to map rectangle 'rect' into rectangle
    // (0, 0, canvas_size.width, canvas_size.height)
    
    // In the case of no rotation we just need to map the transformed origin
    // of the rectangle to the point (0, 0).
    
    NSPoint transformed_origin = [xform transformPoint: rect.origin];
    [xform translateXBy: -transformed_origin.x
                    yBy: -transformed_origin.y];

    // Create canvas to draw upon
    NSImage * canvas = [[NSImage alloc] initWithSize: canvas_size];
    [canvas lockFocus];

    // apply transform
    [xform concat];
    
    // Get NSImageRep of image
    NSImageRep * rep = [self bestRepresentationForDevice: nil];

    // draw the rep onto canvas
    [rep drawAtPoint: NSZeroPoint];
    
    [canvas unlockFocus];
    return AUTORELEASE(canvas);
}

@end


// Call this method in [NSView -drawRect]

@interface MyView : NSView
- (void) drawRect: (NSRect) rect;
@end

@implementation MyView

- (void) drawRect: (NSRect) rect
{
    NSString * fileName = @"testimg.jpg";

    // original size of testimg.jpg
    // NSRect clip_rect = NSMakeRect(0, 0, 2272, 1704);
    NSRect clip_rect = NSMakeRect(502, 369, 1167, 937);

    // float scale = 0.5;   // ok
    float scale = 0.655; // garbage
    // float scale = 0.998; // garbage
    // float scale = 1.0;   // ok
    // float scale = 1.001; // garbage
        
    NSImage * image = [[NSImage alloc] initWithContentsOfFile: fileName];
    if ( image == nil )
    {
        NSLog(@"can't load file '%@'\n", fileName);
        return;
    }

    NSImage * clipping = [image imageFromRect: clip_rect scaledBy: scale];

    NSPoint origin = NSMakePoint(20, 20);
    [clipping compositeToPoint: origin operation: NSCompositeCopy];

    RELEASE(image);
}

@end

// ---------- Glue it together is a standard way ---------------------

@interface MyDelegate : NSObject
{
    NSWindow * my_window;
}

- (void) dealloc;
- (void) createWindow;
- (void) applicationWillFinishLaunching: (NSNotification *)not;
- (void) applicationDidFinishLaunching: (NSNotification *)not;
- (BOOL) applicationShouldTerminateAfterLastWindowClosed: (id)sender;
@end


@implementation MyDelegate : NSObject 

- (void) dealloc
{
    RELEASE(my_window);
}

- (void) createWindow
{
    // Determine good window size.
    NSSize screenSize = [[NSScreen mainScreen] frame].size;
    NSRect rect = NSMakeRect(0,0,
                             screenSize.width * 4./5.,
                             screenSize.height * 4./5.);

    unsigned int styleMask = NSTitledWindowMask
        | NSClosableWindowMask
        | NSMiniaturizableWindowMask
        | NSResizableWindowMask;


    my_window = [[NSWindow alloc] initWithContentRect: rect
                                  styleMask: styleMask
                                  backing: NSBackingStoreRetained
                                  defer: YES];
    [my_window setTitle: @"Test -imageFromRect:scaledBy:"];

    [my_window setContentView: [[MyView alloc] initWithFrame: rect]];
}


- (void) applicationWillFinishLaunching: (NSNotification *)not
{
    [self createWindow];
}

- (void) applicationDidFinishLaunching: (NSNotification *)not
{
    [my_window makeKeyAndOrderFront: nil];

}

- (BOOL) applicationShouldTerminateAfterLastWindowClosed: (id)sender
{
    return YES;
}

@end

int main (int argc, const char **argv)
{
    [NSApplication sharedApplication];
    [NSApp setDelegate: [MyDelegate new]];

    return NSApplicationMain (argc, argv);
}
----------------------- end -----------------------------





reply via email to

[Prev in Thread] Current Thread [Next in Thread]