Площадь посевного центра UIImage
Итак, здесь, где я сделал это до сих пор. Я использую UIImage, захваченный с камеры, и могу обрезать квадрат центра, когда он находится в ландшафте. По какой-то причине это не переводится в портретный режим, как ожидалось. Я отправлю свой код и журналы только для справки.
код:
CGRect squareRect = CGRectMake(offsetX, offsetY, newWidth, newHeight);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], squareRect);
image = [UIImage imageWithCGImage:imageRef scale:1 orientation:image.imageOrientation];
Портретные результаты (не квадратные):
original image size: {1536, 2048}, with orientation: 3
squareRect: {{0, 256}, {1536, 1536}}
new image size: {1280, 1536}, with orientation: 3 <--- not expected
Пейзажные результаты (квадрат):
original image size: {2048, 1536}, with orientation: 1
squareRect: {{256, 0}, {1536, 1536}}
new image size: {1536, 1536}, with orientation: 1
Является ли это ошибкой внутри CGImageCreateWithImageInRect() или я что-то здесь не вижу?
Ответы
Ответ 1
Я думаю, что это было бы идеальным решением!
Не рекомендуется обрезать изображение на toSize
размере. Это будет выглядеть странно, когда разрешение изображения (размер) очень велико.
Следующий код обрезает изображение в соответствии с соотношением toSize
.
Улучшено от ответа @BlackRider.
- (UIImage *)imageByCroppingImage:(UIImage *)image toSize:(CGSize)size
{
double newCropWidth, newCropHeight;
//=== To crop more efficently =====//
if(image.size.width < image.size.height){
if (image.size.width < size.width) {
newCropWidth = size.width;
}
else {
newCropWidth = image.size.width;
}
newCropHeight = (newCropWidth * size.height)/size.width;
} else {
if (image.size.height < size.height) {
newCropHeight = size.height;
}
else {
newCropHeight = image.size.height;
}
newCropWidth = (newCropHeight * size.width)/size.height;
}
//==============================//
double x = image.size.width/2.0 - newCropWidth/2.0;
double y = image.size.height/2.0 - newCropHeight/2.0;
CGRect cropRect = CGRectMake(x, y, newCropWidth, newCropHeight);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);
UIImage *cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return cropped;
}
Ответ 2
Это работает с разными ориентациями. Как портретная, так и ландшафтная ориентации работают правильно.
- (UIImage *)imageByCroppingImage:(UIImage *)image toSize:(CGSize)size
{
// not equivalent to image.size (which depends on the imageOrientation)!
double refWidth = CGImageGetWidth(image.CGImage);
double refHeight = CGImageGetHeight(image.CGImage);
double x = (refWidth - size.width) / 2.0;
double y = (refHeight - size.height) / 2.0;
CGRect cropRect = CGRectMake(x, y, size.height, size.width);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);
UIImage *cropped = [UIImage imageWithCGImage:imageRef scale:0.0 orientation:self.imageOrientation];
CGImageRelease(imageRef);
return cropped;
}
Ответ 3
Основываясь на проверенном ответе Elmundo и его быстрой версии от Imbrue, вот то же самое решение, которое автоматически вычисляет размер центра изображения (с учетом ориентации) и с учетом ошибки:
func cropImageToSquare(image: UIImage) -> UIImage? {
var imageHeight = image.size.height
var imageWidth = image.size.width
if imageHeight > imageWidth {
imageHeight = imageWidth
}
else {
imageWidth = imageHeight
}
let size = CGSize(width: imageWidth, height: imageHeight)
let refWidth : CGFloat = CGFloat(CGImageGetWidth(image.CGImage))
let refHeight : CGFloat = CGFloat(CGImageGetHeight(image.CGImage))
let x = (refWidth - size.width) / 2
let y = (refHeight - size.height) / 2
let cropRect = CGRectMake(x, y, size.height, size.width)
if let imageRef = CGImageCreateWithImageInRect(image.CGImage, cropRect) {
return UIImage(CGImage: imageRef, scale: 0, orientation: image.imageOrientation)
}
return nil
}
версия Swift 3
func cropImageToSquare(image: UIImage) -> UIImage? {
var imageHeight = image.size.height
var imageWidth = image.size.width
if imageHeight > imageWidth {
imageHeight = imageWidth
}
else {
imageWidth = imageHeight
}
let size = CGSize(width: imageWidth, height: imageHeight)
let refWidth : CGFloat = CGFloat(image.cgImage!.width)
let refHeight : CGFloat = CGFloat(image.cgImage!.height)
let x = (refWidth - size.width) / 2
let y = (refHeight - size.height) / 2
let cropRect = CGRect(x: x, y: y, width: size.height, height: size.width)
if let imageRef = image.cgImage!.cropping(to: cropRect) {
return UIImage(cgImage: imageRef, scale: 0, orientation: image.imageOrientation)
}
return nil
}
Ответ 4
Попробуйте что-то вроде этого:
- (UIImage *)imageByCroppingImage:(UIImage *)image toSize:(CGSize)size
{
double x = (image.size.width - size.width) / 2.0;
double y = (image.size.height - size.height) / 2.0;
CGRect cropRect = CGRectMake(x, y, size.height, size.width);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);
UIImage *cropped = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
return cropped;
}
Как вы видите, я не указываю ориентацию в вызове UIImage imageWithCGImage:
. Интересно, что проблема в вашем коде.
Ответ 5
Существует быстрая версия для проверенного решения:
private func imageByCroppingImage(image : UIImage, size : CGSize) -> UIImage{
var refWidth : CGFloat = CGFloat(CGImageGetWidth(image.CGImage))
var refHeight : CGFloat = CGFloat(CGImageGetHeight(image.CGImage))
var x = (refWidth - size.width) / 2
var y = (refHeight - size.height) / 2
let cropRect = CGRectMake(x, y, size.height, size.width)
let imageRef = CGImageCreateWithImageInRect(image.CGImage, cropRect)
let cropped : UIImage = UIImage(CGImage: imageRef, scale: 0, orientation: image.imageOrientation)!
return cropped
}
Ответ 6
улучшено с ответа @Elmundo
+(UIImage *)getCenterMaxSquareImageByCroppingImage:(UIImage *)image withOrientation:(UIImageOrientation)imageOrientation
{
CGSize centerSquareSize;
double oriImgWid = CGImageGetWidth(image.CGImage);
double oriImgHgt = CGImageGetHeight(image.CGImage);
NSLog(@"oriImgWid==[%.1f], oriImgHgt==[%.1f]", oriImgWid, oriImgHgt);
if(oriImgHgt <= oriImgWid) {
centerSquareSize.width = oriImgHgt;
centerSquareSize.height = oriImgHgt;
}else {
centerSquareSize.width = oriImgWid;
centerSquareSize.height = oriImgWid;
}
NSLog(@"squareWid==[%.1f], squareHgt==[%.1f]", centerSquareSize.width, centerSquareSize.height);
double x = (oriImgWid - centerSquareSize.width) / 2.0;
double y = (oriImgHgt - centerSquareSize.height) / 2.0;
NSLog(@"x==[%.1f], x==[%.1f]", x, y);
CGRect cropRect = CGRectMake(x, y, centerSquareSize.height, centerSquareSize.width);
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect);
UIImage *cropped = [UIImage imageWithCGImage:imageRef scale:0.0 orientation:imageOrientation];
CGImageRelease(imageRef);
return cropped;
}
Ответ 7
Swift 2 с использованием расширения UIImage
extension UIImage
{
func imageByCroppingImage(size : CGSize) -> UIImage
{
let refWidth : CGFloat = CGFloat(CGImageGetWidth(self.CGImage))
let refHeight : CGFloat = CGFloat(CGImageGetHeight(self.CGImage))
let x = (refWidth - size.width) / 2
let y = (refHeight - size.height) / 2
let cropRect = CGRectMake(x, y, size.width, size.height)
let imageRef = CGImageCreateWithImageInRect(self.CGImage, cropRect)
let cropped : UIImage = UIImage(CGImage: imageRef!, scale: 0, orientation: self.imageOrientation)
return cropped
}
}
Ответ 8
Swift 3
let refWidth : CGFloat = CGFloat(image.cgImage!.width)
let refHeight : CGFloat = CGFloat(image.cgImage!.height)
let x = (refWidth - size.width) / 2
let y = (refHeight - size.height) / 2
let cropRect = CGRect(x: x, y: y, width: size.width, height: size.height)
let imageRef = image.cgImage!.cropping(to: cropRect)
let cropped : UIImage = UIImage(cgImage: imageRef!, scale: 0, orientation: image.imageOrientation)
return cropped
Ответ 9
Это старый вопрос, но ни один из ответов не является действительно правильным (даже принятый ответ). Важно понимать, что UIImageOrientation
(image.imageOrientation
) действительно корректно, но определение UP и наше определение UP отличаются. Для нас UP - это верхняя часть устройства (где кнопка питания). Для UIImageOrientation
, ВВЕРХ - это сторона, противоположная кнопкам регулировки громкости. Поэтому, если устройство делает снимок с помощью регуляторов громкости, это UIImageOrientationUp
. Если вы делаете снимок в портретном режиме (при нажатии кнопки "дом" ), это UIImageOrientationLeft
.
Итак, вы можете рассчитать центр в портрете, затем вы можете применить следующее преобразование к изображению, чтобы урожай был в правильном месте.
- (UIImage *)cropImage:(UIImage*)image toRect:(CGRect)rect {
CGFloat (^rad)(CGFloat) = ^CGFloat(CGFloat deg) {
return deg / 180.0f * (CGFloat) M_PI;
};
// determine the orientation of the image and apply a transformation to the crop rectangle to shift it to the correct position
CGAffineTransform rectTransform;
switch (image.imageOrientation) {
case UIImageOrientationLeft:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -image.size.height);
break;
case UIImageOrientationRight:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -image.size.width, 0);
break;
case UIImageOrientationDown:
rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -image.size.width, -image.size.height);
break;
default:
rectTransform = CGAffineTransformIdentity;
};
// adjust the transformation scale based on the image scale
rectTransform = CGAffineTransformScale(rectTransform, image.scale, image.scale);
// apply the transformation to the rect to create a new, shifted rect
CGRect transformedCropSquare = CGRectApplyAffineTransform(rect, rectTransform);
// use the rect to crop the image
CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, transformedCropSquare);
// create a new UIImage and set the scale and orientation appropriately
UIImage *result = [UIImage imageWithCGImage:imageRef scale:image.scale orientation:image.imageOrientation];
// memory cleanup
CGImageRelease(imageRef);
return result;
}
Этот код сдвигает квадрат обрезки так, чтобы он находился в правильном относительном положении.
Ответ 10
Это основано на ответе @Alonzo Swift 3, приведенном выше, с упрощенным и оптимизированным кодом, чтобы сделать его более понятным и лаконичным. Это также выручает, если изображение уже квадратное.
extension UIImage {
func square() -> UIImage? {
if size.width == size.height {
return self
}
let cropWidth = min(size.width, size.height)
let cropRect = CGRect(
x: (size.width - cropWidth) * scale / 2.0,
y: (size.height - cropWidth) * scale / 2.0,
width: cropWidth * scale,
height: cropWidth * scale
)
guard let imageRef = cgImage?.cropping(to: cropRect) else {
return nil
}
return UIImage(cgImage: imageRef, scale: scale, orientation: imageOrientation)
}
}
Ответ 11
как насчет получения помощи от UIImageView
+ (UIImage *)laodSquareImage:(UIImage *)image withDiameter:(CGFloat)diameter
{
CGRect frame = CGRectMake(0.0f, 0.0f, diameter, diameter);
UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
imageView.image = image;
CALayer *layer = imageView.layer;
layer.masksToBounds = YES;
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size,NO, [UIScreen mainScreen].scale);
CGContextRef context = UIGraphicsGetCurrentContext();
[layer renderInContext:context];
UIImage *roundedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return roundedImage;
}
И вы также можете сделать изображение круга, добавив только линию.
layer.cornerRadius =MAX( imageView.frame.size.height,imageView.frame.size.width)/2;
Ответ 12
уже есть много решений, но я хочу опубликовать мое:
extension UIImage {
var cgImageWidth: Int { return cgImage?.width ?? 0 }
var cgImageheight: Int { return cgImage?.height ?? 0 }
var blance: CGFloat { return min(size.width, size.height)}
var blanceSize: CGSize { return CGSize(width: blance, height: blance) }
var blanceRect: CGRect { return CGRect(origin: .zero, size: blanceSize) }
var roundedImage: UIImage? {
UIGraphicsBeginImageContextWithOptions(blanceSize, false, scale)
defer { UIGraphicsEndImageContext() }
guard let cgImage = cgImage?.cropping(to: CGRect(origin: CGPoint(x: max(0, CGFloat(cgImageWidth) - blance)/2.0, y: max(0, CGFloat(cgImageheight) - blance)/2.0), size: blanceSize)) else { return nil }
UIBezierPath(ovalIn: blanceRect).addClip()
UIImage(cgImage: cgImage, scale: 1.0, orientation: self.imageOrientation).draw(in: blanceRect)
return UIGraphicsGetImageFromCurrentImageContext()
}
}
Ответ 13
Xamarin:
UIImage ImageByCroppingImage(UIImage image, CGSize size)
{
double newCropWidth, newCropHeight;
if (image.Size.Width < image.Size.Height)
{
newCropWidth = image.Size.Width < size.Width ? size.Width : image.Size.Width;
newCropHeight = (newCropWidth * size.Height) / size.Width;
}
else
{
newCropHeight = image.Size.Height < size.Height ? size.Height : image.Size.Height;
newCropWidth = (newCropHeight * size.Width) / size.Height;
}
double x = image.Size.Width / 2.0 - newCropWidth / 2.0;
double y = image.Size.Height / 2.0 - newCropHeight / 2.0;
CGRect cropRect = new CGRect(x, y, newCropWidth, newCropHeight);
var imageRef = image.CGImage.WithImageInRect(cropRect);
var cropped = new UIImage(imageRef);
return cropped;
}
Ответ 14
Решение основано на расширении Swift 2. Импровизировано от @Geoffrey и @Nirav Dangi. Обратите внимание, что мы устанавливаем newCropWidth и newCropHeight в ширину или высоту изображения, когда они меньше заданной ширины или высоты.
extension UIImage {
func imageByCroppingImage(size: CGSize) -> UIImage {
let newCropWidth, newCropHeight : CGFloat;
if(self.size.width < self.size.height) {
if (self.size.width < size.width) {
newCropWidth = self.size.width;
}
else {
newCropWidth = size.width;
}
newCropHeight = (newCropWidth * size.height)/size.width;
} else {
if (self.size.height < size.height) {
newCropHeight = self.size.height;
}
else {
newCropHeight = size.height;
}
newCropWidth = (newCropHeight * size.width)/size.height;
}
let x = self.size.width / 2 - newCropWidth / 2;
let y = self.size.height / 2 - newCropHeight / 2;
let cropRect = CGRectMake(x, y, newCropWidth, newCropHeight);
let imageRef = CGImageCreateWithImageInRect(self.CGImage, cropRect);
let croppedImage : UIImage = UIImage(CGImage: imageRef!, scale: 0, orientation: self.imageOrientation);
return croppedImage;
}
}
Ответ 15
я имею дело со следующим
extension UIImage {
var cgImageWidth: Int { return cgImage?.width ?? 0 }
var cgImageheight: Int { return cgImage?.height ?? 0 }
var blance: CGFloat { return min(size.width, size.height)}
var blanceSize: CGSize { return CGSize(width: blance, height: blance) }
var blanceRect: CGRect { return CGRect(origin: .zero, size: blanceSize) }
var roundedImage: UIImage? {
UIGraphicsBeginImageContextWithOptions(blanceSize, false, scale)
defer { UIGraphicsEndImageContext() }
guard let cgImage = cgImage?.cropping(to: CGRect(origin: CGPoint(x: max(0, CGFloat(cgImageWidth) - blance)/2.0, y: max(0, CGFloat(cgImageheight) - blance)/2.0), size: blanceSize)) else { return nil }
UIBezierPath(ovalIn: blanceRect).addClip()
UIImage(cgImage: cgImage, scale: 1.0, orientation: self.imageOrientation).draw(in: blanceRect)
return UIGraphicsGetImageFromCurrentImageContext()
}
}
Ответ 16
Свифт 5:
extension UIImage {
func cropped(rect: CGRect) -> UIImage? {
guard let cgImage = cgImage else { return nil }
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
let context = UIGraphicsGetCurrentContext()
context?.translateBy(x: 0.0, y: self.size.height)
context?.scaleBy(x: 1.0, y: -1.0)
context?.draw(cgImage, in: CGRect(x: rect.minX, y: rect.minY, width: self.size.width, height: self.size.height), byTiling: false)
let croppedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
return croppedImage
}
}
Ответ 17
Я смог выполнить это примерно так:
UIImage *thisImage = [[UIImage alloc] initWithContentsOfFile:imagePath];
double x = (thisImage.size.width )/2.0;
double y = (thisImage.size.height)/2.0;
mediaImage = [self imageByCropping:thisImage toRect:CGRectMake(x, y, 60, 60)];
[thisImage release];