【问题标题】:Why when I add add a UIImage on top of another UIImage for a new image does the added image shrink?为什么当我在另一个 UIImage 上为新图像添加 UIImage 时,添加的图像会缩小?
【发布时间】:2013-12-06 20:57:58
【问题描述】:

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

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

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

我用这个方法把它裁剪成一个正方形:

/**
 * 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,因为它是55x55 UIImageView,我认为它会自动缩放(但如果我把它设置为 55,它会被拉伸得很厉害)。

【问题讨论】:

  • 这不能回答你的问题,但我建议使用 UIViews 合成图像,而不是从头开始烘焙 UIImage。虽然您的方法不会对少量图像造成太大问题,但当您想要显示 20 或 100 个图像时,您可能会发现性能(尤其是滚动)会受到影响。
  • 我不能做 UIViews 因为它需要被保存到核心数据。但我想我可以单独保存它们。那么构建两个图像的 UIView 在性能上会更好吗?这同样适用于将第二个 UIImage 添加为第一个 UIImageView 的子视图吗?
  • 我不知道你的情况的所有细节。话虽如此,在实现了非常相似的东西之后,我发现尝试对图像进行大量预处理可能会变得非常棘手,尤其是当您决定更改图形或设计时。您列出的操作都可以通过核心图形和 UIKit 非常流畅地处理。我做过的唯一预处理是确保缩小尺寸的超大图像。 (例如,当我尝试显示它时,我得到了一张 4096x4096 的图像,它在旧的 ipad 上显示它。) UIImageViews 会很容易地处理你想要做的事情。

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


【解决方案1】:

您必须在 resizeImage 调用中放入 110 的原因是因为您正在创建一个比例为 1.0 的 CGGraphics 上下文。 Retina 显示器上视图层次结构中视图的图形上下文的比例为 2.0(前提是您没有对其他任何内容进行缩放)。

我相信您创建的新 UIImage 现在是“正常”图像(抱歉,我不记得技术术语了)。这不是@2x 图像。因此,当您询问大小时,您将获得的它的大小不会缩放为 @2x。

【讨论】:

  • 我在项目中有@2x。我如何让它尊重这一点?
【解决方案2】:

注意这个答案: 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];

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多