NSTextView not drawing text onto NSImage - objective-c

I'm attempting to draw some text onto an NSImage, but I've run into some issues.
Originally I was just drawing an attributed string onto the NSImage, but if the string was too long it would run off the image and I couldn't find a way to wrap the text to a newline.
To solve this I figured that I could just make an NSTextView, place the text in there, and then draw it onto the NSImage.
Unfortunately, when I attempt to draw the NSTextView to the NSImage, the text does not appear. The NSTextView's background color does show up though.
When I set a breakpoint before I lock focus on the NSImage, and preview the NSTextView, the text view has text. After I draw the text view onto the NSImage, it looks like the NSTextView is drawn, just without the text.
If there is a better way to throw text onto an NSImage that has the ability to have multiple lines, please let me know how.
Here's the code I've written for reference:
NSTextView *textToDraw = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, input.size.width - 16, 243)];
textToDraw.backgroundColor = [NSColor blueColor];
[textToDraw setAlignment:NSTextAlignmentCenter];
[textToDraw setEditable:YES];
// textOnImage is a regular NSString
[textToDraw insertText:textOnImage replacementRange:NSMakeRange(0, textOnImage.length)];
[textToDraw setTextColor:[NSColor blackColor]];
[textToDraw setFont:font];
[textToDraw setEditable:NO];
// input is an NSImage
[input lockFocus];
[textToDraw drawRect:NSMakeRect(8, inputImage.size.height - textToDraw.frame.size.height - 8, textToDraw.frame.size.width, textToDraw.frame.size.height)];
[input unlockFocus];

Instead of drawing textview on image you can provide the bounded rect in which text should be drawn. If the string is too long it wouldn't run off the image and will automatically enter in new line.
Here is code where inputImage is the image on which you want to draw text
NSImage *newImage = [[NSImage alloc] initWithSize:inputImage.size];
[newImage lockFocus];
[inputImage drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
[textStr drawInRect:boundedRect withAttributes:attrsDictionary];
[newImage unlockFocus];

Related

Xcode making a pdf, trying to round corners

I am making a pdf in an iPad app. Now i can make the pdf however want to add a picture with a rounded corner border. For example to achieve the effect i want on the border on a simple view item i use the following code.
self.SaveButtonProp.layer.cornerRadius=8.0f;
self.SaveButtonProp.layer.masksToBounds=YES;
self.SaveButtonProp.layer.borderColor=[[UIColor blackColor]CGColor];
self.SaveButtonProp.layer.borderWidth= 1.0f;
With the pdf i am using the following method to add the picture with the border to the pdf.
CGContextRef currentContext = UIGraphicsGetCurrentContext();
UIImage * demoImage = [UIImage imageWithData : Image];
UIColor *borderColor = [UIColor blackColor];
CGRect rectFrame = CGRectMake(20, 125, 200, 200);
[demoImage drawInRect:rectFrame];
CGContextSetStrokeColorWithColor(currentContext, borderColor.CGColor);
CGContextSetLineWidth(currentContext, 2);
CGContextStrokeRect(currentContext, rectFrame);
How do i round the corners?
Thanks
While drawing you can set clipping masks. For example, it's relatively easy to create a Bezier path with the shape of a rounded rectangle and apply that as clipping mask to your graphics context. Everything subsequently drawn will be clipped.
If you want remove the clipping mask later (for example because you have an image with rounded corners but follow that by other elements) you'll have to save the graphic state first, then apply your clipping mask and restore the graphics state when you're done with your rounded corners.
You can see actual code that comes pretty close to what I think you need here:
UIImage with rounded corners
You can use a method to get any UIView/UIImageView to PDF NSData:
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
NSData *data = [self makePDFfromView:imageView];
Method:
- (NSData *)makePDFfromView:(UIView *)view
{
NSMutableData *pdfData = [NSMutableData data];
UIGraphicsBeginPDFContextToData(pdfData, view.bounds, nil);
UIGraphicsBeginPDFPage();
CGContextRef pdfContext = UIGraphicsGetCurrentContext();
[view.layer renderInContext:pdfContext];
UIGraphicsEndPDFContext();
return pdfData;
}
Maybe you can change or use this code to help you with your problem.

Adding an image border

OK, this is what I'm trying to do :
Get an NSImage containing, let's say a photo (1000+ x 1000+ dimensions).
Get another NSImage containing just a tranparent background and a simple black border (500x500).
"Combine" the 2 images, so that the resulting image is the photo with a border.
This is what I've achieved so far :
NSImage* resultImage = [[[self drop] image] copy];
[resultImage lockFocus];
NSRect newRect = NSMakeRect(0, 0, [[[self drop] image] size].width, [[[self drop] image] size].height);
[[[self drop2] image] drawInRect:newRect
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:1.0];
[resultImage unlockFocus];
[[self drop] setImage:resultImage];
Where [self drop] is an ImageWell containing the photo, and [self drop2] an ImageWell containing the border.
The thing is that it IS working. However, the resulting image is - quite obviously - showing a somewhat "stretched" border.
How could I resolve that? Given that the original photo should be of ANY dimensions, how could I make it to use a border (of some fixed dimensions) and still avoid stretching?
How about doing the border directly with CALayer, e.g.:
#import <QuartzCore/QuartzCore.h>
CALayer *layer = imageView.layer;
layer.borderColor = [[NSColor blackColor] CGColor];
layer.borderWidth = 10;
I would do this differently. Just size the image as desired and then add the border. You could do this just by having a simple view with black background, or a suitable image (assuming you want to have customizable image borders, like frames), sized to always keep the resulting border constant. Then you can generate a new image from that view, if you need to.

NSImage +imageWithPatternColor: and NSGradient - Cocoa/Mac

I am drawing on a custom view an NSGradient like this:
- (void)drawRect: (NSRect)dirtyRect
{
NSGradient* g = [[NSGradient alloc] initWithStartingColor: _color endingColor: [NSColor clearColor]];
[g drawInRect: [self bounds] angle: 90];
}
If _color is a normal color, for example [NSColor blueColor], everything is fine. The problem is that _color comes from a pattern image (which in this case is mostly grey with some fancy pixels on it), and when that happens the program keeps logging this error:
*** -[NSGradient initWithColors:atLocations:colorSpace:]: the color NSPatternColorSpace CGImageSource=0x400367d60"
)> cannot be converted into color space Generic RGB colorspace
_color = [NSColor colorWithPatternImage: [NSImage imageNamed: #"mainBG.png"]]
The image is completely opaque and is a png file.
Any ideas? perhaps I should change the file type? I don't know...
EDIT:
If I define _color like this:
_color = [[NSColor colorWithPatternImage: [NSImage imageNamed: #"mainBG.tiff"]] colorUsingColorSpace: [NSColorSpace genericRGBColorSpace]]
then no gradient is displayed. Nothing. Just as if I didn't have the drawRect: method. Any ideas?
An NSGradient doesn't work with a pattern as one of the colors. That's what the exception is telling you. It will only work with an NSColor that can be converted to an RGB color. If you want to make your pattern fade to clear, you'll have to do it another way.

Drawing text in a NSButton subclass - positioning

I Have a custom button:
My Button http://cld.ly/29ubq
And I need the text to be centered, here's my code:
NSMutableParagraphStyle *style =
[[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setLineBreakMode:NSLineBreakByWordWrapping];
[style setAlignment:NSLeftTextAlignment];
att = [[NSDictionary alloc] initWithObjectsAndKeys:
style, NSParagraphStyleAttributeName,
[NSColor blackColor],
NSForegroundColorAttributeName, nil];
[style release];
// other Drawing code here
[[self title] drawInRect:[self bounds] withAttributes:att];
How do I center the text in the center of my button (not center of the bounds)?
You want to get the size of the title first using NSString -sizeWithAttributes:. Then you can use that size to adjust the drawing of title within your bounds.
There is a trick to this, since you will almost always wind up dividing by two at some point in this process. When you do that, you may wind up with a half-pixel result, which Cocoa will happily use. However, it will cause your text to be blurry. You almost always want to call floor() on your coordinates before drawing on them to get yourself back onto integral pixels.
Edit: A basic example of centering (this should compile correctly, I haven't compiled it and my recent work has been over on iPhone which is upside-down):
NSRect rect;
rect.size = [[self title] sizeWithAttributes:att];
rect.origin.x = floor( NSMidX([self bounds]) - rect.size.width / 2 );
rect.origin.y = floor( NSMidY([self bounds]) - rect.size.height / 2 );
[[self title] drawInRect:rect withAttributes:att];
Anyway, something along those lines. You may want to offset a bit because of how your button draws, but this is the basic idea.
You could be interested in Setting a Button’s Image, which also explain how to position the title relative to the button’s image.

NSBitmapImageRep and multi-page TIFFs

I've got a program that can open TIFF documents and display them. I'm using setFlipped:YES.
If I'm just dealing with single page image files, I can do
[image setFlipped: YES];
and that, in addition to the view being flipped, seems to draw the image correctly.
However, for some reason, setting the flipped of the image doesn't seem to affect the flippedness of the individual representations.
This is relevant because the multiple images of a multi-page TIFF seem to appear as different "representations" of the same image. So, if I just draw the IMAGE, it's flipped, but if I draw a specific representation, it isn't flipped. I also can't seem to figure out how to chose which representation is the default one that gets drawn when you draw the NSImage.
thanks.
You shouldn't use the -setFlipped: method to control how the image is drawn. You should use a transform based on the flipped-ness of the context you are drawing into. Something like this (a category on NSImage):
#implementation NSImage (FlippedDrawing)
- (void)drawAdjustedInRect:(NSRect)dstRect fromRect:(NSRect)srcRect operation:(NSCompositingOperation)op fraction:(CGFloat)delta
{
NSGraphicsContext* context = [NSGraphicsContext currentContext];
BOOL contextIsFlipped = [context isFlipped];
if (contextIsFlipped)
{
NSAffineTransform* transform;
[context saveGraphicsState];
// Flip the coordinate system back.
transform = [NSAffineTransform transform];
[transform translateXBy:0 yBy:NSMaxY(dstRect)];
[transform scaleXBy:1 yBy:-1];
[transform concat];
// The transform above places the y-origin right where the image should be drawn.
dstRect.origin.y = 0.0;
}
[self drawInRect:dstRect fromRect:srcRect operation:op fraction:delta];
if (contextIsFlipped)
{
[context restoreGraphicsState];
}
}
- (void)drawAdjustedAtPoint:(NSPoint)point
{
[self drawAdjustedAtPoint:point fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
}
- (void)drawAdjustedInRect:(NSRect)rect
{
[self drawAdjustedInRect:rect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
}
- (void)drawAdjustedAtPoint:(NSPoint)aPoint fromRect:(NSRect)srcRect operation:(NSCompositingOperation)op fraction:(CGFloat)delta
{
NSSize size = [self size];
[self drawAdjustedInRect:NSMakeRect(aPoint.x, aPoint.y, size.width, size.height) fromRect:srcRect operation:op fraction:delta];
}
#end
I believe that the answer is that Yes, different pages are separate representations, and the correct way to deal with them is to turn them into images with:
NSImage *im = [[NSImage alloc] initWithData:[representation TIFFRepresentation]];
[im setFlipped:YES];