Квадратный миниатюра изображения UIImagePickerViewController
В моем приложении пользователь выбирает изображение или снимает изображение с помощью UIImagePickerViewController. Как только изображение было выбрано, я хочу отобразить его миниатюру на квадрате UIImageView (90x90).
Я использую код Apple для создания миниатюры. Проблема заключается в том, что миниатюра не квадратизирована, функция после того, как ключ kCGImageSourceThumbnailMaxPixelSize задал значение 90, кажется, только для изменения высоты изображения, и насколько я знаю, ключ kCGImageSourceThumbnailMaxPixelSize должен отвечать за настройку высоты и ширины миниатюры.
Вот мой код:
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
NSData *imageData = UIImageJPEGRepresentation (image, 0.5);
// My image view is 90x90
UIImage *thumbImage = MyCreateThumbnailImageFromData(imageData, 90);
[myImageView setImage:thumbImage];
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
[picker dismissViewControllerAnimated:YES completion:nil];
}
UIImage* MyCreateThumbnailImageFromData (NSData * data, int imageSize) {
CGImageRef myThumbnailImage = NULL;
CGImageSourceRef myImageSource;
CFDictionaryRef myOptions = NULL;
CFStringRef myKeys[3];
CFTypeRef myValues[3];
CFNumberRef thumbnailSize;
// Create an image source from NSData; no options.
myImageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data,
NULL);
// Make sure the image source exists before continuing.
if (myImageSource == NULL){
fprintf(stderr, "Image source is NULL.");
return NULL;
}
// Package the integer as a CFNumber object. Using CFTypes allows you
// to more easily create the options dictionary later.
thumbnailSize = CFNumberCreate(NULL, kCFNumberIntType, &imageSize);
// Set up the thumbnail options.
myKeys[0] = kCGImageSourceCreateThumbnailWithTransform;
myValues[0] = (CFTypeRef)kCFBooleanTrue;
myKeys[1] = kCGImageSourceCreateThumbnailFromImageIfAbsent;
myValues[1] = (CFTypeRef)kCFBooleanTrue;
myKeys[2] = kCGImageSourceThumbnailMaxPixelSize;
myValues[2] = thumbnailSize;
myOptions = CFDictionaryCreate(NULL, (const void **) myKeys,
(const void **) myValues, 2,
&kCFTypeDictionaryKeyCallBacks,
& kCFTypeDictionaryValueCallBacks);
// Create the thumbnail image using the specified options.
myThumbnailImage = CGImageSourceCreateThumbnailAtIndex(myImageSource,
0,
myOptions);
UIImage* scaled = [UIImage imageWithCGImage:myThumbnailImage];
// Release the options dictionary and the image source
// when you no longer need them.
CFRelease(thumbnailSize);
CFRelease(myOptions);
CFRelease(myImageSource);
// Make sure the thumbnail image exists before continuing.
if (myThumbnailImage == NULL) {
fprintf(stderr, "Thumbnail image not created from image source.");
return NULL;
}
return scaled;
}
И вот как создается мое изображение:
myImageView = [[UIImageView alloc] init];
imageView.contentMode = UIViewContentModeScaleAspectFit;
CGRect rect = imageView.frame;
rect.size.height = 90;
rect.size.width = 90;
imageView.frame = rect;
[imageView setUserInteractionEnabled:YES];
Если я не установил imageView.contentMode = UIViewContentModeScaleAspectFit;
, миниатюра будет искажена, так как это просто версия моего исходного изображения с высотой 90 пикселей.
Итак, почему мой миниатюра не квадрат?
Ответы
Ответ 1
Проще всего было бы установить contentMode
на вашем изображенииView UIViewContentModeScaleAspectFill
. Однако это может быть не идеальным, поскольку он сохранит весь образ в памяти.
Вот код, который я использую для изменения размеров изображений.
+ (UIImage *)imageWithImage:(UIImage *)image scaledToSize:(CGSize)size
{
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
[image drawInRect:CGRectMake(0, 0, size.width, size.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Эта версия будет искажать изображение, если размер не совпадает с форматом изображения.
+ (UIImage *)imageWithImage:(UIImage *)image scaledToFillSize:(CGSize)size
{
CGFloat scale = MAX(size.width/image.size.width, size.height/image.size.height);
CGFloat width = image.size.width * scale;
CGFloat height = image.size.height * scale;
CGRect imageRect = CGRectMake((size.width - width)/2.0f,
(size.height - height)/2.0f,
width,
height);
UIGraphicsBeginImageContextWithOptions(size, NO, 0);
[image drawInRect:imageRect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Часто требуется только верхний квадрат изображения (а не центра). И вы хотите, чтобы конечное изображение имело определенный размер, скажем 128x128, как в примере ниже.
- (UIImage *)squareAndSmall // as a category (so, 'self' is the input image)
{
// fromCleverError original
// http://stackoverflow.com/questions/17884555
CGSize finalsize = CGSizeMake(128,128);
CGFloat scale = MAX(
finalsize.width/self.size.width,
finalsize.height/self.size.height);
CGFloat width = self.size.width * scale;
CGFloat height = self.size.height * scale;
CGRect rr = CGRectMake( 0, 0, width, height);
UIGraphicsBeginImageContextWithOptions(finalsize, NO, 0);
[self drawInRect:rr];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Ответ 2
Вот ссылка, на которую вы можете ссылаться:
1) UIImage + Resize
2) UIImage + ProportionalFill
Здесь вы можете изменить размер представления, а также добавить пропорциональную заливку, чтобы пропорционально соотношение сторон и другие функции, такие как обрезка, масштаб и т.д.
Вы можете использовать метод -(UIImage*)resizedImageToSize:(CGSize*)size
в ссылочной ссылке UIImage + Resize выше только для повторного создания изображения.
Надеюсь, это поможет вам.
Сообщите мне, если вам нужна дополнительная помощь.
Ответ 3
Свифт 2.x версии умной ошибки выше:
// Define thumbnail size
let size = CGSize(width: 100, height: 100)
// Define rect for thumbnail
let scale = max(size.width/image.size.width, size.height/image.size.height)
let width = image.size.width * scale
let height = image.size.height * scale
let x = (size.width - width) / CGFloat(2)
let y = (size.height - height) / CGFloat(2)
let thumbnailRect = CGRectMake(x, y, width, height)
// Generate thumbnail from image
UIGraphicsBeginImageContextWithOptions(size, false, 0)
image.drawInRect(thumbnailRect)
let thumbnail = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Ответ 4
Другой способ сделать это - столкнулся с проблемой на днях, и другие люди могут иметь такую же проблему при использовании кода примера Apple, который лучше всего подходит для больших изображений.
Как уже упоминалось в принятом ответе, проблема загрузки всего изображения в память и iOS может убить ваше приложение, если оно слишком велико. CGImageSourceCreateThumbnailAtIndex в примере кода Apple более эффективен, однако в этом примере есть ошибка. Третий параметр в CFDictionaryCreate - это "numValues" для копирования. Требуется 3 не 2.
myOptions = CFDictionaryCreate(NULL, (const void **) myKeys,
(const void **) myValues,
3, //Changed to 3
&kCFTypeDictionaryKeyCallBacks,
& kCFTypeDictionaryValueCallBacks);