Rotate NSImage in an NSImageView

I didn’t want to half-implement the new tab feature in Slider – I want people to have almost as much control as if they were coding the site by hand.

This has meant I’ve had to rethink Slider’s UI many times, and I’ve had (re: couldn’t face shipping without) to implement many small features that I feel are required, from a usability standpoint.

When I decided that the user may choose to place tabs in 12 different positions, I needed to consider how this would effect the arrows and sliding animations. I came to the conclusion that if the user elects to place the tabs on the top or bottom, the arrows will be on the left and right, with the animation going right/left. If the user chooses to place tabs on the left or right, the arrows will be positioned on the top and bottom, with the animation going up/down.

Pictures make it easier:

tab_position

tab_position_1

As soon as I implemented this I realised how much of a pain it would be to copy out the arrow images, rotate them in an external program, then copy them back in. So I put some buttons next to the arrow image wells that allow the user to rotate the arrows within Slider itself.

Here is the code I used to rotate the images (thanks to Jerry Krinock and Steve Christensen and for posting this solution to the Cocoa-dev list):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#import <Cocoa/Cocoa.h>
 
@interface NSImage (Transform)
 
 
/*!
 @brief    Rotates an image around its center by a given
 angle in degrees and returns the new image.
 
 @details  The width and height of the returned image are,
 respectively, the height and width of the receiver.
 
 I have not yet tested this with a non-square image.
 
authors: Jerry Krinock and Steve Christensen
 */
- (NSImage*)imageRotatedByDegrees:(CGFloat)degrees ;
 
@end
 
#import "NSImage+Transform.h"
 
@implementation NSImage (Transform)
 
 
- (NSImage*)imageRotatedByDegrees:(CGFloat)degrees {
 
	// calculate the bounds for the rotated image
    NSRect imageBounds = {NSZeroPoint, [self size]};
 
	NSBezierPath* boundsPath = [NSBezierPath bezierPathWithRect:imageBounds];
 
    NSAffineTransform* transform = [NSAffineTransform transform];
 
    [transform rotateByDegrees:degrees];
    [boundsPath transformUsingAffineTransform:transform];
 
    NSRect rotatedBounds = {NSZeroPoint, [boundsPath bounds].size};
 
	NSImage* rotatedImage = [[NSImage alloc] initWithSize:rotatedBounds.size];
 
    // center the image within the rotated bounds
 
	imageBounds.origin.x = NSMidX(rotatedBounds) - (NSWidth (imageBounds) / 2); imageBounds.origin.y = NSMidY(rotatedBounds) - (NSHeight (imageBounds) / 2);
 
    // set up the rotation transform
    transform = [NSAffineTransform transform];
 
	[transform translateXBy:+(NSWidth(rotatedBounds) / 2) yBy:+ (NSHeight(rotatedBounds) / 2)];
 
    [transform rotateByDegrees:degrees];
 
	[transform translateXBy:-(NSWidth(rotatedBounds) / 2) yBy:- (NSHeight(rotatedBounds) / 2)];
 
    // draw the original image, rotated, into the new image
    [rotatedImage lockFocus];
    [transform concat];
 
	[self drawInRect:imageBounds fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0] ;
 
    [rotatedImage unlockFocus];
 
    return [rotatedImage autorelease];	
 
}
@end

I had to change (from/to):

NSImage* rotatedImage = [[[NSImage alloc] initWithSize:rotatedBounds.size] autorelease];
 NSImage* rotatedImage = [[NSImage alloc] initWithSize:rotatedBounds.size];
return rotatedImage;
return [rotatedImage autorelease];
[transform set];
[transform concat];

For it to work flawlessly with Slider.

Thanks guys!

Like this post? Move it on along with:

email Email | delicious delicious | digg Digg | Tweet this post Tweet | reddit Reddit | newsvine Newsvine | furl Furl | google Google | StumbleUpon Stumble | Hao Hao HaoHao


Trackback:

Comments: 0 | Comments Feed

Scroll to post title

No commentsTrackback

Tile an NSImage Within an NSBezierPath

Another snippet I had to write during the great Slider rebuild.

I needed to be able to take an NSImage supplied by the user and tile it within an NSBezierPath defined by more user-set values.

The below example uses a rounded rectangle.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
NSBitmapImageRep *theImage = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:imageSize.width pixelsHigh:imageSize.height
 bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO
 colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:0 bitsPerPixel:0];
 
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:theImage]];
 
//bgImage can be any NSImage
NSColor *c = [NSColor colorWithPatternImage:bgImage];
[c set];
[path appendBezierPathWithRoundedRect:NSMakeRect(0, 0, imageSize.width, imageSize.height) xRadius:10.0 yRadius:10.0];
[path fill];
 
[NSGraphicsContext restoreGraphicsState];

Like this post? Move it on along with:

email Email | delicious delicious | digg Digg | Tweet this post Tweet | reddit Reddit | newsvine Newsvine | furl Furl | google Google | StumbleUpon Stumble | Hao Hao HaoHao


Trackback:

Comments: 0 | Comments Feed

Scroll to post title

No commentsTrackback

Fancy Footer Update

I’ve updated the Fancy Footer snippet, now Trackbacks/Pingbacks will be able to find your posts – the previous version’s implementation was … lacking.

The previous snippet used the post permalink as both the permalink and the path – the Trackback/Pingback system didn’t like “http://“ being included in the path attribute.

I was afraid that I wouldn’t be able to find a solution that allowed us to have Trackback/Pingback support and keep our existing comments.

I am glad to say that my fears were unfounded, and I managed to come up with a solution. The snippet now parses out the “http://domain.com” part of the permalink, and uses that for the path attribute for the widgets. Happily, JS-Kit must do a similar thing, as it hasn’t messed up my comments (the path attribute is what JS-Kit uses to determine what page to display which comments).

The snippet may be downloaded here. To learn how to use this snippet, read Fancy Footer – Usage and Tips.

Like this post? Move it on along with:

email Email | delicious delicious | digg Digg | Tweet this post Tweet | reddit Reddit | newsvine Newsvine | furl Furl | google Google | StumbleUpon Stumble | Hao Hao HaoHao


Trackback:

Comments: 0 | Comments Feed

Scroll to post title

No commentsTrackback

JS-Kit Comments + Greybox on Any Page

I’ve been using JS-Kit for comments for a long time, and I’ve been extremely impressed with the quality of their service.

They’ve recently acquired Haloscan, which is great – I dropped Haloscan in favour of JS-Kit some time ago, as I didn’t like the lack of control I felt I had over my comments. I haven’t looked back.

A few weeks ago I was showing my site to a fellow student, when she asked me why people were unable to leave comments on my photo pages. I couldn’t think of a reason, so as soon as I got home I set about fixing this lack.

After thinking about the problem for a short time, I realised that I didn’t want comments to be visible on the page in case one set of photos became wildly popular (yeah, right); which would result in a page of comments with a few photos, instead of a page of photos with maybe one or two comments. For some reason, Greybox popped into my head, and wouldn’t leave. A few hours later, this happened: Hangzhou Day 1.

If you like the effect, read on. Below is a short tutorial explaining how it was accomplished.

1) You must first have Greybox integrated with your site. Jan Erik Moström has written a tutorial explaining how to do this: RapidWeaver – using Greybox in a theme.

When you’re done with that (please make a test page to verify Greybox is working), head over to Code of Interest and download the Friendly Comments snippet.

Friendly Comment Snippet’s User Rating:

2) Open your RW project, select/create the page you wish to add JS-Kit comments to.

3) Open the page inspector, go to the Header > CSS tab. Paste the following CSS:

#comment{
height: 40px;
visibility: hidden;
font-size: 13px;
}
.href{
font-size: 15px;
}
#subtext{
height: 12px;
position: relative;
top: -20px;
visibility: hidden;
font-size: 8px;
font-style: italic;
}

Please note that the CSS may require some editing to ensure the link to the comment page matches the style of your site. Not all of us adore grey links.

The CSS reserves a space for the comments link, which is generated when the page has finished loading.

4) Still in the page inspector, switch to the Javascript tab. Drag the Friendly Comments snippet in. Close the page inspector.

Please note that if you are using a different script on the page that uses the “addLoadEvent” function, you don’t need to add the function again. You will, however, need to make a call to it:

addLoadEvent(friendlyComment);
5)

Create a new HTML page. The following code should be modified, then pasted into this page:

 

A_TITLE = a title (do this now, it’ll come in handy in the future ;)
PATH_TO_MAIN_PAGE = full URL to the page containing the link to this comment page.

As this page will only be displaying comments, it won’t need much of the styling required for the other pages in your site. The way I accomplished this is possibly not the best, but it worked for me. I copied the CSS from the styles.css file for the theme I use, pasted it between tags, and removed the information from the {…} for each item. It took awhile. I suggest you work through the rest of the tutorial and preview your work to see if you need this step.

View the CSS example

Now you should upload the HTML page.

6) On your main page, wherever you wish the link to the comment page to appear, paste* the following:



    

(Comments will open on top of this page)

You will need to change the following:

***X = Horizontal size of the comment Greybox
***Y = Vertical size of the comment Greybox
LINK_TO_THIS_PAGE = the full URL to the page this code is to be pasted in
LINK_TO_COMMENTS_PAGE = full URL to the comments page
TITLE_OF_COMMENTS = Text you wish to appear at the top of the comment Greybox

This code should go in either the main body of the page or the sidebar. On my photo pages I’ve pasted it into the “header” area of the Rapidflicker plugin.

As an example, this is the exact code I use for my Hangzhou Day 1 photo page:



    

(Comments will open on top of this page)

Example CSS:

Back to step #5

*Remember to select the pasted code and either choose “Format > Ignore Formatting” from the RapidWeaver menu, or press “⌘ + .”

Always do this when pasting code. Always.

If you don’t do this, there is a good chance that the code will break. Always do this!

As an added precaution, open the Page Inspector, go to the “General” tab and choose “Output: Default”. This will stop RapidWeaver from inadvertently breaking PHP or HTML code.

To learn more JS-Kit tricks, read the following posts:

Fancy Footer
JS-Kit Comments for Each Blog Entry
JS-Kit Comments: Correct Usage of the ‘Permalink’ and ‘Path’ Attributes
Recent Comments PHP Script
Styling JS-Kit Comments
JS-Kit Comments: Correct Usage of the ‘Permalink’ and ‘Path’ Attributes

Like this post? Move it on along with:

email Email | delicious delicious | digg Digg | Tweet this post Tweet | reddit Reddit | newsvine Newsvine | furl Furl | google Google | StumbleUpon Stumble | Hao Hao HaoHao


Trackback:

Comments: 0 | Comments Feed

Scroll to post title

No commentsTrackback

Archive Annihilator Improved Again

The solution for the ’sidebar explosion’ effect that the Archive Annihilator caused occurred to me earlier today. The fix was pretty simple, the fact that I didn’t think of it right away is a little embarrassing.

The update has been uploaded, and is available here.

Like this post? Move it on along with:

email Email | delicious delicious | digg Digg | Tweet this post Tweet | reddit Reddit | newsvine Newsvine | furl Furl | google Google | StumbleUpon Stumble | Hao Hao HaoHao


Trackback:

Comments: 0 | Comments Feed

Scroll to post title

No commentsTrackback