My application is downloading a set of image files from the network, and saving them to the local iPhone disk. Some of those images are pretty big in size (widths larger than 500 pixels, for instance). Since the iPhone doesn't even have a big enough display to show the image in its original size, I'm planning on resizing the image to something a bit smaller to save on space/performance.
我的应用程序正在从网络下载一组图像文件,并将它们保存到本地的iPhone磁盘。其中一些图像的大小相当大(例如宽度大于500像素)。由于iPhone甚至没有足够大的显示器来显示原始大小的图像,所以我打算将图像大小调整到更小一点,以节省空间/性能。
Also, some of those images are JPEGs and they are not saved as the usual 60% quality setting.
此外,其中一些图像是jpeg格式,它们不会保存为通常的60%质量设置。
How can I resize a picture with the iPhone SDK, and how can I change the quality setting of a JPEG image?
如何使用iPhone SDK调整图片的大小,如何更改JPEG图像的质量设置?
18 个解决方案
#1
240
A couple of suggestions are provided as answers to this question. I had suggested the technique described in this post, with the relevant code:
对于这个问题,我们提供了一些建议。我已经提出了这篇文章中所述的技术,以及有关的代码:
+ (UIImage*)imageWithImage:(UIImage*)image
scaledToSize:(CGSize)newSize;
{
UIGraphicsBeginImageContext( newSize );
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
As far as storage of the image, the fastest image format to use with the iPhone is PNG, because it has optimizations for that format. However, if you want to store these images as JPEGs, you can take your UIImage and do the following:
至于图像的存储,使用iPhone最快的图像格式是PNG,因为它对该格式进行了优化。但是,如果您想将这些图像存储为jpeg,您可以获取您的UIImage并执行以下操作:
NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);
This creates an NSData instance containing the raw bytes for a JPEG image at a 60% quality setting. The contents of that NSData instance can then be written to disk or cached in memory.
这将创建一个NSData实例,该实例包含JPEG图像的原始字节,其质量设置为60%。然后,可以将该NSData实例的内容写到磁盘或缓存在内存中。
#2
64
The easiest and most straightforward way to resize your images would be this
调整图像大小的最简单和最直接的方法是这样的
float actualHeight = image.size.height;
float actualWidth = image.size.width;
float imgRatio = actualWidth/actualHeight;
float maxRatio = 320.0/480.0;
if(imgRatio!=maxRatio){
if(imgRatio < maxRatio){
imgRatio = 480.0 / actualHeight;
actualWidth = imgRatio * actualWidth;
actualHeight = 480.0;
}
else{
imgRatio = 320.0 / actualWidth;
actualHeight = imgRatio * actualHeight;
actualWidth = 320.0;
}
}
CGRect rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight);
UIGraphicsBeginImageContext(rect.size);
[image drawInRect:rect];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
#3
23
The above methods work well for small images, but when you try to resize a very large image, you will quickly run out of memory and crash the app. A much better way is to use CGImageSourceCreateThumbnailAtIndex
to resize the image without completely decoding it first.
上面的方法对于小图像来说效果很好,但是当您尝试调整一个非常大的图像的大小时,您将很快耗尽内存并导致应用程序崩溃。
If you have the path to the image you want to resize, you can use this:
如果您有要调整大小的图像的路径,可以使用以下方法:
- (void)resizeImageAtPath:(NSString *)imagePath {
// Create the image source (from path)
CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef) [NSURL fileURLWithPath:imagePath], NULL);
// To create image source from UIImage, use this
// NSData* pngData = UIImagePNGRepresentation(image);
// CGImageSourceRef src = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);
// Create thumbnail options
CFDictionaryRef options = (__bridge CFDictionaryRef) @{
(id) kCGImageSourceCreateThumbnailWithTransform : @YES,
(id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
(id) kCGImageSourceThumbnailMaxPixelSize : @(640)
};
// Generate the thumbnail
CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options);
CFRelease(src);
// Write the thumbnail at path
CGImageWriteToFile(thumbnail, imagePath);
}
More details here.
更多细节在这里。
#4
18
Best way to scale images without losing the aspect ratio (i.e. without stretching the imgage) is to use this method:
在不损失高宽比(即不拉伸imgage)的情况下缩放图像的最佳方法是使用以下方法:
//to scale images without changing aspect ratio
+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize {
float width = newSize.width;
float height = newSize.height;
UIGraphicsBeginImageContext(newSize);
CGRect rect = CGRectMake(0, 0, width, height);
float widthRatio = image.size.width / width;
float heightRatio = image.size.height / height;
float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;
width = image.size.width / divisor;
height = image.size.height / divisor;
rect.size.width = width;
rect.size.height = height;
//indent in case of width or height difference
float offset = (width - height) / 2;
if (offset > 0) {
rect.origin.y = offset;
}
else {
rect.origin.x = -offset;
}
[image drawInRect: rect];
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return smallImage;
}
Add this method to your Utility class so you can use it throughout your project, and access it like so:
将此方法添加到您的实用程序类中,以便您可以在整个项目中使用它,并像这样访问它:
xyzImageView.image = [Utility scaleImage:yourUIImage toSize:xyzImageView.frame.size];
This method takes care of scaling while maintaining aspect ratio. It also adds indents to the image in case the scaled down image has more width than height (or vice versa).
该方法在保持高宽比的同时兼顾缩放。如果缩小后的图像宽度大于高度(反之亦然),它还会在图像中添加缩进。
#5
7
If you have control over the server, I would strongly recommend resizing the images server side with ImageMagik. Downloading large images and resizing them on the phone is a waste of many precious resources - bandwidth, battery and memory. All of which are scarce on phones.
如果您控制了服务器,我强烈建议使用ImageMagik调整映像服务器端大小。下载大型图片并在手机上调整大小是对许多宝贵资源的浪费——带宽、电池和内存。所有这些在手机上都很稀缺。
#6
5
I developed an ultimate solution for image scaling in Swift.
我在Swift中开发了一个最终的图像缩放解决方案。
You can use it to resize image to fill, aspect fill or aspect fit specified size.
您可以使用它来调整图像的大小以填充、填充方面或匹配指定的尺寸。
You can align image to center or any of four edges and four corners.
你可以将图像对齐到中心或任何四边和四角。
And also you can trim extra space which is added if aspect ratios of original image and target size are not equal.
另外,如果原始图像和目标尺寸的比例不相等,则可以减少额外的空间。
enum UIImageAlignment {
case Center, Left, Top, Right, Bottom, TopLeft, BottomRight, BottomLeft, TopRight
}
enum UIImageScaleMode {
case Fill,
AspectFill,
AspectFit(UIImageAlignment)
}
extension UIImage {
func scaleImage(width width: CGFloat? = nil, height: CGFloat? = nil, scaleMode: UIImageScaleMode = .AspectFit(.Center), trim: Bool = false) -> UIImage {
let preWidthScale = width.map { $0 / size.width }
let preHeightScale = height.map { $0 / size.height }
var widthScale = preWidthScale ?? preHeightScale ?? 1
var heightScale = preHeightScale ?? widthScale
switch scaleMode {
case .AspectFit(_):
let scale = min(widthScale, heightScale)
widthScale = scale
heightScale = scale
case .AspectFill:
let scale = max(widthScale, heightScale)
widthScale = scale
heightScale = scale
default:
break
}
let newWidth = size.width * widthScale
let newHeight = size.height * heightScale
let canvasWidth = trim ? newWidth : (width ?? newWidth)
let canvasHeight = trim ? newHeight : (height ?? newHeight)
UIGraphicsBeginImageContextWithOptions(CGSizeMake(canvasWidth, canvasHeight), false, 0)
var originX: CGFloat = 0
var originY: CGFloat = 0
switch scaleMode {
case .AspectFit(let alignment):
switch alignment {
case .Center:
originX = (canvasWidth - newWidth) / 2
originY = (canvasHeight - newHeight) / 2
case .Top:
originX = (canvasWidth - newWidth) / 2
case .Left:
originY = (canvasHeight - newHeight) / 2
case .Bottom:
originX = (canvasWidth - newWidth) / 2
originY = canvasHeight - newHeight
case .Right:
originX = canvasWidth - newWidth
originY = (canvasHeight - newHeight) / 2
case .TopLeft:
break
case .TopRight:
originX = canvasWidth - newWidth
case .BottomLeft:
originY = canvasHeight - newHeight
case .BottomRight:
originX = canvasWidth - newWidth
originY = canvasHeight - newHeight
}
default:
break
}
self.drawInRect(CGRectMake(originX, originY, newWidth, newHeight))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
There are examples of applying this solution below.
下面是应用这个解决方案的例子。
Gray rectangle is target site image will be resized to. Blue circles in light blue rectangle is the image (I used circles because it's easy to see when it's scaled without preserving aspect). Light orange color marks areas that will be trimmed if you pass trim: true
.
灰色矩形是目标站点图像的大小调整。蓝色矩形中的蓝色圆圈是图像(我使用圆圈是因为它在缩放时很容易看到而不保留相位)。如果通过修剪,将会被修剪的区域用浅橙色标记:正确。
Aspect fit before and after scaling:
尺度变换前后尺寸拟合:
Another example of aspect fit:
另一个方面拟合的例子:
Aspect fit with top alignment:
方面与上对齐:
Aspect fill:
方面填写:
Fill:
填充:
I used upscaling in my examples because it's simpler to demonstrate but solution also works for downscaling as in question.
在我的例子中,我使用了向上扩展,因为演示更简单,但是解决方案也适用于降级。
For JPEG compression you should use this :
对于JPEG压缩,您应该使用以下方法:
let compressionQuality: CGFloat = 0.75 // adjust to change JPEG quality
if let data = UIImageJPEGRepresentation(image, compressionQuality) {
// ...
}
You can check out my gist with Xcode playground.
你可以去Xcode游乐场看看我的要点。
#7
3
For Swift 3, the below code scales the image keeping the aspect ratio. You can read more about the ImageContext in Apple's documentation:
对于Swift 3,下面的代码缩放图像,保持高宽比。你可以阅读更多关于苹果文件中的ImageContext:
extension UIImage {
class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {
let scale = newHeight / image.size.height
let newWidth = image.size.width * scale
UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
To use it, call resizeImage()
method:
要使用它,调用resizeImage()方法:
UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight)
#8
2
you can use this code to scale image in required size.
您可以使用此代码按要求的大小缩放图像。
+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize
{
CGSize actSize = image.size;
float scale = actSize.width/actSize.height;
if (scale < 1) {
newSize.height = newSize.width/scale;
}
else {
newSize.width = newSize.height*scale;
}
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
#9
1
Adding to the slew of answers here, but I have gone for a solution which resizes by file size, rather than dimensions.
在这里添加了大量的答案,但是我选择了一个根据文件大小而不是尺寸大小调整大小的解决方案。
This will both reduce the dimensions and quality of the image until it reaches your given size.
这将减少尺寸和质量的图像,直到它达到你的给定尺寸。
func compressTo(toSizeInMB size: Double) -> UIImage? {
let bytes = size * 1024 * 1024
let sizeInBytes = Int(bytes)
var needCompress:Bool = true
var imgData:Data?
var compressingValue:CGFloat = 1.0
while (needCompress) {
if let resizedImage = scaleImage(byMultiplicationFactorOf: compressingValue), let data: Data = UIImageJPEGRepresentation(resizedImage, compressingValue) {
if data.count < sizeInBytes || compressingValue < 0.1 {
needCompress = false
imgData = data
} else {
compressingValue -= 0.1
}
}
}
if let data = imgData {
print("Finished with compression value of: \(compressingValue)")
return UIImage(data: data)
}
return nil
}
private func scaleImage(byMultiplicationFactorOf factor: CGFloat) -> UIImage? {
let size = CGSize(width: self.size.width*factor, height: self.size.height*factor)
UIGraphicsBeginImageContext(size)
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
if let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() {
UIGraphicsEndImageContext()
return newImage;
}
return nil
}
Credit for scaling by size answer
归功于按规模大小进行的扩展
#10
1
func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage? {
let scale = newWidth / image.size.width
let newHeight = CGFloat(200.0)
UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
#11
0
If anyone still looking for better option
如果还有人在寻找更好的选择。
-(UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)targetSize {
UIImage *sourceImage = image;
UIImage *newImage = nil;
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
if (widthFactor < heightFactor)
scaleFactor = widthFactor;
else
scaleFactor = heightFactor;
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
// center the image
if (widthFactor < heightFactor) {
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
} else if (widthFactor > heightFactor) {
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
}
}
// this is actually the interesting part:
UIGraphicsBeginImageContext(targetSize);
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect:thumbnailRect];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if(newImage == nil) NSLog(@"could not scale image");
return newImage ;
}
#12
0
A problem that might occur on retina displays is that the scale of the image is set by ImageCapture or so. The resize functions above will not change that. In these cases the resize will work not properly.
视网膜显示器上可能会出现的一个问题是,图像的大小是由成像来决定的。上面的resize函数不会改变这一点。在这些情况下,调整大小将不能正常工作。
In the code below, the scale is set to 1 (not scaled) and the returned image has the size that you would expect. This is done in the UIGraphicsBeginImageContextWithOptions
call.
在下面的代码中,比例被设置为1(没有缩放),返回的图像具有您期望的大小。这是在UIGraphicsBeginImageContextWithOptions调用中完成的。
-(UIImage *)resizeImage :(UIImage *)theImage :(CGSize)theNewSize {
UIGraphicsBeginImageContextWithOptions(theNewSize, NO, 1.0);
[theImage drawInRect:CGRectMake(0, 0, theNewSize.width, theNewSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
#13
0
I ended up using Brads technique to create a scaleToFitWidth
method in UIImage+Extensions
if that's useful to anyone...
我最后使用Brads技术在UIImage+扩展中创建了一个scaleToFitWidth方法,如果这对任何人都有用的话……
-(UIImage *)scaleToFitWidth:(CGFloat)width
{
CGFloat ratio = width / self.size.width;
CGFloat height = self.size.height * ratio;
NSLog(@"W:%f H:%f",width,height);
UIGraphicsBeginImageContext(CGSizeMake(width, height));
[self drawInRect:CGRectMake(0.0f,0.0f,width,height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
then wherever you like
然后只要你喜欢
#import "UIImage+Extensions.h"
#进口“用户界面图像+ Extensions.h”
UIImage *newImage = [image scaleToFitWidth:100.0f];
UIImage *newImage = [image scaleToFitWidth:100.0f];
Also worth noting you could move this further down into a UIView+Extensions
class if you want to render images from a UIView
同样值得注意的是,如果你想要从UIView渲染图像,你可以把它移到UIView+Extensions类中
#14
0
I just wanted to answer that question for Cocoa Swift programmers. This function returns NSImage with new size. You can use that function like this.
我只是想为Cocoa Swift程序员回答这个问题。这个函数返回新大小的NSImage。你可以用这个函数。
let sizeChangedImage = changeImageSize(image, ratio: 2)
// changes image size
func changeImageSize (image: NSImage, ratio: CGFloat) -> NSImage {
// getting the current image size
let w = image.size.width
let h = image.size.height
// calculating new size
let w_new = w / ratio
let h_new = h / ratio
// creating size constant
let newSize = CGSizeMake(w_new ,h_new)
//creating rect
let rect = NSMakeRect(0, 0, w_new, h_new)
// creating a image context with new size
let newImage = NSImage.init(size:newSize)
newImage.lockFocus()
// drawing image with new size in context
image.drawInRect(rect)
newImage.unlockFocus()
return newImage
}
#15
0
Try this,It work for me,
试试这个,对我有用,
CGRect rect =CGRectMake (0, 0,1200,900);
UIGraphicsBeginImageContext( rect.size );
[image drawInRect:rect];
UIImage *picture1 = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *imageData = UIImagePNGRepresentation(picture1);
UIImage *img=[UIImage imageWithData:imageData];
[imageArray addObject:img];
#16
0
- (UIImage *)resizeImage:(UIImage*)image newSize:(CGSize)newSize {
CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
CGImageRef imageRef = image.CGImage;
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height);
CGContextConcatCTM(context, flipVertical);
CGContextDrawImage(context, newRect, imageRef);
CGImageRef newImageRef = CGBitmapContextCreateImage(context);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
CGImageRelease(newImageRef);
UIGraphicsEndImageContext();
return newImage;
}
#17
0
If you image is in document directory, Add this URL extension:
如果您的图像在文档目录中,请添加此URL扩展名:
extension URL {
func compressedImageURL(quality: CGFloat = 0.3) throws -> URL? {
let imageData = try Data(contentsOf: self)
debugPrint("Image file size before compression: \(imageData.count) bytes")
let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + NSUUID().uuidString + ".jpg")
guard let actualImage = UIImage(data: imageData) else { return nil }
guard let compressedImageData = UIImageJPEGRepresentation(actualImage, quality) else {
return nil
}
debugPrint("Image file size after compression: \(compressedImageData.count) bytes")
do {
try compressedImageData.write(to: compressedURL)
return compressedURL
} catch {
return nil
}
}
}
Usage:
用法:
guard let localImageURL = URL(string: "< LocalImagePath.jpg >") else {
return
}
//Here you will get URL of compressed image
guard let compressedImageURL = try localImageURL.compressedImageURL() else {
return
}
debugPrint("compressedImageURL: \(compressedImageURL.absoluteString)")
Note:- Change < LocalImagePath.jpg > with your local jpg image path.
注意:-使用本地jpg图像路径修改< LocalImagePath.jpg >。
#18
-2
To resize an image I have better (graphical) results by using this function in stead of DrawInRect:
为了调整图像的大小,我使用这个函数而不是DrawInRect来获得更好的(图形)结果:
- (UIImage*) reduceImageSize:(UIImage*) pImage newwidth:(float) pWidth
{
float lScale = pWidth / pImage.size.width;
CGImageRef cgImage = pImage.CGImage;
UIImage *lResult = [UIImage imageWithCGImage:cgImage scale:lScale
orientation:UIImageOrientationRight];
return lResult;
}
Aspect ratio is taken care for automatically
纵横比自动处理
#1
240
A couple of suggestions are provided as answers to this question. I had suggested the technique described in this post, with the relevant code:
对于这个问题,我们提供了一些建议。我已经提出了这篇文章中所述的技术,以及有关的代码:
+ (UIImage*)imageWithImage:(UIImage*)image
scaledToSize:(CGSize)newSize;
{
UIGraphicsBeginImageContext( newSize );
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
As far as storage of the image, the fastest image format to use with the iPhone is PNG, because it has optimizations for that format. However, if you want to store these images as JPEGs, you can take your UIImage and do the following:
至于图像的存储,使用iPhone最快的图像格式是PNG,因为它对该格式进行了优化。但是,如果您想将这些图像存储为jpeg,您可以获取您的UIImage并执行以下操作:
NSData *dataForJPEGFile = UIImageJPEGRepresentation(theImage, 0.6);
This creates an NSData instance containing the raw bytes for a JPEG image at a 60% quality setting. The contents of that NSData instance can then be written to disk or cached in memory.
这将创建一个NSData实例,该实例包含JPEG图像的原始字节,其质量设置为60%。然后,可以将该NSData实例的内容写到磁盘或缓存在内存中。
#2
64
The easiest and most straightforward way to resize your images would be this
调整图像大小的最简单和最直接的方法是这样的
float actualHeight = image.size.height;
float actualWidth = image.size.width;
float imgRatio = actualWidth/actualHeight;
float maxRatio = 320.0/480.0;
if(imgRatio!=maxRatio){
if(imgRatio < maxRatio){
imgRatio = 480.0 / actualHeight;
actualWidth = imgRatio * actualWidth;
actualHeight = 480.0;
}
else{
imgRatio = 320.0 / actualWidth;
actualHeight = imgRatio * actualHeight;
actualWidth = 320.0;
}
}
CGRect rect = CGRectMake(0.0, 0.0, actualWidth, actualHeight);
UIGraphicsBeginImageContext(rect.size);
[image drawInRect:rect];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
#3
23
The above methods work well for small images, but when you try to resize a very large image, you will quickly run out of memory and crash the app. A much better way is to use CGImageSourceCreateThumbnailAtIndex
to resize the image without completely decoding it first.
上面的方法对于小图像来说效果很好,但是当您尝试调整一个非常大的图像的大小时,您将很快耗尽内存并导致应用程序崩溃。
If you have the path to the image you want to resize, you can use this:
如果您有要调整大小的图像的路径,可以使用以下方法:
- (void)resizeImageAtPath:(NSString *)imagePath {
// Create the image source (from path)
CGImageSourceRef src = CGImageSourceCreateWithURL((__bridge CFURLRef) [NSURL fileURLWithPath:imagePath], NULL);
// To create image source from UIImage, use this
// NSData* pngData = UIImagePNGRepresentation(image);
// CGImageSourceRef src = CGImageSourceCreateWithData((CFDataRef)pngData, NULL);
// Create thumbnail options
CFDictionaryRef options = (__bridge CFDictionaryRef) @{
(id) kCGImageSourceCreateThumbnailWithTransform : @YES,
(id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
(id) kCGImageSourceThumbnailMaxPixelSize : @(640)
};
// Generate the thumbnail
CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(src, 0, options);
CFRelease(src);
// Write the thumbnail at path
CGImageWriteToFile(thumbnail, imagePath);
}
More details here.
更多细节在这里。
#4
18
Best way to scale images without losing the aspect ratio (i.e. without stretching the imgage) is to use this method:
在不损失高宽比(即不拉伸imgage)的情况下缩放图像的最佳方法是使用以下方法:
//to scale images without changing aspect ratio
+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize {
float width = newSize.width;
float height = newSize.height;
UIGraphicsBeginImageContext(newSize);
CGRect rect = CGRectMake(0, 0, width, height);
float widthRatio = image.size.width / width;
float heightRatio = image.size.height / height;
float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;
width = image.size.width / divisor;
height = image.size.height / divisor;
rect.size.width = width;
rect.size.height = height;
//indent in case of width or height difference
float offset = (width - height) / 2;
if (offset > 0) {
rect.origin.y = offset;
}
else {
rect.origin.x = -offset;
}
[image drawInRect: rect];
UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return smallImage;
}
Add this method to your Utility class so you can use it throughout your project, and access it like so:
将此方法添加到您的实用程序类中,以便您可以在整个项目中使用它,并像这样访问它:
xyzImageView.image = [Utility scaleImage:yourUIImage toSize:xyzImageView.frame.size];
This method takes care of scaling while maintaining aspect ratio. It also adds indents to the image in case the scaled down image has more width than height (or vice versa).
该方法在保持高宽比的同时兼顾缩放。如果缩小后的图像宽度大于高度(反之亦然),它还会在图像中添加缩进。
#5
7
If you have control over the server, I would strongly recommend resizing the images server side with ImageMagik. Downloading large images and resizing them on the phone is a waste of many precious resources - bandwidth, battery and memory. All of which are scarce on phones.
如果您控制了服务器,我强烈建议使用ImageMagik调整映像服务器端大小。下载大型图片并在手机上调整大小是对许多宝贵资源的浪费——带宽、电池和内存。所有这些在手机上都很稀缺。
#6
5
I developed an ultimate solution for image scaling in Swift.
我在Swift中开发了一个最终的图像缩放解决方案。
You can use it to resize image to fill, aspect fill or aspect fit specified size.
您可以使用它来调整图像的大小以填充、填充方面或匹配指定的尺寸。
You can align image to center or any of four edges and four corners.
你可以将图像对齐到中心或任何四边和四角。
And also you can trim extra space which is added if aspect ratios of original image and target size are not equal.
另外,如果原始图像和目标尺寸的比例不相等,则可以减少额外的空间。
enum UIImageAlignment {
case Center, Left, Top, Right, Bottom, TopLeft, BottomRight, BottomLeft, TopRight
}
enum UIImageScaleMode {
case Fill,
AspectFill,
AspectFit(UIImageAlignment)
}
extension UIImage {
func scaleImage(width width: CGFloat? = nil, height: CGFloat? = nil, scaleMode: UIImageScaleMode = .AspectFit(.Center), trim: Bool = false) -> UIImage {
let preWidthScale = width.map { $0 / size.width }
let preHeightScale = height.map { $0 / size.height }
var widthScale = preWidthScale ?? preHeightScale ?? 1
var heightScale = preHeightScale ?? widthScale
switch scaleMode {
case .AspectFit(_):
let scale = min(widthScale, heightScale)
widthScale = scale
heightScale = scale
case .AspectFill:
let scale = max(widthScale, heightScale)
widthScale = scale
heightScale = scale
default:
break
}
let newWidth = size.width * widthScale
let newHeight = size.height * heightScale
let canvasWidth = trim ? newWidth : (width ?? newWidth)
let canvasHeight = trim ? newHeight : (height ?? newHeight)
UIGraphicsBeginImageContextWithOptions(CGSizeMake(canvasWidth, canvasHeight), false, 0)
var originX: CGFloat = 0
var originY: CGFloat = 0
switch scaleMode {
case .AspectFit(let alignment):
switch alignment {
case .Center:
originX = (canvasWidth - newWidth) / 2
originY = (canvasHeight - newHeight) / 2
case .Top:
originX = (canvasWidth - newWidth) / 2
case .Left:
originY = (canvasHeight - newHeight) / 2
case .Bottom:
originX = (canvasWidth - newWidth) / 2
originY = canvasHeight - newHeight
case .Right:
originX = canvasWidth - newWidth
originY = (canvasHeight - newHeight) / 2
case .TopLeft:
break
case .TopRight:
originX = canvasWidth - newWidth
case .BottomLeft:
originY = canvasHeight - newHeight
case .BottomRight:
originX = canvasWidth - newWidth
originY = canvasHeight - newHeight
}
default:
break
}
self.drawInRect(CGRectMake(originX, originY, newWidth, newHeight))
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
There are examples of applying this solution below.
下面是应用这个解决方案的例子。
Gray rectangle is target site image will be resized to. Blue circles in light blue rectangle is the image (I used circles because it's easy to see when it's scaled without preserving aspect). Light orange color marks areas that will be trimmed if you pass trim: true
.
灰色矩形是目标站点图像的大小调整。蓝色矩形中的蓝色圆圈是图像(我使用圆圈是因为它在缩放时很容易看到而不保留相位)。如果通过修剪,将会被修剪的区域用浅橙色标记:正确。
Aspect fit before and after scaling:
尺度变换前后尺寸拟合:
Another example of aspect fit:
另一个方面拟合的例子:
Aspect fit with top alignment:
方面与上对齐:
Aspect fill:
方面填写:
Fill:
填充:
I used upscaling in my examples because it's simpler to demonstrate but solution also works for downscaling as in question.
在我的例子中,我使用了向上扩展,因为演示更简单,但是解决方案也适用于降级。
For JPEG compression you should use this :
对于JPEG压缩,您应该使用以下方法:
let compressionQuality: CGFloat = 0.75 // adjust to change JPEG quality
if let data = UIImageJPEGRepresentation(image, compressionQuality) {
// ...
}
You can check out my gist with Xcode playground.
你可以去Xcode游乐场看看我的要点。
#7
3
For Swift 3, the below code scales the image keeping the aspect ratio. You can read more about the ImageContext in Apple's documentation:
对于Swift 3,下面的代码缩放图像,保持高宽比。你可以阅读更多关于苹果文件中的ImageContext:
extension UIImage {
class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage {
let scale = newHeight / image.size.height
let newWidth = image.size.width * scale
UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
To use it, call resizeImage()
method:
要使用它,调用resizeImage()方法:
UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight)
#8
2
you can use this code to scale image in required size.
您可以使用此代码按要求的大小缩放图像。
+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize
{
CGSize actSize = image.size;
float scale = actSize.width/actSize.height;
if (scale < 1) {
newSize.height = newSize.width/scale;
}
else {
newSize.width = newSize.height*scale;
}
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
#9
1
Adding to the slew of answers here, but I have gone for a solution which resizes by file size, rather than dimensions.
在这里添加了大量的答案,但是我选择了一个根据文件大小而不是尺寸大小调整大小的解决方案。
This will both reduce the dimensions and quality of the image until it reaches your given size.
这将减少尺寸和质量的图像,直到它达到你的给定尺寸。
func compressTo(toSizeInMB size: Double) -> UIImage? {
let bytes = size * 1024 * 1024
let sizeInBytes = Int(bytes)
var needCompress:Bool = true
var imgData:Data?
var compressingValue:CGFloat = 1.0
while (needCompress) {
if let resizedImage = scaleImage(byMultiplicationFactorOf: compressingValue), let data: Data = UIImageJPEGRepresentation(resizedImage, compressingValue) {
if data.count < sizeInBytes || compressingValue < 0.1 {
needCompress = false
imgData = data
} else {
compressingValue -= 0.1
}
}
}
if let data = imgData {
print("Finished with compression value of: \(compressingValue)")
return UIImage(data: data)
}
return nil
}
private func scaleImage(byMultiplicationFactorOf factor: CGFloat) -> UIImage? {
let size = CGSize(width: self.size.width*factor, height: self.size.height*factor)
UIGraphicsBeginImageContext(size)
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
if let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() {
UIGraphicsEndImageContext()
return newImage;
}
return nil
}
Credit for scaling by size answer
归功于按规模大小进行的扩展
#10
1
func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage? {
let scale = newWidth / image.size.width
let newHeight = CGFloat(200.0)
UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight))
image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
#11
0
If anyone still looking for better option
如果还有人在寻找更好的选择。
-(UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)targetSize {
UIImage *sourceImage = image;
UIImage *newImage = nil;
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
if (widthFactor < heightFactor)
scaleFactor = widthFactor;
else
scaleFactor = heightFactor;
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
// center the image
if (widthFactor < heightFactor) {
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
} else if (widthFactor > heightFactor) {
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
}
}
// this is actually the interesting part:
UIGraphicsBeginImageContext(targetSize);
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect:thumbnailRect];
newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
if(newImage == nil) NSLog(@"could not scale image");
return newImage ;
}
#12
0
A problem that might occur on retina displays is that the scale of the image is set by ImageCapture or so. The resize functions above will not change that. In these cases the resize will work not properly.
视网膜显示器上可能会出现的一个问题是,图像的大小是由成像来决定的。上面的resize函数不会改变这一点。在这些情况下,调整大小将不能正常工作。
In the code below, the scale is set to 1 (not scaled) and the returned image has the size that you would expect. This is done in the UIGraphicsBeginImageContextWithOptions
call.
在下面的代码中,比例被设置为1(没有缩放),返回的图像具有您期望的大小。这是在UIGraphicsBeginImageContextWithOptions调用中完成的。
-(UIImage *)resizeImage :(UIImage *)theImage :(CGSize)theNewSize {
UIGraphicsBeginImageContextWithOptions(theNewSize, NO, 1.0);
[theImage drawInRect:CGRectMake(0, 0, theNewSize.width, theNewSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
#13
0
I ended up using Brads technique to create a scaleToFitWidth
method in UIImage+Extensions
if that's useful to anyone...
我最后使用Brads技术在UIImage+扩展中创建了一个scaleToFitWidth方法,如果这对任何人都有用的话……
-(UIImage *)scaleToFitWidth:(CGFloat)width
{
CGFloat ratio = width / self.size.width;
CGFloat height = self.size.height * ratio;
NSLog(@"W:%f H:%f",width,height);
UIGraphicsBeginImageContext(CGSizeMake(width, height));
[self drawInRect:CGRectMake(0.0f,0.0f,width,height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
then wherever you like
然后只要你喜欢
#import "UIImage+Extensions.h"
#进口“用户界面图像+ Extensions.h”
UIImage *newImage = [image scaleToFitWidth:100.0f];
UIImage *newImage = [image scaleToFitWidth:100.0f];
Also worth noting you could move this further down into a UIView+Extensions
class if you want to render images from a UIView
同样值得注意的是,如果你想要从UIView渲染图像,你可以把它移到UIView+Extensions类中
#14
0
I just wanted to answer that question for Cocoa Swift programmers. This function returns NSImage with new size. You can use that function like this.
我只是想为Cocoa Swift程序员回答这个问题。这个函数返回新大小的NSImage。你可以用这个函数。
let sizeChangedImage = changeImageSize(image, ratio: 2)
// changes image size
func changeImageSize (image: NSImage, ratio: CGFloat) -> NSImage {
// getting the current image size
let w = image.size.width
let h = image.size.height
// calculating new size
let w_new = w / ratio
let h_new = h / ratio
// creating size constant
let newSize = CGSizeMake(w_new ,h_new)
//creating rect
let rect = NSMakeRect(0, 0, w_new, h_new)
// creating a image context with new size
let newImage = NSImage.init(size:newSize)
newImage.lockFocus()
// drawing image with new size in context
image.drawInRect(rect)
newImage.unlockFocus()
return newImage
}
#15
0
Try this,It work for me,
试试这个,对我有用,
CGRect rect =CGRectMake (0, 0,1200,900);
UIGraphicsBeginImageContext( rect.size );
[image drawInRect:rect];
UIImage *picture1 = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
NSData *imageData = UIImagePNGRepresentation(picture1);
UIImage *img=[UIImage imageWithData:imageData];
[imageArray addObject:img];
#16
0
- (UIImage *)resizeImage:(UIImage*)image newSize:(CGSize)newSize {
CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
CGImageRef imageRef = image.CGImage;
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height);
CGContextConcatCTM(context, flipVertical);
CGContextDrawImage(context, newRect, imageRef);
CGImageRef newImageRef = CGBitmapContextCreateImage(context);
UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
CGImageRelease(newImageRef);
UIGraphicsEndImageContext();
return newImage;
}
#17
0
If you image is in document directory, Add this URL extension:
如果您的图像在文档目录中,请添加此URL扩展名:
extension URL {
func compressedImageURL(quality: CGFloat = 0.3) throws -> URL? {
let imageData = try Data(contentsOf: self)
debugPrint("Image file size before compression: \(imageData.count) bytes")
let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + NSUUID().uuidString + ".jpg")
guard let actualImage = UIImage(data: imageData) else { return nil }
guard let compressedImageData = UIImageJPEGRepresentation(actualImage, quality) else {
return nil
}
debugPrint("Image file size after compression: \(compressedImageData.count) bytes")
do {
try compressedImageData.write(to: compressedURL)
return compressedURL
} catch {
return nil
}
}
}
Usage:
用法:
guard let localImageURL = URL(string: "< LocalImagePath.jpg >") else {
return
}
//Here you will get URL of compressed image
guard let compressedImageURL = try localImageURL.compressedImageURL() else {
return
}
debugPrint("compressedImageURL: \(compressedImageURL.absoluteString)")
Note:- Change < LocalImagePath.jpg > with your local jpg image path.
注意:-使用本地jpg图像路径修改< LocalImagePath.jpg >。
#18
-2
To resize an image I have better (graphical) results by using this function in stead of DrawInRect:
为了调整图像的大小,我使用这个函数而不是DrawInRect来获得更好的(图形)结果:
- (UIImage*) reduceImageSize:(UIImage*) pImage newwidth:(float) pWidth
{
float lScale = pWidth / pImage.size.width;
CGImageRef cgImage = pImage.CGImage;
UIImage *lResult = [UIImage imageWithCGImage:cgImage scale:lScale
orientation:UIImageOrientationRight];
return lResult;
}
Aspect ratio is taken care for automatically
纵横比自动处理