Why the image is rotated , by calling CGContextDrawImage.Thanks for your help.
// Initialization code
UIImage *img = [UIImage imageNamed:#"logo.png"];
UIImagePNGRepresentation(img);
_image_ref = img.CGImage;
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect img_rect = CGRectMake(20, 40, 100, 150);
CGContextDrawImage(context, img_rect, _image_ref);
core graphics's coordinated system not like UIKit, you need to calculate the right coordinate.
http://blog.ddg.com/?p=10
Following this explanation. I created solution which allow to draw multiple images with custom rects in one context.
func foo() -> UIImage? {
let image = UIImage(named: "back.png")!
let contextSize = CGSize(width: 500, height: 500)
UIGraphicsBeginImageContextWithOptions(contextSize, true, image.scale)
guard let ctx = UIGraphicsGetCurrentContext() else { return nil }
guard let cgImage = image.cgImage else { return nil}
//Start code which can by copy/paste
let imageRect = CGRect(origin: CGPoint(x: 200.0, y: 200.0), size: image.size) //custom rect
let ty = imageRect.origin.y + imageRect.size.height //calculate translation Y
let imageRectWithoutOriginY = CGRect(origin: CGPoint(x: imageRect.origin.x, y: 0), size: imageRect.size)
ctx.translateBy(x: 0.0, y: ty) //prepare context for custom rect
ctx.scaleBy(x: 1.0, y: -1.0)
ctx.draw(cgImage, in: imageRectWithoutOriginY) //draw image
ctx.translateBy(x: 0.0, y:-ty) //restore default context setup (so you can select new area to place another image)
ctx.scaleBy(x: 1.0, y: -1.0)
//End code which can by copy/paste
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result
}
Example with to images:
I know that it can be refactored. I duplicated code for more clarity.
Related
I am trying to crop my image using UIBezierPath (the user draw the path) I want the path area to be removed from the UIImage, I have this code implementation but the cut is not working in the path area
let originalImage = treaCameraImage!
UIGraphicsBeginImageContext(originalImage.size)
originalImage.draw(at: .zero)
let context = UIGraphicsGetCurrentContext()
context!.addPath(path.cgPath)
context!.clip()
context!.setFillColor(UIColor.red.cgColor)
context!.clear(CGRect(x: 0, y: 0, width: originalImage.size.width, height: originalImage.size.width))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
imageCut.image = newImage
Well for the solution you need first add this code in the viewDidAppear
override func viewDidAppear(_ animated: Bool) {
//Implemented to overcome trackerview problem(UIBreizerPath is not correct) when working direcly on an image bigger than the screen(For brackets cut image).
if (self.treaCameraImage!.size.width != self.view.bounds.size.width || self.treaCameraImage!.size.height != self.view.bounds.size.width) {
UIGraphicsBeginImageContext(self.imageCut.bounds.size);
let context = UIGraphicsGetCurrentContext()
if let context = context {
imageCut.layer.render(in: context)
}
let screenShot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
self.treaCameraImage = screenShot;
//self.tempOriginalImage = screenShot;
}
}
The treaCameraImage is the default image and imageCut is the image container
In my method to cut the image i changed:
context!.clear(CGRect(x: 0, y: 0, width: originalImage.size.width, height: originalImage.size.width))
to this:
context!.clear(CGRect(x: 0, y: 0, width: originalImage.size.width * 2, height: originalImage.size.width * 2))
and that works for me!
I have a code that adds an outline of the required width and color to an image and it works well
But I still need to adjust the rounding for the contour, please tell me in which direction should I start?
There are two functions here that do the job of laying the outline.
func colorized(with color: UIColor = .white) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, false, scale)
defer {
UIGraphicsEndImageContext()
}
guard let context = UIGraphicsGetCurrentContext(), let cgImage = cgImage else { return self }
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
color.setFill()
context.translateBy(x: 0, y: size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.clip(to: rect, mask: cgImage)
context.fill(rect)
guard let colored = UIGraphicsGetImageFromCurrentImageContext() else { return self }
return colored
}
/**
Returns the stroked version of the fransparent image with the given stroke color and the thickness.
- Parameters:
- color: The colors to user. By defaut, uses the ``UIColor.white`
- thickness: the thickness of the border. Default to `2`
- quality: The number of degrees (out of 360): the smaller the best, but the slower. Defaults to `10`.
- Returns: the stroked version of the image, or self if something was wrong
*/
func stroked(with color: UIColor = .red, thickness: CGFloat = 2, quality: CGFloat = 10) -> UIImage {
guard let cgImage = cgImage else { return self }
// Colorize the stroke image to reflect border color
let strokeImage = colorized(with: color)
guard let strokeCGImage = strokeImage.cgImage else { return self }
/// Rendering quality of the stroke
let step = quality == 0 ? 10 : abs(quality)
let oldRect = CGRect(x: thickness, y: thickness, width: size.width, height: size.height).integral
let newSize = CGSize(width: size.width + 2 * thickness, height: size.height + 2 * thickness)
let translationVector = CGPoint(x: thickness, y: 0)
UIGraphicsBeginImageContextWithOptions(newSize, false, scale)
guard let context = UIGraphicsGetCurrentContext() else { return self }
defer {
UIGraphicsEndImageContext()
}
context.translateBy(x: 0, y: newSize.height)
context.scaleBy(x: 1.0, y: -1.0)
context.interpolationQuality = .high
for angle: CGFloat in stride(from: 0, to: 360, by: step) {
let vector = translationVector.rotated(around: .zero, byDegrees: angle)
let transform = CGAffineTransform(translationX: vector.x, y: vector.y)
context.concatenate(transform)
context.draw(strokeCGImage, in: oldRect)
let resetTransform = CGAffineTransform(translationX: -vector.x, y: -vector.y)
context.concatenate(resetTransform)
}
context.draw(cgImage, in: oldRect)
guard let stroked = UIGraphicsGetImageFromCurrentImageContext() else { return self }
return stroked
}
I tried many options but most of the answers are just adding a conerRadius to the UIImageView (this doesn't work)
I'm trying to make function that will take text from a textfield (textField) and draw it onto an image. The function at the moment can only change the drawing's coordinates x and y, and width and height. What I was wondering is how I can make the text be drawn at an angle (eg 45˚, 18˚, etc...)
Thanks in advance.
func drawText() {
let font = UIFont.boldSystemFont(ofSize: 30)
let showText:NSString = textField.text as! NSString
// setting attr: font name, color...etc.
let attr = [NSFontAttributeName: font, NSForegroundColorAttributeName:UIColor.white]
// getting size
let sizeOfText = showText.size(attributes: attr)
let image = UIImage(named: "image")!
let rect = CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height)
UIGraphicsBeginImageContextWithOptions(CGSize(width: rect.size.width, height: rect.size.height), true, 0)
// drawing our image to the graphics context
image.draw(in: rect)
// drawing text
showText.draw(in: CGRect(x: rect.size.width-sizeOfText.width-10, y: rect.size.height-sizeOfText.height-10, width: rect.size.width, height: rect.size.height), withAttributes: attr)
// getting an image from it
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()
self.imageView.image = newImage
}
1.Draw text to an image first, then rotate the image.
2.Draw rotated image(with text) onto the background image.
//First create the rotated and transparent image with text
UIGraphicsBeginImageContextWithOptions(CGSize(width: rect.size.width, height: rect.size.height), false, 0)
if let context = UIGraphicsGetCurrentContext() {
context.rotate (by: 45.0 * CGFloat.pi/180.0) //45˚
}
showText.draw(in: CGRect(x: 10, y: 10, width: rect.size.width, height: rect.size.height), withAttributes: attr)
let rotatedImageWithText = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()
//Then, draw rotated image(with text) onto the background image
UIGraphicsBeginImageContextWithOptions(CGSize(width: rect.size.width, height: rect.size.height), true, 0)
image.draw(in: rect)
rotatedImageWithText?.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext()
self.imageView.image = newImage
I'm drawing image with core graphics than i want to use it like a mask for another image, but just getting clear rectangular image.
take a look whats wrong with my cropping function ?
UIGraphicsBeginImageContext(CGSizeMake(self.bounds.size.width / 0.5, self.bounds.size.height / 0.5))
let imageCtx = UIGraphicsGetCurrentContext()
CGContextAddArc(imageCtx, CGFloat(self.frame.size.width ) , CGFloat(self.frame.size.height ), 158, 0, CGFloat(DegreesToRadians(Double(angle))) , 0)
CGContextSetLineWidth(imageCtx, 80)
CGContextDrawPath(imageCtx, .Stroke)
let myMask :CGImageRef = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext())!
UIGraphicsEndImageContext()
let maskImage = UIImage(CGImage: myMask)
let testVideoPreview = UIImage(named: "alex")
guard let makedImage = testVideoPreview else {return}
var imageMaskOne: CGImageRef = CGImageMaskCreate(CGImageGetWidth(myMask), CGImageGetHeight(myMask), CGImageGetBitsPerComponent(myMask), CGImageGetBitsPerPixel(myMask), CGImageGetBytesPerRow(myMask), CGImageGetDataProvider(myMask), nil, // Decode is null
true)!
let masked: CGImageRef = CGImageCreateWithMask(makedImage.CGImage, imageMaskOne)!
//Finished
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 350, height: 350))
imageView.image = UIImage(CGImage: masked)
self.addSubview(imageView)
If you just need to create a crop at a specific coordinates there is an easier way CGImageCreateWithImageInRect
func CGImageCreateWithImageInRect(_ image: CGImage?, _ rect: CGRect) -> CGImage?
Here the documentation.
I've a UIImageView with a image with is a car with a transparent background:
And I want to draw a border around the car:
How can I reach this effect?
At the moment, I've tested CoreGraphics in this way, but without good results:
// load the image
UIImage *img = carImage;
UIGraphicsBeginImageContext(img.size);
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor redColor] setFill];
CGContextTranslateCTM(context, 0, img.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
CGContextSetBlendMode(context, kCGBlendModeNormal);
CGRect rect = CGRectMake(0, 0, img.size.width * 1.1, img.size.height*1.1);
CGContextDrawImage(context, rect, img.CGImage);
CGContextClipToMask(context, rect, img.CGImage);
CGContextAddRect(context, rect);
CGContextDrawPath(context,kCGPathFill);
// generate a new UIImage from the graphics context we drew onto
UIImage *coloredImg = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Any help? Thanks.
Here's what I did:
I did it in Swift just to check it in playgrounds, think you can translate it to Objective-C easily:
import UIKit
func drawOutlie(#image:UIImage, color:UIColor) -> UIImage
{
var newImageKoef:CGFloat = 1.08
var outlinedImageRect = CGRect(x: 0.0, y: 0.0, width: image.size.width * newImageKoef, height: image.size.height * newImageKoef)
var imageRect = CGRect(x: image.size.width * (newImageKoef - 1) * 0.5, y: image.size.height * (newImageKoef - 1) * 0.5, width: image.size.width, height: image.size.height)
UIGraphicsBeginImageContextWithOptions(outlinedImageRect.size, false, newImageKoef)
image.drawInRect(outlinedImageRect)
var context = UIGraphicsGetCurrentContext()
CGContextSetBlendMode(context, kCGBlendModeSourceIn)
CGContextSetFillColorWithColor(context, color.CGColor)
CGContextFillRect(context, outlinedImageRect)
image.drawInRect(imageRect)
var newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
var imageIn = UIImage(named: "158jM")
var imageOut = drawOutlie(image: imageIn, UIColor.redColor())
So how does it work?
We create clean context (aka canvas) with a bit bigger size then original image (for outline)
We draw our image on whole canvas
We fill that image with color
We draw smaller image on top
You can change outline size changing this property : var newImageKoef:CGFloat = 1.08
Here's a result that I had in playgrounds
Swift 5:
extension UIImage {
func drawOutline(imageKeof: CGFloat = 0.2, color: UIColor = .white)-> UIImage? {
let outlinedImageRect = CGRect(x: 0.0, y: 0.0, width: size.width * imageKeof, height: size.height * imageKeof)
let imageRect = CGRect(x: self.size.width * (imageKeof - 1) * 0.5, y: self.size.height * (imageKeof - 1) * 0.5, width: size.width, height: size.height)
UIGraphicsBeginImageContextWithOptions(outlinedImageRect.size, false, imageKeof)
draw(in: outlinedImageRect)
let context = UIGraphicsGetCurrentContext()
context!.setBlendMode(.sourceIn)
context!.setFillColor(color.cgColor)
context!.fill(outlinedImageRect)
draw(in: imageRect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
haawa answer for Swift 5
extension UIImage {
func drawOutlie(imageKeof: CGFloat = 1.01, color: UIColor) -> UIImage? {
let outlinedImageRect = CGRect(x: 0.0, y: 0.0,
width: size.width * imageKeof,
height: size.height * imageKeof)
let imageRect = CGRect(x: size.width * (imageKeof - 1) * 0.5,
y: size.height * (imageKeof - 1) * 0.5,
width: size.width,
height: size.height)
UIGraphicsBeginImageContextWithOptions(outlinedImageRect.size, false, imageKeof)
draw(in: outlinedImageRect)
guard let context = UIGraphicsGetCurrentContext() else {return nil}
context.setBlendMode(.sourceIn)
context.setFillColor(color.cgColor)
context.fill(outlinedImageRect)
draw(in: imageRect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
This approach is a little bit different but more simple.
imageView.layer.shadowColor = UIColor.red.cgColor
imageView.layer.shadowOffset = CGSize(width: 0, height: 0)
imageView.layer.shadowOpacity = 1
imageView.layer.shadowRadius = 10.0
imageView.clipsToBounds = false