Can't draw UImage in UIView::drawRect - objective-c

I know this seems like a simple task, which is why I don't understand why I can't get the image to render.
When I set up my UIView, I do the following:
myUiView.backgroundColor = [UIColor clearColor];
myUiView.opaque = NO;
I create and retain the UIImage in the init function of my UIView:
image = [[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"test" ofType:#"png"]] retain];
then my drawRect looks like this:
- (void) drawRect:(CGRect) rect
{
[image drawInRect:self.bounds];
}
Ultimately I'll be manipulating that UIImage via bitmap context, and then in drawRect create a CGImage out of the context, and render that, but for now I'm just trying to get it rendering a known image.
I've been digging through this site, as well as the documentation. I've gone down the CG path and tried drawing it with CGContextDrawImage by following the numerous examples other people have posted, but that didn't work either.
So I've come back to what seems to be the most straightforward way to draw an image, but it isn't working.
Any help would be greatly appreciated.
Thanks in advance.

First of all, verify that the size and position of self.bounds are what you want them to be. If the size is {0,0} nothing will display. Check using this function:
NSLog(#"%#", NSStringFromCGRect(self.bounds));
Also make sure that the image is not nil:
NSLog(#"%#", image);

Related

Objective C - UIImage resizing not working

I have a program that fetches an image from the library, but I'm using code I found online to resize that image so that it can fit on the screen (basically making it 640x960), but then it would still be too big to display, so in another UIImage I'm copying the first resized image and re-resizing this one to make it about 1/4 of the screen (or 160x240). The code is this:
for ViewController.h:
UIImage *img;
UIImage *thumb;
-(UIImage*) scaleImage: (UIImage*)image toSize:(CGSize)newSize;
(this of course, is only the code related to my problem)
for ViewController.m
-(UIImage*) scaleImage: (UIImage*)image toSize:(CGSize)newSize {
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
and in the same m file on another function, the scaleImage function is called when pressing a button with these lines:
[self scaleImage:img toSize:CGSizeMake(640, 960)];
thumb = img;
[self scaleImage:thumb toSize:CGSizeMake(160, 240)];
In the project I've previously been able to successfully provide an image for img using [info objectForKey:UIImagePickerControllerOriginalImage]; which would be the image chosen from the library. I've already "file owned" everything so that this function takes place (and it does because I create an UIAlert within it and it shows, and a NSLog to print out when scaleImage starts and it does, twice), but the image is never re-sized!! Does anyone know why?? Please let me know, thank you for anyone who comments with help or suggestions!!
Your scaleImage method returns the scaled image, for example
thumb = [self scaleImage:img toSize:CGSizeMake(640, 960)];

Draw NSString without using drawAtPoint or drawRectIn

I have subclassed an UILabel and i use drawrect method to draw the string on the screen. This is my code:
- (void)drawRect:(CGRect)rect
{
CGRect aRect = self.frame;
NSMutableArray *Text=[globaltextarray Text];
[[NSString stringWithCString:[[Text objectAtIndex:labelindexpath.row] cStringUsingEncoding:NSISOLatin1StringEncoding] encoding:NSUTF8StringEncoding] drawInRect:aRect
withFont:[UIFont fontWithName:#"Times New Roman" size:15.0] lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentLeft];
[super drawRect:rect];
}
It is working fine but it is slow for my purpose. I need to draw the string without using [Label setNeedDisplay]; because setNeedsDisplay needs to be called from the main thread. The rendering work needs to be done in a background queue. I would be grateful if you could provide me with a small example. Any help appreciated.
Thanks.
You can create a new CGContext to draw the string into CGImage/UIImage using CGBitmapContextCreateImage on separate thread, then draw the bitmap(generated image) into view on the main thread.
EDIT:
Check this post for example.

To Convert HTML doc to image in cocoa

is it possible to convert the HTML page to image in cocoa?
Actually i have created the complete view in the HTML and now i want to convert the whole html preview to the image (any jpeg or png etc.).
I couldn't find any resource or sample on the web, which provides some sort of help on my above queries.It's highly appreciated if someone could share his wisdom on how I can achieve this.
Thanks in advance..
First off, I'd like to thank sergio... his answer got me started but I thought I'd share some of the code that I didn't find obvious that I had to write to make it work:
Here's how to make a thumbnail for a page without ever having it displayed:
// Your width and height can be whatever you like, but if you want this to render
// off screen, you need an x and y bigger than the superview's width and height
UIWebView* webView = [[UIWebView alloc] initWithFrame:CGRectMake(largerScreenDimension, largerScreenDimension, largerScreenDimension, largerScreenDimension)];
[self.view addSubview:webView]; // UIWebViews without an assigned superview don't load ever.
webView.delegate = self; // or whoever you have implement UIWebViewDelegate
webView.scalesToFit = YES; // This zooms the page appropriately to fill the entire thumbnail.
[webView loadRequest:[NSURLRequest requestWithURL:url]];
Then implement this in your delegate:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
UIGraphicsBeginImageContext(webView.bounds.size);
[webView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *webViewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *thumbnailData = UIImagePNGRepresentation(webViewImage);
[webView removeFromSuperview];
}
Finally, to display this thumbnail you'll need something like:
thumbnailImageView.image = [UIImage imageWithData:thumbnailData];
As a bonus thing I'll mention, I wanted multiple thumbnails to be generated at once. I found using objc_setAssociatedObject() and objc_getAssociatedObject() to be very helpful with keeping track of which webView was loading which thumbnail. Going into detail on how that worked is beyond the scope of this question, though.
You can draw your view in an image context, like this:
UIWebView* view = ...
....
UIGraphicsBeginImageContext(view.bounds.size);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *imagedata = UIImagePNGRepresentation(viewimage);
NSString *encodedString = [imageData base64Encoding];
Another option would be using Quartz PDF engine to create a PDF.

Rendering NSView containing some CALayers to an NSImage

I have an NSView that contains an NSScrollView containing a CALayer-backed NSView. I've tried all the usual methods of capturing an NSView into an NSImage (using -dataWithPDFInsideRect, NSBitmapImageRep's -initWithFocusedViewRect, etc.) However, all these methods treat the CALayer-backed NSView as if it doesn't exist. I've already seen this StackOverflow post, but it was a question about rendering just a CALayer tree to an image, not an NSView containing both regular NSView's and layer-backed views.
Any help is appreciated, thanks :)
The only way I found to do this is to use the CGWindow API's, something like:
CGImageRef cgimg = CGWindowListCreateImage(CGRectZero, kCGWindowListOptionIncludingWindow, [theWindow windowNumber], kCGWindowImageDefault);
then clip out the part of that CGImage that corresponds to your view with
-imageByCroppingToRect.
Then make a NSImage from the cropped CGImage.
Be aware this won't work well if parts of that window are offscreen.
This works to draw a view directly to an NSImage, though I haven't tried it with a layer-backed view:
NSImage * i = [[NSImage alloc] initWithSize:[view frame].size];
[i lockFocus];
if ([view lockFocusIfCanDrawInContext:[NSGraphicsContext currentContext]]) {
[view displayRectIgnoringOpacity:[view frame] inContext:[NSGraphicsContext currentContext]];
[view unlockFocus];
}
[i unlockFocus];
NSData * d = [i TIFFRepresentation];
[d writeToFile:#"/path/to/my/test.tiff" atomically:YES];
[i release];
Have you looked at the suggestions in the Cocoa Drawing Guide? ("Creating a Bitmap")
To draw directly into a bitmap, create a new NSBitmapImageRep object with the parameters you want and use the graphicsContextWithBitmapImageRep: method of NSGraphicsContext to create a drawing context. Make the new context the current context and draw. This technique is available only in Mac OS X v10.4 and later.
Alternatively, you can create an NSImage object (or an offscreen window), draw into it, and then capture the image contents. This technique is supported in all versions of Mac OS X.
That sounds similar to the iOS solution I'm familiar with (using UIGraphicsBeginImageContext and UIGraphicsGetImageFromCurrentImageContext) so I'd expect it to work for your view.
Please have a look at the answer on this post: How do I render a view which contains Core Animation layers to a bitmap?
That approach worked for me under similar circumstances to your own.

Using drawAtPoint with my CIImage not doing anything on screen

Stuck again. :(
I have the following code crammed into a procedure invoked when I click on a button on my application main window. I'm just trying to tweak a CIIMage and then display the results. At this point I'm not even worried about exactly where / how to display it. I'm just trying to slam it up on the window to make sure my Transform worked. This code seems to work down through the drawAtPoint message. But I never see anything on the screen. What's wrong? Thanks.
Also, as far as displaying it in a particular location on the window ... is the best technique to put a frame of some sort on the window, then get the coordinates of that frame and "draw into" that rectangle? Or use a specific control from IB? Or what? Thanks again.
// earlier I initialize a NSImage from JPG file on disk.
// then create NSBitmapImageRep from the NSImage. This all works fine.
// then ...
CIImage * inputCIimage = [[CIImage alloc] initWithBitmapImageRep:inputBitmap];
if (inputCIimage == Nil)
NSLog(#"could not create CI Image");
else {
NSLog (#"CI Image created. working on transform");
CIFilter *transform = [CIFilter filterWithName:#"CIAffineTransform"];
[transform setDefaults];
[transform setValue:inputCIimage forKey:#"inputImage"];
NSAffineTransform *affineTransform = [NSAffineTransform transform];
[affineTransform rotateByDegrees:3];
[transform setValue:affineTransform forKey:#"inputTransform"];
CIImage * myResult = [transform valueForKey:#"outputImage"];
if (myResult == Nil)
NSLog(#"Transformation failed");
else {
NSLog(#"Created transformation successfully ... now render it");
[myResult drawAtPoint: NSMakePoint ( 0,0 )
fromRect: NSMakeRect ( 0,0,128,128 )
operation: NSCompositeSourceOver
fraction: 1.0]; //100% opaque
[inputCIimage release];
}
}
Edit #1:
snip - removed the prior code sample mentioned below (in the comments about drawRect), which did not work
Edit #2: adding some code that DOES work, for anyone else in the future who might be stuck on this same thing. Not sure if this is the BEST way to do it ... but it does work for my quick and dirty purposes. So this new code (below) replaces the entire [myResult drawAtPoint ...] message from above / in my initial question. This code takes the image created by the CIImage transform and displays it in the NSImageView control.
NSImage *outputImage;
NSCIImageRep *ir;
ir = [NSCIImageRep imageRepWithCIImage:myResult];
outputImage = [[[NSImage alloc] initWithSize: NSMakeSize(inputImage.size.width, inputImage.size.height)] autorelease];
[outputImage addRepresentation:ir];
[outputImageView setImage: outputImage]; //outputImageView is an NSImageView control on my application's main window
Drawing on screen in Cocoa normally takes place inside an -[NSView drawRect:] override. I take it you're not doing that, so you don't have a correctly set up graphics context.
So one solution to this problem is to create a NSCIImageRep from the CIImage, then add that representation to a new NSImage, then it is easy to display the NSImage in a variety of ways. I've added the code I used up above (see "edit #2"), where I display the "output image" within an NSImageView control. Man ... what a PITA this was!