为什么当我添加UIImage在另一个UIImage的顶部添加新图像时,添加的图像会缩小?

时间:2013-12-06 20:57:59

标签: ios objective-c uiimageview uiimage core-graphics

我正在尝试在视频缩略图的顶部添加视频播放器图标。

我从YouTube API获取图片,然后将其裁剪为方形,然后将其调整为适当大小。然后我在其上添加我的播放器图标图像。

问题在于播放器图标比缩略图上的图标要小得多(它在屏幕上的尺寸要小28倍28秒)。请参阅下面的图像,我将其添加到单元格以显示应该的大小,而不是缩略图大小:

enter image description here

用这种方法将它裁剪成正方形:

/**
 * Given a UIImage, return it with a square aspect ratio (via cropping, not smushing).
 */
- (UIImage *)createSquareVersionOfImage:(UIImage *)image {
    CGFloat originalWidth = image.size.width;
    CGFloat originalHeight = image.size.height;

    float smallestDimension = fminf(originalWidth, originalHeight);

    // Determine the offset needed to crop the center of the image out.
    CGFloat xOffsetToBeCentered = (originalWidth - smallestDimension) / 2;
    CGFloat yOffsetToBeCentered = (originalHeight - smallestDimension) / 2;

    // Create the square, making sure the position and dimensions are set appropriately for retina displays.
    CGRect square = CGRectMake(xOffsetToBeCentered * image.scale, yOffsetToBeCentered * image.scale, smallestDimension * image.scale, smallestDimension *image.scale);
    CGImageRef squareImageRef = CGImageCreateWithImageInRect([image CGImage], square);

    UIImage *squareImage = [UIImage imageWithCGImage:squareImageRef scale:image.scale orientation:image.imageOrientation];
    CGImageRelease(squareImageRef);

    return squareImage;
}

使用此方法调整大小:

/**
 * Resize the given UIImage to a new size and return the newly resized image.
 */
- (UIImage *)resizeImage:(UIImage *)image toSize:(CGSize)newSize {
    UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
    [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

使用此方法将其添加到另一个图像的顶部:

/**
 * Adds a UIImage on top of another UIImage and returns the result. The top image is centered.
 */
- (UIImage *)addImage:(UIImage *)additionalImage toImage:(UIImage *)backgroundImage {
    UIGraphicsBeginImageContext(backgroundImage.size);
    [backgroundImage drawInRect:CGRectMake(0, 0, backgroundImage.size.width, backgroundImage.size.height)];
    [additionalImage drawInRect:CGRectMake((backgroundImage.size.width - additionalImage.size.width) / 2, (backgroundImage.size.height - additionalImage.size.height) / 2, additionalImage.size.width, additionalImage.size.height)];

    UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return resultingImage;
}

这就是它的实施方式:

UIImage *squareThumbnail = [self resizeImage:[self createSquareVersionOfImage:responseObject] toSize:CGSizeMake(110.0, 110.0)];
UIImage *playerIcon = [UIImage imageNamed:@"video-thumbnail-overlay"];
UIImage *squareThumbnailWithPlayerIcon = [self addImage:playerIcon toImage:squareThumbnail];

但最终,图标总是太小。在处理图像时,尺寸调整的东西让我感到困惑,因为我习惯于自动识别与视网膜屏幕相关的东西,例如在上面的代码块中,我不知道为什么我将其设置为110.0, 110.0 as这是一个55x55的UIImageView,我认为它会自动缩放(但是如果我把它放到55它就会非常紧张)。

2 个答案:

答案 0 :(得分:0)

您必须在resizeImage调用中放置110的原因是因为您正在创建一个1.0的缩放比例的CGGraphics上下文。视网膜显示器上视图层次结构中视图的图形上下文的比例为2.0(前提是您没有做任何其他事情来扩展)。

我相信你创建的新UIImage现在是一个“正常”的形象(抱歉,我不记得技术术语)。它不是@ 2x图像。因此,当您要求尺寸时,它的尺寸将不会缩放为@ 2x。

答案 1 :(得分:0)

请注意这个答案: UIGraphicsGetImageFromCurrentImageContext retina resolutions?

我没有对此进行过测试,但应该工作。如果没有,它至少应该更直接调试。

//images should be passed in with their original scales
-(UIImage*)compositedImageWithSize:(CGSize)newSize bg:(UIImage*)backgroundImage fgImage:(UIImage*)foregroundImage{
    //match the scale of screen.
    CGFloat scale = [[UIScreen mainScreen] scale];
    UIGraphicsBeginImageContextWithOptions(newSize, NO, scale);
    //instead of resizing the image ahead of time, we just draw it into the context at the appropriate size. The context will clip the image.
    CGRect aspectFillRect = CGRectZero;

    if(newSize.width/newSize.height > backgroundImage.size.width/backgroundImage.size.height){
        aspectFillRect.y = 0;
        aspectFillRect.height = newSize.height;
        CGFloat scaledWidth = (newSize.height / backgroundImage.size.height) * newSize.width;
        aspectFillRect.x = (newSize.width - scaledWidth)/2.0;
        aspectFillRect.width = scaledWidth;
    }else{
        aspectFillRect.x = 0;
        aspectFillRect.width = newSize.width;
        CGFloat scaledHeight = (newSize.width / backgroundImage.size.width) * newSize.height;
        aspectFillRect.y = (newSize.height - scaledHeight)/2.0;
        aspectFillRect.height = scaledHeight;
    }

    [backgroundImage drawInRect:aspectFillRect];

    //pass in the 2x image for the fg image so it provides a better resolution
    [foregroundImage drawInRect:CGRectMake((newSize.width - additionalImage.size.width) / 2, (newSize.height - additionalImage.size.height) / 2, additionalImage.size.width, additionalImage.size.height)];

    UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return resultingImage;
}

您可以跳过之前调用的所有方法并执行:

UIImage *playerIcon = [UIImage imageNamed:@"video-thumbnail-overlay"];
//pass in the non-retina scale of the image
UIImage *result = [self compositedImageWithSize:CGSizeMake(55.0, 55.0) 
                                             bg:responseObject 
                                             fg:playerIcon];

希望这有帮助!