[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 %@\n 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 -----------------------------
- Problem with image scaling with back-art,
Tima Vaisburd <=