• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Rotating an image
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Rotating an image


  • Subject: Re: Rotating an image
  • From: Scott Thompson <email@hidden>
  • Date: Fri, 5 Oct 2007 09:14:08 -0500

In your posts, and in your code, you seem to be struggling with the drawing model. I don't want to sound like a commercial, but I would like to suggest two books on Quartz 2D that may help you come to grips with the graphics model and may help you understand how to use things like affine transforms. The first book is one that I wrote:

http://www.amazon.com/Quartz-2D-Graphics-Mac-Developers/dp/0321336631

And the second is an excellent book by David Gelphman, an member of the the Quartz 2D engineering team:

http://www.amazon.com/Programming-Quartz-Graphics-Kaufmann-Computer/dp/0123694736

Either of which should help you come to grips with the drawing model and how it works. I don't have it at my fingertips, but I suspect that David's book would cover the Cocoa wrappers to Quartz 2D more thoroughly than my own does. His book is much better as reference material than my own. In contrast, my book is intended to be a slow and gentle introduction to the drawing model that some people find helpful when they are first starting out (or so I've been told).

Ok, I can rotate the view of an image easily by setting the rotation of the NSImageView. but I need to be able to actually rotate the image in the view and then adjust the size of the view and redisplay.

What do you mean by "adjust the size of the view and redisplay". How are you trying to adjust the view's size? Are you trying to make the view "just fit" the rotated image?


I thought that this would be done by NSBezierPath and NSAffineTransform. I still think this is the case but my code only produces either completely blank images OR completely black images or an image with a black rectangle offset to the right by some number of pixels or another. I've spent the past two hours on the developer site and in google but the answer has not been apparent to me. Below is the flawed code. I have subclassed NSImage view and added this code to the subclass:

-(NSImage*)rotateImage:(float)degrees
{
NSRect sourceImageRect = [[self cell] rectCoveredByImageInBounds: [self bounds]];

The first odd thing I note about your code is that you are using "rectCoveredByImageInBounds" to determine the size of the image. This is an unusual way to obtain the bounds of an image. It would be very specific to the context that the view is being drawn in and would not take into account the actual image's dimensions. The image has it's own size independent of how large it appears on the display and if you want to rotate the original image you would be better served by using that size rather than the size at which it is draw in the user's window.


If I were to write this code, I might write it as:

NSSize imageSize = [[self image] size];
NSRect sourceImageRect = NSMakeRect(0, 0, imageSize.width, imageSize.height);


that way you are manipulating the actual size of the image, not just how the image appears in the current view. This is a very important distinction.

NSAffineTransform * xform = [NSAffineTransform transform];
NSBezierPath * xformedPath = [NSBezierPath bezierPathWithRect:sourceImageRect];
[xform rotateByDegrees: degrees];
xformedPath = [xform transformBezierPath:[self imagePath]];
NSRect newRect =[xformedPath bounds];

There's not really a good reason to construct a bezier path at this point. All you really want to know is how big the image will be after it is rotated. You could get that information from the transformSize method on the affine transform.


This brings up the point that (at least at this point) you don't really even need to know the "sourceImageRect". You could probably get by with the "imageSize" above. There is not really a good reason to construct a rect :-)

Another interesting thing to note about your code here is that you are calculating the rotation as if you were rotating the image around it's bottom, left corner. That is fine for this rotation because you are only interested in calculating the size of the resulting image. However, when you want to draw the image actually rotated, my guess would be that you want the image rotated about it's center. To do that, you are going to have to move the image so that it's center corresponds with the origin, rotate the image, then put the image back where you found it. This is Computer Graphics 101 type stuff for using Affine Transformations so I encourage you to look on the net for resources to help you with that.

NSImage * newImage = [[NSImage alloc]initWithSize:newRect.size];
[newImage lockFocus];
[[NSColor blackColor] set];
[xformedPath fill];
[[self image] drawInRect:newRect fromRect:sourceImageRect operation:NSCompositeSourceIn fraction:1.0];

Here you are looking to draw the new image, but you haven't done anything to take the rotation angle you'd like into account. Your xFormedPath is rotated so it would probably draw something vaguely diamond-shaped (instead of filling the entire image in black). The new image you draw is basically axis aligned so it's not going to draw as rotated at all. This is where you're going to have to use your Computer Graphics 101 transformation discussed above. You want to move the origin of the current context to the center of the new image, rotate user space, then draw the original image centered around the origin.


Your choice of a composite operation here seems unusual to me too. I would expect that you could leave off the black rectangle and just draw the original image using something like SourceCopy mode. But I'm not sure what effect you might be trying to achieve.

	[newImage unlockFocus];
	return newImage;
}


Finally, I have a stylistic comment. Personally, I would not create a subclass of NSImageView to contain this method. This method, to me, feels more like something that should be the responsibility of a controller and not a view. However, keep in mind that I have not seen your code and don't know the full context. Take that suggestion with a grain of salt and do the right thing for your situation :-)

Scott

_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden


References: 
 >Rotating an image (From: Development <email@hidden>)

  • Prev by Date: Re: multiple methods named 'xxx' found.
  • Next by Date: Re: multiple methods named 'xxx' found.
  • Previous by thread: Re: Rotating an image
  • Next by thread: Re: Rotating an image
  • Index(es):
    • Date
    • Thread