I had the following code working in AppDelegate.h/.m but cannot change it to work in ViewController with a button triggering it.
#implementation BSViewController
#synthesize imageView;
#synthesize workingImage;
- (IBAction) chooseImage:(id) sender {
UIImage* testCard = [UIImage imageNamed:#"ipad 7D.JPG"];
CGImageRef num = CGImageCreateWithImageInRect([testCard CGImage],CGRectMake(532, 0, 104, 104));
UIGraphicsBeginImageContext(CGSizeMake( 250,650));
CGContextRef con = UIGraphicsGetCurrentContext();
UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
CGContextDrawImage(con, CGRectMake(0, 0, 13, 13) ,num);
UIGraphicsEndImageContext();
CGImageRelease(num);
UIImageView* iv = [[UIImageView alloc] initWithImage:im];
[self.imageView addSubview: iv];
iv.center = self.imageView.center;
[iv release];
I see the button named "Choose image" in the simulator, but I do not see the image there.
You haven't added self.imageView to any views.
You need
[self.view addSubview:self.imageView];
To show your imageView.
I was able to make it work, but let me ask you some dummy questions before. You can skip these and jump directly to the end for the answer:
Did it worked before?
Why aren't you using ARC?
Have you linked the chooseImage: to the button with Interface Builder, or programmatically? I sometimes forget this basic step, and nothing works of course :)
Why are you adding iv as a subview of self.imageView instead of just changing the image property of self.imageView. Knowing this could be useful to answer properly.
Supposing you have a good reason for adding iv as a subview, beware iv.center = self.imageView.center the centers are in two different coordinates system.
Form the Apple Documentation:
The center is specified within the coordinate system of its superview
and is measured in points. Setting this property changes the values of
the frame properties accordingly.
Edit: Other things to check
Does self.imageView exist? I mean, have you added it with IB and linked it to the IBOutlet, or defined it programmatically?
Add a break point in chooseImage: and go through it step by step, making sure that the objects you generate there are not nil
Test: try self.imageView setImage:im instead of self.imageView addSubview:iv, even if it's not what you want to do, if everything else is ok you should see the image.
It works if you switch the order of
UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
and
CGContextDrawImage(con, CGRectMake(0, 0, 13, 13) ,num);
Otherwise you would be asking to create im with the content of the context without nothing in drawn in it.
The code would then become:
UIImage* testCard = [UIImage imageNamed:#"ipad 7D.JPG"];
CGImageRef num = CGImageCreateWithImageInRect([testCard CGImage],CGRectMake(532, 0, 104, 104));
UIGraphicsBeginImageContext(CGSizeMake( 250,650));
CGContextRef con = UIGraphicsGetCurrentContext();
CGContextDrawImage(con, CGRectMake(0, 0, 13, 13) ,num);
UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRelease(num);
Hope it helps. :D
Related
Under iOS 8 a call to UIView's
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
results in a 1 frame flash of the image. You can see it for a split second on the screen. It only happens when afterScreenUpdates parameter is YES.
This is my complete code to take screenshot:
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, sf);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextConcatCTM(ctx, [self.layer affineTransform]);
if ([self respondsToSelector:#selector(drawViewHierarchyInRect:afterScreenUpdates:)]) { // iOS 7+
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:YES];
} else { // iOS 6
[self.layer renderInContext:ctx];
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
CGContextRestoreGState(ctx);
UIGraphicsEndImageContext();
Is there a workaround?
Provide #3x launch images to be used in iPhone6 and iPhone6 plus and this problem goes away.
Here's a possible workaround that solved my issue.
Use CATransaction.completionBlock to call UIView drawViewHierarchyInRect:afterScreenUpdates with the screen updates flag set to NO. I used this to workaround the same problem. It is semantically equivalent to setting the flag to YES in my case since I'm only invoking it after the current CATransaction has finished and the screen is in the desired state. That said, in my case, I don't have any animations, so this is pretty much immediate and captures exactly what I want. If there were animations, this may not be appropriate.
For my case, I have a collection view that is a collection of files. Each item is rendered as a snapshot of what the file looks like once the user opens it. Some files cause the UI to have hundreds of layers. When these complicated views were being snapshotted, I would get a black screen flash; or the last/current animation to partially rerun. My collection view is w/in a navigation controller, I was seeing partial reruns of the pop animation. I also have noticed reruns of rotation animations. For simpler files, there was often no issue. I noticed this on my iPad Air (iOs 8.1) and on various simulators. I tried putting appIcons and launchImages in place but they had no effect.
Here was the original code. It initializes a view controller, then adds the controller's view to the a utility view.
UIViewController *vlController = [[ComplicatedViewController alloc]init];
UIView *innerView = vlController.view;
[v addSubview:innerView];
innerView.transform = CGAffineTransformMakeScale(scalar, scalar);
innerView.center = CGRectCenterPoint(v.bounds);
auto sz = v.bounds.size;
innerView.bounds = {{0,0}, {sz.width/scalar, sz.height/scalar}};
UIGraphicsBeginImageContextWithOptions(v.bounds.size, YES, 0);
[v drawViewHierarchyInRect:v.bounds afterScreenUpdates:YES];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[innerView removeFromSuperview];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[v addSubview:imageView];
The new code just moves the bottom half to the completion block of UIView animateWithDuration:completion. Notice that the duration of the UIView animation is 0, but that still seems to give that extra refresh cycle to update the screen with the new UI.
UIViewController *vlController = [[ComplicatedViewController alloc]init];
UIView *innerView = vlController.view;
[UIView animateWithDuration:0.0 animations:^{
[v addSubview:innerView];
innerView.transform = CGAffineTransformMakeScale(scalar, scalar);
innerView.center = CGRectCenterPoint(v.bounds);
auto sz = v.bounds.size;
innerView.bounds = {{0,0}, {sz.width/scalar, sz.height/scalar}};
} completion:^(BOOL finished) {
UIGraphicsBeginImageContextWithOptions(v.bounds.size, YES, 0);
BOOL drawResult = [v drawViewHierarchyInRect:v.bounds afterScreenUpdates:NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[innerView removeFromSuperview];
[self add:image forFile:v.filename withOrientation:v.orientation];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[v addSubview:imageView];
}];
I have a table that contains the path to the picture, saved on user's library. Then, I pass this path to a View that contains just a imageView. I want to fills this ImageView with the picture. Like WhatsApp (when you click on a profile's picture). But, my picture it's always cropped or distorted. I tryed different ways to do this, but I didn't find the best way:
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBar.translucent = NO;
UIImage *picture = [UIImage imageWithContentsOfFile: self.picturePath]; //I passed this path from the previous View
UIImageView* imageView = [[UIImageView alloc] initWithImage:picture];
CGRect screenRect = [[UIScreen mainScreen] bounds];
imageView.frame = CGRectMake(0, 0, screenRect.size.width, screenRect.size.height);
imageView.contentMode = UIViewContentModeScaleAspectFill;
[self.view addSubview:imageView];
}
Original (I want something like it)
My app
If your image is cut , the reason is you are using a higher resolution image in a smaller container and instructed your imageview to fill , using this line imageView.contentMode = UIViewContentModeScaleAspectFill;
Change it to imageView.contentMode = UIViewContentModeScaleAspectFit;
I think #whitewolf09 is right and his method will solve your problem. But i suggest you to look into MGImageUtilities that will be very useful for different cases where you can crop images maintaining aspect ratio to fit inside your image view's frame.
Just #import "UIImage+ProportionalFill.h"
UIImage *image = [[UIImage imageWithContentsOfFile:filePath] imageScaledToFitSize:imageView.frame.size];
That's the very useful category for image resizing and may help you in future.
I think the reason it is being clipped is that you are creating the image view with a picture THEN setting the frame and probably the picture is bigger than the frame so it is clipping it. Also try changing the aspect to: 'UIViewContentModeScaleAspectFit' Try this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBar.translucent = NO;
UIImage *picture = [UIImage imageWithContentsOfFile:self.picturePath]; //I passed this path from the previous View
UIImageView* imageView = [[UIImageView alloc] initWithRect:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height);];
CGRect screenRect = [[UIScreen mainScreen] bounds];
imageView.image = picture;
imageView.contentMode = UIViewContentModeCenter;
[self.view addSubview:imageView];
}
I am having a UILabel with attributed string that user edits and eventually draws on a image. Here's how I update the UILabel every time user changes text in a UITextview and confirm.
- (void)displayPicture {
[self.view endEditing:YES];
self.attributedStr = [[NSAttributedString alloc] initWithString:self.textInputField.text attributes:self.attributes];
self.displayField.attributedText = [[NSAttributedString alloc] initWithString:self.textInputField.text attributes:self.attributes];
self.displayField.lineBreakMode = NSLineBreakByCharWrapping;
[self.displayField sizeToFit];
[self.displayField setNeedsDisplay];
self.textInputField.hidden = YES;
self.tapRecog.enabled = YES;
self.displayField.hidden = NO;
}
For now the UILabel displays the way desired on the screen.
When user wants the Pic+Text combined to an UIImage and posted, the following code is implemented:
- (UIImage *)generatePicture {
UIGraphicsBeginImageContextWithOptions(CGSizeMake(Picture_Standard_Width, Picutre_Standard_Height), YES, 0.0f);
[self.bgImageView.image drawInRect:CGRectMake(0, 0, Picture_Standard_Width, Picutre_Standard_Height)];
CGRect originalFrame = self.displayField.frame;
CGRect adjustedFrame = CGRectMake(originalFrame.origin.x, originalFrame.origin.y - self.bgImageView.frame.origin.y, originalFrame.size.width, originalFrame.size.height);
[self.displayField.attributedText drawInRect:adjustedFrame];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
self.imageToUpload = newImage;
UIGraphicsEndImageContext();
return self.imageToUpload;
}
Most of the times the attributed only shows one line or two in the generated image. It may very likely have something to do with the frame. I am simply confused by the fact that the attributed string displays nicely in the label and differently when I draw it.
Any help with having the attributedString drawn correctly will be greatly appreciated.
when you start a picture, you start a new context in which you draw.
the Context is the image and 0,0 is the images corner.
so you have to adjust your originalFrame to take into account that you're now no longer drawing into view's context but into the image's context
I have a UIImage (called image) that i want to merge with another UIView (called overlayView), that contains different subviews eg. UILabels, UIImageViews and so on, to make a new UIImage (called mergedImage). Here's my code until now:
-(UIImage *) mergeViewWithImage: (UIImage *) image{
//The mergedImage need to be the same size as the image
UIGraphicsBeginImageContext(image.size);
//I'm doing this to get the layer, when i renderInContext, other ways?
UIImageView *temp = [[UIImageView alloc] initWithImage:image];
//This is working, the view gets its new frame, but the subviews won't scale up
[overlayView setFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
[temp.layer renderInContext:UIGraphicsGetCurrentContext()];
[overlayView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *mergedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//Need to set the frame to the initial one
[overlayView setFrame:CGRectMake(0, 0, 320, 320)];
return mergedImage;
}
This screenshot is what I really want it to look like
what you see is a AVCaptureVideoPreviewLayer (320*320), in the square, and I have a UIView, called overlayView (320*320), on top. When i press the "Take"-button, I do certain scaling, cropping and so on with the AVCaptureStillImageOutput, then i run the mergeViewWithImage-method. At this point the image is 968*968, but the overlayView is still 320*320 (has a blue boarder, just to know where it is). When I setFrame: to the overlayView, the the subviews, eg. the example-image of Luca Toni in the left lower corner doesn't scale, as you see in this screenshot
This is what i get
So you see, the background image (a white wall) stays the same, and the overlayView did resize, but the image of Luca Toni is much smaller, it wont scale... Please, help.
I've tried a lot of things, like setting this:
//imageOne is the picture with Luca Toni...
[[overlayView imageOne] setAutoresizingMask: UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
The overlayView is made in the Interface Builder as a .xib, which is a UIView with a UIImageVIew (imageOne), and has its own UIVIew custom class (nothing here yet, only the reference to imageOne (Luca Toni)). The overlayView is initiated in the MainViewController, like this:
[self overlayView:[[OverlayView alloc] init]];
overlayView = [[[NSBundle mainBundle] loadNibNamed:#"OverlayView" owner:self options:nil] objectAtIndex:0];
and added to the main view like this:
[[self view] addSubview:overlayView];
I have a set of images facing one side(Man facing right side), and I'm flipping it using this method and then adding it into a uiimageview's animationImages. However after adding in the flipped images, and then start to animate, the animation is still facing the right side.
manRunAnimations = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
NSArray *manAniRunArray = #[[UIImage imageNamed:#"robot1"],
[UIImage imageNamed:#"robot2"],
[UIImage imageNamed:#"robot3"],
[UIImage imageNamed:#"robot4"],
[UIImage imageNamed:#"robot5"],
[UIImage imageNamed:#"robot6"],
];
manRunAnimationsf = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 64, 64)];
NSMutableArray *flippedRunAnimationImages = [[NSMutableArray alloc] init];
for( UIImage *image in manAniRunArray)
{
UIImage * flippedImage = [UIImage imageWithCGImage:image.CGImage scale:image.scale orientation:UIImageOrientationRightMirrored];
[flippedRunAnimationImages addObject:flippedImage];
}
manRunAnimationsf.animationImages = (NSArray *)flippedRunAnimationImages;
testImgView.image = [manRunAnimationsf.animationImages objectAtIndex:0];
manRunAnimationsf.animationDuration = runAnimationSpeedSlider.value;
[manRunAnimationsf startAnimating];
I've even tested it using
testImgView.image = [manRunAnimationsf.animationImages objectAtIndex:5];
This would display one of the flipped images properly on screen just before I do a
[manRunAnimationsf startAnimating];
Once it starts, the animations are not flipped at all!!
Anyone know why?
I can't believe no one knows why, but I found way around it. Is to add the following before I startAnimating:
manRunAnimationsf.transform = CGAffineTransformMake(-1,0,0,1,0,0);
I didn't even need to do the CGImage flips in that for loop.
But the manual image flip should have worked with the imageWithCGImage method, and I really want to know why!! You guys disappoint me. :p