objective-c 在 iPhone 上切片 UIImage

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/248667/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 20:52:22  来源:igfitidea点击:

Slicing up a UIImage on iPhone

iphoneobjective-ccocoa-touchimage-manipulation

提问by executor21

Objective: take a UIImage, crop out a square in the middle, change size of square to 320x320 pixels, slice up the image into 16 80x80 images, save the 16 images in an array.

目标:取一张UIImage,在中间剪出一个正方形,将正方形的大小改为320x320像素,将图像切成16张80x80的图像,将这16张图像保存在一个数组中。

Here's my code:

这是我的代码:

CGImageRef originalImage, resizedImage, finalImage, tmp;
float imgWidth, imgHeight, diff;
UIImage *squareImage, *playImage;
NSMutableArray *tileImgArray;
int r, c;

originalImage = [image CGImage];

imgWidth = image.size.width;
imgHeight = image.size.height;
diff = fabs(imgWidth - imgHeight);

if(imgWidth > imgHeight){
    resizedImage = CGImageCreateWithImageInRect(originalImage, CGRectMake(floor(diff/2), 0, imgHeight, imgHeight));
}else{
    resizedImage = CGImageCreateWithImageInRect(originalImage, CGRectMake(0, floor(diff/2), imgWidth, imgWidth));
}
CGImageRelease(originalImage);

squareImage = [UIImage imageWithCGImage:resizedImage];      
if(squareImage.size.width != squareImage.size.height){
    NSLog(@"image cutout error!");
    //*code to return to main menu of app, irrelevant here
}else{
    float newDim = squareImage.size.width;
    if(newDim != 320.0){
        CGSize finalSize = CGSizeMake(320.0, 320.0);
        UIGraphicsBeginImageContext(finalSize);
        [squareImage drawInRect:CGRectMake(0, 0, finalSize.width, finalSize.height)];
        playImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }else{
        playImage = squareImage;
    }
}

finalImage = [playImage CGImage];
tileImgArray = [NSMutableArray arrayWithCapacity:0];
for(int i = 0; i < 16; i++){
    r = i/4;
    c = i%4;
    //*
    tmp = CGImageCreateWithImageInRect(finalImage, CGRectMake(c*tileSize, r*tileSize, tileSize, tileSize));
    [tileImgArray addObject:[UIImage imageWithCGImage:tmp]];
}

The code works correctly when the original (the variable image) has its smaller dimension either bigger or smaller than 320 pixels. When it's exactly 320, the resulting 80x80 images are almost entirely black, some with a few pixels at the edges that may (I can't really tell) be from the original image.

当原始(可变图像)的较小尺寸大于或小于 320 像素时,代码可以正常工作。当它正好是 320 时,生成的 80x80 图像几乎完全是黑色的,有些在边缘有一些像素(我真的无法分辨)可能来自原始图像。

I tested by displaying the full image both directly:

我通过直接显示完整图像来测试:

[UIImage imageWithCGImage:finalImage];

And indirectly:

并间接地:

[UIImage imageWithCGImage:CGImageCreateWithImageInRect(finalImage, CGRectMake(0, 0, 320, 320))];

In both cases, the display worked. The problems only arise when I attempt to slice out some part of the image.

在这两种情况下,显示器都能正常工作。只有当我尝试切出图像的某些部分时才会出现问题。

采纳答案by executor21

After some more experimentation, I found the following solution (I still don't know why it didn't work as originally written, though.) But anyway, the slicing works after the resize code is put in place even when resizing is unnecessary:

经过一些更多的实验,我找到了以下解决方案(我仍然不知道为什么它不能像最初编写的那样工作。)但无论如何,即使在不需要调整大小的情况下,也可以在调整大小代码到位后进行切片:

if(newDim != 320.0){
            CGSize finalSize = CGSizeMake(320.0, 320.0);
            UIGraphicsBeginImageContext(finalSize);
            [squareImage drawInRect:CGRectMake(0, 0, finalSize.width, finalSize.height)];
            playImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
}else{
            CGSize finalSize = CGSizeMake(320.0, 320.0);
            UIGraphicsBeginImageContext(finalSize);
            [squareImage drawInRect:CGRectMake(0, 0, finalSize.width, finalSize.height)];
            playImage = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
}

Anyone has any clue WHY this is going on?

任何人都知道为什么会这样?

P.S. Yes, if/else is no longer required here. Removing it beforeI knew it was going to work would be stupid, though.

PS 是的,这里不再需要 if/else。但是,我知道它会起作用之前将其删除将是愚蠢的。

回答by executor21

Just out of curiosity, why did you make your mutable array with bound of 0 when you know you're going to put 16 things in it?

只是出于好奇,当您知道要在其中放入 16 项内容时,为什么还要使可变数组的边界为 0?

Well, aside from that, I've tried the basic techniques you used for resizing and slicing (I did not need to crop, because I'm working with images that are already square) and I'm unable to reproduce your problem in the simulator. You might want to try breaking your code into three separate functions (crop to square, resize, and slice into pieces) and then test the three separately so you can figure out which of the three steps is causing the problems (ie. input images that you've manipulated in a normal graphics program instead of using objective c and then inspect what you get back out!).

好吧,除此之外,我已经尝试了您用于调整大小和切片的基本技术(我不需要裁剪,因为我正在处理已经是方形的图像)并且我无法在模拟器。您可能想尝试将代码分解为三个独立的函数(裁剪成正方形、调整大小和切片),然后分别测试这三个函数,以便找出导致问题的三个步骤中的哪一个(即输入图像您已经在普通图形程序中进行了操作,而不是使用目标 c,然后检查您得到的结果!)。

I'll attach my versions of the resize and slice functions below, which will hopefully be helpful. It was nice to have your versions to look at, since I didn't have to find all the methods by myself for once. :)

我将在下面附上我的调整大小和切片功能版本,希望对您有所帮助。很高兴看到您的版本,因为我不必自己一次找到所有方法。:)

Just as a note, the two dimensional array mentioned is my own class built out of NSMutableArrays, but you could easily implement your own version or use a flat NSMutableArray instead. ;)

请注意,上面提到的二维数组是我自己用 NSMutableArrays 构建的类,但您可以轻松实现自己的版本或使用平面 NSMutableArray。;)

// cut the given image into a grid of equally sized smaller images
// this assumes that the image can be equally divided in the requested increments
// the images will be stored in the return array in [row][column] order
+ (TwoDimensionalArray *) chopImageIntoGrid : (UIImage *) originalImage : (int) numberOfRows : (int) numberOfColumns
{   
// figure out the size of our tiles
int tileWidth = originalImage.size.width / numberOfColumns;
int tileHeight = originalImage.size.height / numberOfRows;

// create our return array
TwoDimensionalArray * toReturn = [[TwoDimensionalArray alloc] initWithBounds : numberOfRows 
                                                                             : numberOfColumns];

// get a CGI image version of our image
CGImageRef cgVersionOfOriginal = [originalImage CGImage];

// loop to chop up each row
for(int row = 0; row < numberOfRows ; row++){
    // loop to chop up each individual piece by column
    for (int column = 0; column < numberOfColumns; column++)
    {
        CGImageRef tempImage = 
                CGImageCreateWithImageInRect(cgVersionOfOriginal, 
                                             CGRectMake(column * tileWidth, 
                                                        row * tileHeight, 
                                                        tileWidth, 
                                                        tileHeight));
        [toReturn setObjectAt : row : column : [UIImage imageWithCGImage:tempImage]];
    }
}

// now return the set of images we created
return [toReturn autorelease];
}

// this method resizes an image to the requested dimentions
// be a bit careful when using this method, since the resize will not respect
// the proportions of the image
+ (UIImage *) resize : (UIImage *) originalImage : (int) newWidth : (int) newHeight
{   
// translate the image to the new size
CGSize newSize = CGSizeMake(newWidth, newHeight); // the new size we want the image to be
UIGraphicsBeginImageContext(newSize); // downside: this can't go on a background thread, I'm told
[originalImage drawInRect : CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); // get our new image
UIGraphicsEndImageContext();

// return our brand new image
return newImage;
}

Eva Schiffer

伊娃·希弗