Anti-aliasing custom bar button image in iOS - ios

I'm trying to use a custom bar button image. I've created a simple PNG image with a white object and a transparent background as recommended by Apple:
As you can see, there is no anti-aliasing being applied (that is my exact image, pixel for pixel).
Apple does recommend to use Anti-aliasing, but don't provide any more detail. I would have thought this would be a function of the software like it would with text, rather than pre-applying it to the image.
The question is--how can I programatically provide anti-aliasing for my custom bar button images?
I have tried several things but nothing is doing it for me. Here's one thing I tried:
- (UIImage *)antialiasedImage
{
// Check to see if Antialiased Image has already been initialized
if (_antialiasedImage != nil) {
return _antialiasedImage;
}
// Get Device Scale
CGFloat scale = [[UIScreen mainScreen] scale];
// Get the Image from Resource
UIImage *buttonImage = [UIImage imageNamed:#"ReferenceFieldIcon"]; // .png???
// Get the CGImage from UIImage
CGImageRef imageRef = [buttonImage CGImage];
// Find width and height
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
// Begin Context
UIGraphicsBeginImageContextWithOptions(buttonImage.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
// Set Antialiasing Parameters
CGContextSetAllowsAntialiasing(context, YES);
CGContextSetShouldAntialias(context, YES);
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
// Draw Image Ref on Context
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
// End Context
UIGraphicsEndImageContext();
// Set CGImage to UIImage
_antialiasedImage =
[UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
// Release Image Ref
CGImageRelease(imageRef);
return _antialiasedImage;
}
Then I create my Segmented Control Like So:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSArray *centerItemsArray =
[NSArray arrayWithObjects: #"S",
self.antialiasedImage,
#"D",
nil];
UISegmentedControl *centerSegCtrl =
[[UISegmentedControl alloc] initWithItems:centerItemsArray];
centerSegCtrl.segmentedControlStyle = UISegmentedControlStyleBar;
UIBarButtonItem *centerButtonItem =
[[UIBarButtonItem alloc] initWithCustomView:(UIView *)centerSegCtrl];
UIBarButtonItem *flexibleSpace =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
target:nil
action:nil];
NSArray *barArray = [NSArray arrayWithObjects: flexibleSpace,
centerButtonItem,
flexibleSpace,
nil];
[self setToolbarItems:barArray];
}
Thank you in advance!

IOS doesn't add anti-aliasing to rendered images--only items drawn from code. You'll have to anti-alias the image before saving to file.
The way to anti-alias images from code is to draw them code.

Related

Putting text over an image programmatically in Objective-C

I want to add text on an image programmatically, but I can't seem to find how to do it. I've found one solution on here, but a lot of things are deprecated so it doesn't work...
Please help!
EDIT:
Here's my code:
UIImage *backgroundImage = image;
NSMutableDictionary *stringAttributes = [NSMutableDictionary dictionary];
[stringAttributes setObject: [UIFont fontWithName:#"Helvetica" size:20] forKey: NSFontAttributeName];
[stringAttributes setObject: [UIColor whiteColor] forKey: NSForegroundColorAttributeName];
[stringAttributes setObject: [NSNumber numberWithFloat: 2.0] forKey: NSStrokeWidthAttributeName];
[stringAttributes setObject: [UIColor blackColor] forKey: NSStrokeColorAttributeName];
[backgroundImage drawInRect:CGRectMake(0, 0, backgroundImage.size.width, backgroundImage.size.height)];
NSString *myString = [NSString stringWithFormat:#"Yolo"];
[myString drawInRect:CGRectMake(0, 0, 200, 50) withAttributes:stringAttributes];
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.imageView.image = result;
NEW EDIT:
I'd like to clearify some things to understand the question better. My app lets the user send a photo that they have taken themselves via text messaging or by email, and I want to add some pre-written text from strings, on the photo.
So my question is: How do I get the text from the strings, on to the photo?
It took forever, but I figured it out.
Code:
NSMutableDictionary *stringAttributes = [NSMutableDictionary dictionary];
[stringAttributes setObject: [UIFont fontWithName:#"Avenir Book" size:250] forKey: NSFontAttributeName];
[stringAttributes setObject: [UIColor whiteColor] forKey: NSForegroundColorAttributeName];
NSString *placeString = [NSString stringWithFormat:#"Text here."];
CGSize size = [placeString sizeWithAttributes:stringAttributes];
//Create a bitmap context into which the text will be rendered.
UIGraphicsBeginImageContext(size);
//Render the text.
[placeString drawAtPoint:CGPointMake(0.0, 0.0) withAttributes:stringAttributes];
//Retrieve the image.
UIImage *imagene = UIGraphicsGetImageFromCurrentImageContext();
UIImage *mergedImage = _imageView.image;
CGSize newSize = image.size;
UIGraphicsBeginImageContext(newSize);
//Use existing opacity as is.
[mergedImage drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
//Apply supplied opacity if applicable.
CGRect drawingRect = (CGRect) {.size = size};
drawingRect.origin.x = (newSize.width - size.width) * 0.01;
drawingRect.origin.y = (newSize.height - size.height) * 0.03;
[imagene drawInRect:drawingRect blendMode:kCGBlendModeNormal alpha:1];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[_imageView setImage:newImage];
self.imageView.image = newImage;
Here's a general approach, code is likely missing but it gives you the important bits.
CGContextRef ctx = CGBitmapContextCreate(...)
CGContextDrawImage (gtx, myContextRect, myimage);
CGContextSelectFont(ctx, "Helvetica", 10.0, kCGEncodingMacRoman);
CGContextSetCharacterSpacing(ctx, 1.7);
CGContextSetTextDrawingMode(ctx, kCGTextFill);
CGContextShowTextAtPoint(ctx, 100.0, 100.0, "SOME TEXT", 9);
CGImageRef imageRef = CGBitmapContextCreateImage(ctx);
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
This will give you an image you can put in a view, or share via UIActivityViewController. I'm sure you can work out the bits.
The approach is:
1) Create bitmap context.
2) Render image
3) Add text
4) Save context to image
Simply place a UILabel on top of a UIImageView in IB and position them as desired using constraints. Then set the text into the label as desired.
EDIT:
Now that I know you want to be able to save I'd suggest using UIGraphicsBeginImageContextWithOptions to create an off-screen graphics context. I find that easier to deal with than CGContext and Core Graphics calls.
Draw into the context and the fetch and image from it.
Make the context the size of your image, and pass in a scale of 0 to use the device's native scale.
Your code might look something like this:
//Create an off-screen graphics context for drawing.
CGSize imageSize = myImage.size;
UIGraphicsBeginImageContextWithOptions(imageSize, false, 0);
//draw your image using drawAtPoint(CGPointmake(0,0));
//draw your string using one of the drawAtPoint or drawInRect methods
//available in NSString UIKit additions
//Fetch the resulting image from the context.
UIImage *maskImage = UIGraphicsGetImageFromCurrentImageContext();
//End the off-screen context
UIGraphicsEndImageContext();

iOS Mask Image size too high

I wasn't sure how to name this, sorry for the title.
I have an image that I want to fill more or less depending on a variable. For this, I created an image made of black and white (below). The goal is to use it as a mask and fill it the way I want, based on this documentation.
The issue: the image is drawn properly BUT its dimensions are way too high. I test it on iPhone 6+ with a #3x image, the image asset size is correct but the image that is returned by my function is way too big. When I put constraints on my UIImageView*, I only view part of the returned filled image; when I don't, the image is way too big. See below for a screenshot (iPhone 6+)
I subclassed a UIView with the following code:
- (void)drawRect:(CGRect)rect
{
CGFloat width = self.frame.size.width;
NSLog(#"%0.f", width);
CGFloat height = self.frame.size.height;
NSLog(#"%0.f", height);
CGFloat fillHeight = 0.9 * height;
NSLog(#"%0.f", fillHeight);
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect fillRect = CGRectMake(0, height - fillHeight, width, fillHeight);
CGContextAddRect(context, fillRect);
CGContextSetFillColorWithColor(context, [UIColor yellowColor].CGColor);
CGContextFillRect(context, fillRect);
CGRect emptyRect = CGRectMake(0, 0, width, height - fillHeight);
CGContextAddRect(context, emptyRect);
CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
CGContextFillRect(context, emptyRect);
}
- (UIImage *)renderAsImage
{
// setup context
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0); // use same scale factor as device
CGContextRef c = UIGraphicsGetCurrentContext();
// render view
[self.layer renderInContext:c];
// get reslting image
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
NSLog(#"result size = %d width, %d height", result.size.width, result.size.height);
UIGraphicsEndImageContext();
return result;
}
And in my ViewController:
- (void) setUpMaskedImage
{
// Image View set in Storyboard that will contain the final image. Bounds are set in Storyboard (constraints)
UIImageView* imageView = self.containingImageView;
// Custom View (see methods above) that will draw a rectangle filled with color
UIView* view = [[CustomView alloc] initWithFrame: imageView.frame];
// Mask Image used along with the custom view to create final view (see image above)
UIImage* maskImage = [UIImage imageNamed: #"maskImage"];
[view setNeedsDisplay];
UIImage* fillImage = [view renderAsImage];
CGImageRef maskRef = maskImage.CGImage;
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
CGImageGetHeight(maskRef),
CGImageGetBitsPerComponent(maskRef),
CGImageGetBitsPerPixel(maskRef),
CGImageGetBytesPerRow(maskRef),
CGImageGetDataProvider(maskRef), NULL, false);
CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
UIImage* imageToDisplay = [UIImage imageWithCGImage:masked];
[imageView setImage:imageToDisplay];
}
I just don't get it. I used similar code elsewhere in my app and it works just fine. I will do a sample project soon if necessary.
Thank you!

How do I set the height and width to an NSArray animation?

I have animation of images and some images are different widths and heights. What I am looking to do is set the width and height to each of theses images.
jumperguy.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"jumperguy_a_1.png"],
[UIImage imageNamed:#"jumperguy_a_2.png"],
[UIImage imageNamed:#"jumperguy_a_3.png"],
[UIImage imageNamed:#"jumperguy_a_4"],nil];
[jumperguy setAnimationRepeatCount:1];
jumperguy.animationDuration = 1;
[jumperguy startAnimating];
UIImageView animation does a "flip book" style animation where each image is drawn into the same frame. I don't believe it will handle images of different sizes between frames. As Wain suggests, you should scale your images to fit in the same frame in an image editor before putting them into your app.
As I mentioned in my comment, you can programmatically scale each image in your array like so:
...
CGFloat width = whateverWidth;
CGFloat height = whateverHeight;
jumperguy.animationImages = [NSArray arrayWithObjects:
[self imageWithImage:[UIImage imageNamed:#"jumperguy_a_1.png"] scaledToSize:CGSizeMake(width, height)],
[self imageWithImage:[UIImage imageNamed:#"jumperguy_a_2.png"] scaledToSize:CGSizeMake(width, height)],
[self imageWithImage:[UIImage imageNamed:#"jumperguy_a_3.png"] scaledToSize:CGSizeMake(width, height)],
[self imageWithImage:[UIImage imageNamed:#"jumperguy_a_4.png"] scaledToSize:CGSizeMake(width, height)],nil];
[jumperguy setAnimationRepeatCount:1];
jumperguy.animationDuration = 1;
[jumperguy startAnimating];
}
- (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)newSize {
//UIGraphicsBeginImageContext(newSize);
// In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution).
// Pass 1.0 to force exact pixel size.
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}

set size of an image programatically

is there any way I can set the size of an image in my NavigationBar programatically instead of changing in manually?
Here is the code which creates the button:
UIBarButtonItem *Share = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"fb_share.png"] style:UIBarButtonItemStyleBordered target:self action:#selector(Share:)];
My images size is 256*256 so it simply show up in this resolution and whole screen is messed.
You just want to change the size of your image? If so, something like this should work:
// Given a UIImage image and a CGSize newSize:
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Then use newImage for the image of the UIBarButtonItem.
Normaly you should use contentMode (in this case UIViewContentModeScaleAspectFit) every UIView subclass have this property usually you might use it to UIImageView. But i'm almost sure that does not work with UIBarButtonItem. Try, but you might hit a wall.
If my prediction was true you have to resize image programatically:
UIImage *myImage = [UIImage imageNamed:#"fb_share"];
float maximumHeight = 44;
float ratio = maximumHeight/ myImage.size.height;
CGSize imageNewSize = CGSizeMake(myImage.size.width*ratio, maximumHeight);
UIGraphicsBeginImageContextWithOptions(imageNewSize, NO, 0.0);
[myImage drawInRect:CGRectMake(0, 0, imageNewSize.width, imageNewSize.height)];
UIImage *resizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIBarButtonItem *Share = [[UIBarButtonItem alloc] initWithImage:resizedImage style:UIBarButtonItemStyleBordered target:self action:#selector(Share:)];

Converting between UIImage (PNG) and RGB8

I am using https://github.com/PaulSolt/UIImage-Conversion
However, it seems to have a problem on the alpha channel. Problem reconstituting UIImage from RGBA pixel byte data
I have simplified the problem so I present it as a tidier question.
I download Paul's project, run it. It displays an image in the centre of the screen -- everything so far is correct.
But his demo is not testing for Alpha.
So I attempt to composite my button image...
... on top.
The result is:
here is the code -- I have just modified AppDelegate_iPad.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
{
UIImage *image = [UIImage imageNamed:#"Icon4.png"];
int width = image.size.width;
int height = image.size.height;
// Create a bitmap
unsigned char *bitmap = [ImageHelper convertUIImageToBitmapRGBA8:image];
// Create a UIImage using the bitmap
UIImage *imageCopy = [ImageHelper convertBitmapRGBA8ToUIImage:bitmap withWidth:width withHeight:height];
// Cleanup
if(bitmap) {
free(bitmap);
bitmap = NULL;
}
// Display the image copy on the GUI
UIImageView *imageView = [[UIImageView alloc] initWithImage:imageCopy];
CGPoint center = CGPointMake([UIScreen mainScreen].bounds.size.width / 2.0,
[UIScreen mainScreen].bounds.size.height / 2.0);
[imageView setCenter:center];
[window addSubview:imageView];
[imageView release];
}
if( 1 )
{
UIImage *image = [UIImage imageNamed:#"OuterButton_Dull.png"];
int width = image.size.width;
int height = image.size.height;
// Create a bitmap
unsigned char *bitmap = [ImageHelper convertUIImageToBitmapRGBA8:image];
// Create a UIImage using the bitmap
UIImage *imageCopy = [ImageHelper convertBitmapRGBA8ToUIImage:bitmap withWidth:width withHeight:height];
// Cleanup
if(bitmap) {
free(bitmap);
bitmap = NULL;
}
// Display the image copy on the GUI
UIImageView *imageView = [[UIImageView alloc] initWithImage:imageCopy]; // <-- X
imageView.backgroundColor = [UIColor clearColor];
CGPoint center = CGPointMake([UIScreen mainScreen].bounds.size.width / 2.0,
[UIScreen mainScreen].bounds.size.height / 2.0);
[imageView setCenter:center];
[window addSubview:imageView];
[imageView release];
}
[window makeKeyAndVisible];
return YES;
}
If I switch the line marked...
// <-- X
to say...
... initWithImage:image]; // instead of imageCopy
... it displays as it should:
Is anyone up having a crack at this? It looks a really nice library to use, but I can't figure out where the problem is.
I just got a reply from the author:
At the bottom of his blog post, http://paulsolt.com/2010/09/ios-converting-uiimage-to-rgba8-bitmaps-and-back/ Scott Davies presents a fix:
There’s a simple one-line fix for your code so that alpha channels are
preserved when you go from the byte buffer to the UIImage. In
convertBitmapRGBA8ToUIImage, change this:
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
to this:
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault |
kCGImageAlphaPremultipliedLast;

Resources