Обрезать UIImage to alpha - PullRequest
       22

Обрезать UIImage to alpha

9 голосов
/ 29 июня 2011

У меня довольно большое, почти полноэкранное изображение, которое я собираюсь показать на iPad.Изображение примерно на 80% прозрачно.Мне нужно на клиенте определить ограничивающий прямоугольник непрозрачных пикселей, а затем обрезать до этого ограничивающего прямоугольника.

Сканирование других вопросов здесь в StackOverflow и чтение некоторых документов CoreGraphics, думаю, я мог бы выполнитьэто по:

CGBitmapContextCreate(...) // Use this to render the image to a byte array

 ..
   - iterate through this byte array to find the bounding box
 ..

CGImageCreateWithImageInRect(image, boundingRect);

Это просто кажется очень неэффективным и неуклюжим.Есть ли что-то умное, что я могу сделать с масками CGImage или что-то, что использует для этого ускорение графики устройства?

Ответы [ 3 ]

13 голосов
/ 27 сентября 2012

Спасибо пользователю 404709 за всю тяжелую работу.Ниже также код обрабатывает изображения сетчатки и освобождает CFDataRef.

- (UIImage *)trimmedImage {

    CGImageRef inImage = self.CGImage;
    CFDataRef m_DataRef;
    m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));

    UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef);

    size_t width = CGImageGetWidth(inImage);
    size_t height = CGImageGetHeight(inImage);

    CGPoint top,left,right,bottom;

    BOOL breakOut = NO;
    for (int x = 0;breakOut==NO && x < width; x++) {
        for (int y = 0; y < height; y++) {
            int loc = x + (y * width);
            loc *= 4;
            if (m_PixelBuf[loc + 3] != 0) {
                left = CGPointMake(x, y);
                breakOut = YES;
                break;
            }
        }
    }

    breakOut = NO;
    for (int y = 0;breakOut==NO && y < height; y++) {

        for (int x = 0; x < width; x++) {

            int loc = x + (y * width);
            loc *= 4;
            if (m_PixelBuf[loc + 3] != 0) {
                top = CGPointMake(x, y);
                breakOut = YES;
                break;
            }

        }
    }

    breakOut = NO;
    for (int y = height-1;breakOut==NO && y >= 0; y--) {

        for (int x = width-1; x >= 0; x--) {

            int loc = x + (y * width);
            loc *= 4;
            if (m_PixelBuf[loc + 3] != 0) {
                bottom = CGPointMake(x, y);
                breakOut = YES;
                break;
            }

        }
    }

    breakOut = NO;
    for (int x = width-1;breakOut==NO && x >= 0; x--) {

        for (int y = height-1; y >= 0; y--) {

            int loc = x + (y * width);
            loc *= 4;
            if (m_PixelBuf[loc + 3] != 0) {
                right = CGPointMake(x, y);
                breakOut = YES;
                break;
            }

        }
    }


    CGFloat scale = self.scale;

    CGRect cropRect = CGRectMake(left.x / scale, top.y/scale, (right.x - left.x)/scale, (bottom.y - top.y) / scale);
    UIGraphicsBeginImageContextWithOptions( cropRect.size,
                                           NO,
                                           scale);
    [self drawAtPoint:CGPointMake(-cropRect.origin.x, -cropRect.origin.y)
           blendMode:kCGBlendModeCopy
               alpha:1.];
    UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    CFRelease(m_DataRef);
    return croppedImage;
}
8 голосов
/ 09 февраля 2012

Я создал категорию на UImage, которая делает это, если кому-то это нужно ...

+ (UIImage *)cropTransparencyFromImage:(UIImage *)img {

    CGImageRef inImage = img.CGImage;           
    CFDataRef m_DataRef;  
    m_DataRef = CGDataProviderCopyData(CGImageGetDataProvider(inImage));  
    UInt8 * m_PixelBuf = (UInt8 *) CFDataGetBytePtr(m_DataRef);  

    int width = img.size.width;
    int height = img.size.height;

    CGPoint top,left,right,bottom;

    BOOL breakOut = NO;
    for (int x = 0;breakOut==NO && x < width; x++) {
        for (int y = 0; y < height; y++) {
            int loc = x + (y * width);
            loc *= 4;
            if (m_PixelBuf[loc + 3] != 0) {
                left = CGPointMake(x, y);
                breakOut = YES;
                break;
            }
        }
    }

    breakOut = NO;
    for (int y = 0;breakOut==NO && y < height; y++) {

        for (int x = 0; x < width; x++) {

            int loc = x + (y * width);
            loc *= 4;
            if (m_PixelBuf[loc + 3] != 0) {
                top = CGPointMake(x, y);
                breakOut = YES;
                break;
            }

        }
    }

    breakOut = NO;
    for (int y = height-1;breakOut==NO && y >= 0; y--) {

        for (int x = width-1; x >= 0; x--) {

            int loc = x + (y * width);
            loc *= 4;
            if (m_PixelBuf[loc + 3] != 0) {
                bottom = CGPointMake(x, y);
                breakOut = YES;
                break;
            }

        }
    }

    breakOut = NO;
    for (int x = width-1;breakOut==NO && x >= 0; x--) {

        for (int y = height-1; y >= 0; y--) {

            int loc = x + (y * width);
            loc *= 4;
            if (m_PixelBuf[loc + 3] != 0) {
                right = CGPointMake(x, y);
                breakOut = YES;
                break;
            }

        }
    }


    CGRect cropRect = CGRectMake(left.x, top.y, right.x - left.x, bottom.y - top.y);

    UIGraphicsBeginImageContextWithOptions( cropRect.size,
                                           NO,
                                           0.);
    [img drawAtPoint:CGPointMake(-cropRect.origin.x, -cropRect.origin.y)
           blendMode:kCGBlendModeCopy
               alpha:1.];
    UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return croppedImage;
}
0 голосов
/ 11 июля 2011

Нет хитрой хитрости, чтобы устройство работало, но есть несколько способов ускорить задачу или минимизировать влияние на пользовательский интерфейс.

Сначала рассмотрим необходимость ускорения этой задачи.Простая итерация по этому байтовому массиву может пройти достаточно быстро.Возможно, нет необходимости вкладывать средства в оптимизацию этой задачи, если приложение просто вычисляет это один раз за прогон или в ответ на выбор пользователя, который занимает по крайней мере несколько секунд между вариантами выбора.

Если ограничивающий прямоугольник нетребуется некоторое время после того, как изображение становится доступным, эта итерация может быть запущена в отдельном потоке.Таким образом, расчет не блокирует основной поток интерфейса.Grand Central Dispatch может упростить использование отдельного потока для этой задачи.

Если задача должна быть ускорена, возможно, это обработка видеоизображений в реальном времени, тогда параллельная обработка данных может помочь.Платформа Accelerate может помочь в настройке SIMD-расчетов для данных.Или, чтобы действительно добиться производительности с помощью этой итерации, код на языке ассемблера ARM, использующий операции NEON SIMD, может получить отличные результаты при значительных усилиях по разработке.

Последний вариант - изучить лучший алгоритм.Существует огромная работа по обнаружению особенностей в изображениях.Алгоритм обнаружения края может быть быстрее, чем простая итерация по байтовому массиву.Возможно, в будущем Apple добавит в Core Graphics возможности обнаружения краев, которые могут быть применены в этом случае.Внедренная Apple возможность обработки изображений может не совсем соответствовать этому случаю, но реализация Apple должна быть оптимизирована для использования возможностей SIMD или GPU iPad, что приведет к повышению общей производительности.

...