In an iPhone app, I wrote some code to resize an image taken from the photo album, in order to use it as background for the app.
The code is strongly inspired from what I could find looking on the net. Namely here:
http://forrst.com/posts/UIImage_simple_resize_and_crop_image-sUG#comment-land
It works fine on the simulator. But it looks like no resizing at all is happening on the device. Why is that? Any idea?
Thank you for any tip.
hi Michel.
i dont know more about your code but i am using this code you can try
this you will find your solution.
here you need to pass image and the required width and height for
that image in this function and you will get another image with that
new size.
-(UIImage *)resizeImage:(UIImage *)image3 width:(int)width height:(int)height {
CGImageRef imageRef = [image3 CGImage];
CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef);
//if (alphaInfo == kCGImageAlphaNone)
alphaInfo = kCGImageAlphaNoneSkipLast;
CGContextRef bitmap = CGBitmapContextCreate(NULL, width, height, CGImageGetBitsPerComponent(imageRef), 4 * width, CGImageGetColorSpace(imageRef), alphaInfo);
CGContextDrawImage(bitmap, CGRectMake(0, 0, width, height), imageRef);
CGImageRef ref = CGBitmapContextCreateImage(bitmap);
UIImage *result = [UIImage imageWithCGImage:ref];
CGContextRelease(bitmap);
CGImageRelease(ref);
return result;
}
Related
I am new to FreeImage. I just want to read an JPEG image and display it in my MFC dialog. How do I do that? I try that using ImageStone by doing:
img.Load(blob.data, size, IMG_JPG);
img.Draw(hdc, DC);
Now, how do I do the same thing using FreeImage?
I tried and it worked exactly the way you described.... I used SHCreateMemStream and fed the stream to the overloaded LOAD method of CImage. Everything worked perfectly.
Thank you so much,
Makoto
CImage im;
IStream* is = SHCreateMemStream(Blob.pData, nSize);
HRESULT hr = im.Load(is);
RECT rect = { 0, 0, 500, 500 };
BOOL b = im.Draw(hdc, rect);
My ImageView is matching screen size on x-axis and is using remaining space on y-axis in my layout. I want to create bitmap into this ImageView with exactly the same size as the ImageView is. How to make it please? Can it be done by some automatic setting, should I call some measure function?
I tried SetAdjustViewBounds() but it didn't work for me.
Creating Bitmap big enough (I don't like much such a memory wasting) and setting SetScaleType(ImageView.ScaleType.Matrix) works, but still when I'm making drawing operations on canvas, I don't know real size of area I should paint into, both canvas and bitmap height are equal to yScreen while imgWeekView height is pretending to be 0, even though it paints whole desired area with gray color.
imgWeekView = new ImageView(context);
//imgWeekView.SetAdjustViewBounds(true);
imgWeekView.SetScaleType(ImageView.ScaleType.Matrix);
layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MatchParent, LinearLayout.LayoutParams.WrapContent,1f);
layoutParams.Height = 0;
imgWeekView.LayoutParameters = layoutParams;
Bitmap bitmap = Bitmap.CreateBitmap((int)xScreen, (int)yScreen, Bitmap.Config.Argb8888);
cnvWeekView = new Canvas(bitmap);
imgWeekView.SetImageBitmap(bitmap);
linearLayout.AddView(imgWeekView); //whole activity layout
//Test
cnvWeekView.DrawColor(new Color(128, 128, 128));
Paint paint = new Paint(PaintFlags.AntiAlias);
paint.Color = new Color(255, 255,0);
cnvWeekView.DrawCircle(50, 50, 40, paint);
Finally I found a way how to measure my ImageView and here I will post my answer.
I believed that there should be much easier solution, but maybe there isn't. From this question I took most of the important data:
How to get the width and height of an android.widget.ImageView?
Things look however a little different in my android application and I'm not experienced enough to tell why. I had to change things a little. I had to learn a bit about interfaces and this question helped too.
Implementing the View.IOnTouchListener interface
Here is how I combined things. First I created class that will do the measure.
public class MyPredrawListener : Java.Lang.Object, ViewTreeObserver.IOnPreDrawListener
{
ImageView imageView;
public MyPredrawListener(ImageView img)
{
imageView = img;
}
public bool OnPreDraw()
{
imageView.ViewTreeObserver.RemoveOnPreDrawListener(this);
int finalHeight = imageView.MeasuredHeight;
int finalWidth = imageView.MeasuredWidth;
Bitmap bitmap = Bitmap.CreateBitmap(finalWidth, finalHeight, Bitmap.Config.Argb8888);
imageView.SetImageBitmap(bitmap);
//Test to see result
Canvas cnv = new Canvas(bitmap);
Paint paint = new Paint();
paint.Color = new Color(255, 255, 0);
cnv.DrawColor(new Color(128, 128, 128));
cnv.DrawCircle(finalWidth-50, finalHeight-50, 50, paint);
return true;
}
}
And in code where I create my imageView I set the listener like this.
imgWeekView = new ImageView(context);
MyPredrawListener listener=new MyPredrawListener(imgWeekView);
imgWeekView.ViewTreeObserver.AddOnPreDrawListener(listener);
In OnPreDraw function I put test code to see the result graphically, clearing bitmap to gray color and painting yellow circle to bottom right of a view.
I'm getting crazy while trying to merge two UIImageView.
The situation:
a background UIImageView
(userPhotoImageView)
an overlayed
UIImageView (productPhotoImageView)
that can be streched, pinched and
rotated
I call my function on the UIImages but I can take coords and new stretched size from the UIImageView containing them (they are synthesized in my class)
- (UIImage *)mergeImage:(UIImage *)bottomImg withImage:(UIImage *)topImg;
Maybe simplest way would be rendering the layer of the top UIImageView in a the new CGContextRef like this:
[bottomImg drawInRect:CGRectMake(0, 0, bottomImg.size.width, bottomImg.size.height)];
[productPhotoImageView.layer renderInContext:ctx];
But in this way I loose the rotation effect previosly applied by gestures.
A second way would be trying to apply AffineTransformation to UIImage to reproduce GestureEffects and then draw it in the context like this:
UIImage * scaledTopImg = [topImg imageByScalingProportionallyToSize:productPhotoView.frame.size];
UIImage * rotatedScaledTopImg = [scaledTopImg imageRotatedByDegrees:ANGLE];
[rotatedScaledTopImg drawAtPoint:CGPointMake(productPhotoView.frame.origin.x, productPhotoView.frame.origin.y)];
The problem of this second approach is that I'm not able to exactly get the final rotation degrees (the ANGLE parameter that should be filled in the code above) amount since the user started to interact, this because the RotationGesture is reset to 0 after applying so the next callback is a delta from the current rotation.
For sure the most easy way would be the first one, freezing the two UIImageViews as they are displayed in that very moment but actually I still didn't find anyway to do it.
Ok basically there is another workaround for all this crazy merging stuff, but it's definitively not an elegant solution. For avoid handling any kind of AffineTransformation just capture the ImageScreen and then crop it.
CGImageRef screenImage = UIGetScreenImage();
CGRect fullRect = [[UIScreen mainScreen] applicationFrame];
CGImageRef saveCGImage = CGImageCreateWithImageInRect(screenImage, fullRect);
CGRect cropRect = CGRectMake(x,y,width,height);
CGImageRef saveCGImage = CGImageCreateWithImageInRect(screenImage, cropRect);
Told you it wasnt elegant, but for someone it could be useful.
Great that was helpful and so too much workaroundy ;)
so since i see it's pretty hard to find around some code examples to merge pics after a manipulation here goes mine, hope it can be helpful:
- (UIImage *)mergeImage:(UIImage *)bottomImg withImage:(UIImage *)topImg {
UIImage * scaledTopImg = [topImg imageByScalingProportionallyToSize:productPhotoView.frame.size];
UIGraphicsBeginImageContext(scaledTopImg.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, scaledTopImg.size.width * 0.5f, scaledTopImg.size.height * 0.5f);
CGFloat angle = atan2(productPhotoView.transform.b, productPhotoView.transform.a);
CGContextRotateCTM(ctx, angle);
[scaledTopImg drawInRect:CGRectMake(- scaledTopImg.size.width * 0.5f, -(scaledTopImg.size.height * 0.5f), scaledTopImg.size.width, scaledTopImg.size.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIGraphicsBeginImageContext(bottomImg.size);
[bottomImg drawInRect:CGRectMake(0, 0, bottomImg.size.width, bottomImg.size.height)];
[newImage drawInRect:CGRectMake(productPhotoView.frame.origin.x, productPhotoView.frame.origin.y, newImage.size.width, newImage.size.height)];
UIImage *newImage2 = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage2;
}
Since I got a background image it was easier first create a context just to apply tranformation to the overlayview, than save it and write on top of the bottom layer.
Take care of the CTM translation before rotating the overlayview or it will rotate around an axis placed at {0,0} while I want to rotate my image around its center.
Regards
I have the same problem.
I only have problem with rotation.
I use gesture recognizers for move, scale and rotation.
At the beginning when I save the image tha scale was right, the position was right but never apply rotation to the saved image.
Now it works
if you want to know the rotation angle I get it with:
CGFloat angle = atan2(overlay.transform.b, overlay.transform.a);
And rotation with:
CGContextRotateCTM(context, angle);
If you have a different approach please let me know.
I'm able to set the MKPinAnnotationView with title, subtitle, an image on the left (leftCalloutAccessoryView) and a button on the right (rightCalloutAccessoryView).
With this code i set the image on the left:
UIImageView *myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Icon.png"]];
myImageView.frame = CGRectMake(0, 0, 10, 10);
customPinView.leftCalloutAccessoryView = myImageView;
[myImageView release], myImageView = nil;
The result is something like this:
Image 1
but I would like to get something like this:
Image 2
where the image is aligned with the subtitle.
How can get it?
Thx.
That's going to require using a custom annotationView. There's plenty of documentation about this in the developer resources. There's no way to do that image alignment using the default annotation style.
I've made a CALayer with an added CATextLayer and the text comes out blurry. In the docs, they talk about "sub-pixel antialiasing", but that doesn't mean much to me. Anyone have a code snippet that makes a CATextLayer with a bit of text that is clear?
Here's the text from Apple's documentation:
Note: CATextLayer disables sub-pixel antialiasing when rendering text.
Text can only be drawn using sub-pixel antialiasing when it is
composited into an existing opaque background at the same time that
it's rasterized. There is no way to draw subpixel-antialiased text by
itself, whether into an image or a layer, separately in advance of
having the background pixels to weave the text pixels into. Setting
the opacity property of the layer to YES does not change the rendering
mode.
The second sentence implies that one can get good looking text if one composites it into an existing opaque background at the same time that it's rasterized. That's great, but how do I composite it and how do you give it an opaque background and how do you rasterize it?
The code they use in their example of a Kiosk Menu is as such: (It's OS X, not iOS, but I assume it works!)
NSInteger i;
for (i=0;i<[names count];i++) {
CATextLayer *menuItemLayer=[CATextLayer layer];
menuItemLayer.string=[self.names objectAtIndex:i];
menuItemLayer.font=#"Lucida-Grande";
menuItemLayer.fontSize=fontSize;
menuItemLayer.foregroundColor=whiteColor;
[menuItemLayer addConstraint:[CAConstraint
constraintWithAttribute:kCAConstraintMaxY
relativeTo:#"superlayer"
attribute:kCAConstraintMaxY
offset:-(i*height+spacing+initialOffset)]];
[menuItemLayer addConstraint:[CAConstraint
constraintWithAttribute:kCAConstraintMidX
relativeTo:#"superlayer"
attribute:kCAConstraintMidX]];
[self.menuLayer addSublayer:menuItemLayer];
} // end of for loop
Thanks!
EDIT: Adding the code that I actually used that resulted in blurry text. It's from a related question I posted about adding a UILabel rather than a CATextLayer but getting a black box instead. http://stackoverflow.com/questions/3818676/adding-a-uilabels-layer-to-a-calayer-and-it-just-shows-black-box
CATextLayer* upperOperator = [[CATextLayer alloc] init];
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGFloat components1[4] = {1.0, 1.0, 1.0, 1.0};
CGColorRef almostWhite = CGColorCreate(space,components1);
CGFloat components2[4] = {0.0, 0.0, 0.0, 1.0};
CGColorRef almostBlack = CGColorCreate(space,components2);
CGColorSpaceRelease(space);
upperOperator.string = [NSString stringWithFormat:#"13"];
upperOperator.bounds = CGRectMake(0, 0, 100, 50);
upperOperator.foregroundColor = almostBlack;
upperOperator.backgroundColor = almostWhite;
upperOperator.position = CGPointMake(50.0, 25.0);
upperOperator.font = #"Helvetica-Bold";
upperOperator.fontSize = 48.0f;
upperOperator.borderColor = [UIColor redColor].CGColor;
upperOperator.borderWidth = 1;
upperOperator.alignmentMode = kCAAlignmentCenter;
[card addSublayer:upperOperator];
[upperOperator release];
CGColorRelease(almostWhite);
CGColorRelease(almostBlack);
EDIT 2: See my answer below for how this got solved. sbg.
Short answer — You need to set the contents scaling:
textLayer.contentsScale = [[UIScreen mainScreen] scale];
A while ago I learned that when you have custom drawing code, you have to check for the retina display and scale your graphics accordingly. UIKit takes care of most of this, including font scaling.
Not so with CATextLayer.
My blurriness came from having a .zPosition that was not zero, that is, I had a transform applied to my parent layer. By setting this to zero, the blurriness went away, and was replaced by serious pixelation.
After searching high and low, I found that you can set .contentsScale for a CATextLayer and you can set it to [[UIScreen mainScreen] scale] to match the screen resolution. (I assume this works for non-retina, but I haven't checked - too tired)
After including this for my CATextLayer the text became crisp. Note - it's not necessary for the parent layer.
And the blurriness? It comes back when you're rotating in 3D, but you don't notice it because the text starts out clear and while it's in motion, you can't tell.
Problem solved!
Swift
Set the text layer to use the same scale as the screen.
textLayer.contentsScale = UIScreen.main.scale
Before:
After:
Before setting shouldRasterize, you should:
set the rasterizationScale of the base layer you are going to rasterize
set the contentsScale property of any CATextLayers and possibly other types of layers(it never hurts to do it)
If you don't do #1, then the retina version of sub layers will look blurry, even for normal CALayers.
- (void)viewDidLoad {
[super viewDidLoad];
CALayer *mainLayer = [[self view] layer];
[mainLayer setRasterizationScale:[[UIScreen mainScreen] scale]];
CATextLayer *messageLayer = [CATextLayer layer];
[messageLayer setForegroundColor:[[UIColor blackColor] CGColor]];
[messageLayer setContentsScale:[[UIScreen mainScreen] scale]];
[messageLayer setFrame:CGRectMake(50, 170, 250, 50)];
[messageLayer setString:(id)#"asdfasd"];
[mainLayer addSublayer:messageLayer];
[mainLayer setShouldRasterize:YES];
}
First off I wanted to point out that you've tagged your question with iOS, but constraint managers are only available on OSX, so I'm not sure how you're getting this to work unless you've been able to link against it in the simulator somehow. On the device, this functionality is not available.
Next, I'll just point out that I create CATextLayers often and never have the blurring problem you're referring to so I know it can be done. In a nutshell this blurring occurs because you are not positioning your layer on the whole pixel. Remember that when you set the position of a layer, you use a float values for the x and y. If those values have numbers after the decimal, the layer will not be positioned on the whole pixel and will therefore give this blurring effect--the degree of which depending upon the actual values. To test this, just create a CATextLayer and explicitly add it to the layer tree ensuring that your position parameter is on a whole pixel. For example:
CATextLayer *textLayer = [CATextLayer layer];
[textLayer setBounds:CGRectMake(0.0f, 0.0f, 200.0f, 30.0f)];
[textLayer setPosition:CGPointMake(200.0f, 100.0f)];
[textLayer setString:#"Hello World!"];
[[self menuLayer] addSublayer:textLayer];
If your text is still blurry, then there is something else wrong. Blurred text on your text layer is an artifact of incorrectly written code and not an intended capability of the layer. When adding your layers to a parent layer, you can just coerce the x and y values to the nearest whole pixel and it should solve your blurring problem.
You should do 2 things, the first was mentioned above:
Extend CATextLayer and set the opaque and contentsScale properties to properly support retina display, then render with anti aliasing enabled for text.
+ (TextActionLayer*) layer
{
TextActionLayer *layer = [[TextActionLayer alloc] init];
layer.opaque = TRUE;
CGFloat scale = [[UIScreen mainScreen] scale];
layer.contentsScale = scale;
return [layer autorelease];
}
// Render after enabling with anti aliasing for text
- (void)drawInContext:(CGContextRef)ctx
{
CGRect bounds = self.bounds;
CGContextSetFillColorWithColor(ctx, self.backgroundColor);
CGContextFillRect(ctx, bounds);
CGContextSetShouldSmoothFonts(ctx, TRUE);
[super drawInContext:ctx];
}
If you came searching here for a similar issue for a CATextLayer in OSX, after much wall head banging, I got the sharp clear text by doing:
text_layer.contentsScale = self.window!.backingScaleFactor
(I also set the views background layer contentsScale to be the same).
This is faster and easier: you just need to set contentsScale
CATextLayer *label = [[CATextLayer alloc] init];
[label setFontSize:15];
[label setContentsScale:[[UIScreen mainScreen] scale]];
[label setFrame:CGRectMake(0, 0, 50, 50)];
[label setString:#"test"];
[label setAlignmentMode:kCAAlignmentCenter];
[label setBackgroundColor:[[UIColor clearColor] CGColor]];
[label setForegroundColor:[[UIColor blackColor] CGColor]];
[self addSublayer:label];