CGContextDrawLayerInRect из CGBitmapContext Создать сбой iPhone 7 Plus

У меня есть проект Objective C, который в какой-то момент берет фотографию из вашей библиотеки фотографий или с камеры, а затем нарезает их на маленькие квадраты (плитки) и в конечном итоге создает новые объекты UIImage из нарезанных квадратов.

Код отлично работает на моем старом iPhone 5 и на iPad Mini 2.

Однако на моем iPhone 7 Plus он выдает пустой вывод (а не нарезанные части моего ввода). IPad Mini 2 и iPhone 7 Plus работают под управлением iOS 10.3.3 и являются 64-разрядными устройствами.

Полная функция здесь:

-(void) createTilesFromImage:(UIImage*)img inRect:(CGRect)rect inContext:(CGContextRef)context {

    if (tilesDefined) {
            return;
    }

    tilesDefined = YES;


    // Tileboard layer
    CGSize tileboardsize = rect.size;
    tileboardrect = rect;

    // Chop image
    CGLayerRef imagetochop = CGLayerCreateWithContext(context, tileboardsize, NULL);
    CGContextRef ctx2 = CGLayerGetContext(imagetochop);
    UIGraphicsPushContext(ctx2);
    [img drawInRect:CGRectMake(0, 0, tileboardsize.width, tileboardsize.height)];
    UIGraphicsPopContext();

    // Tile layer size (CG & CA)
    tilesize = CGSizeMake(ceilf(tileboardsize.width / dims.x),ceilf( tileboardsize.height / dims.y ));

    // Bitmap context
    CGContextRef bmpContext = [[QPDrawing shared] newCGBitmapContextWithSize:tilesize withData:YES];

    // Create tile layers
    tiles = [[NSMutableArray alloc] initWithCapacity:dims.x * dims.y];
    int i = 0;
    for (int y = 0; y < dims.y; y++) {
            for (int x = 0; x < dims.x; x++) {
                    tileLayers[i] = CGLayerCreateWithContext(context, tilesize, NULL);               

                    CGContextRef squarecontext = CGLayerGetContext(tileLayers[i]);
                    CGPoint offset = CGPointMake(x * tileboardsize.width / dims.x * -1, y * tileboardsize.height / dims.y * -1);

                    // Invert the layer prior to drawing
                    CGContextTranslateCTM(squarecontext, 0, tilesize.height);
                    CGContextScaleCTM(squarecontext, 1.0, -1.0);
                    CGContextDrawLayerAtPoint(squarecontext, offset, imagetochop);

                    CGContextDrawLayerInRect(bmpContext, (CGRect){0,0,tilesize.width,tilesize.height}, tileLayers[i]);
                    CGImageRef imageRef = CGBitmapContextCreateImage( bmpContext );

                    [tiles addObject: [UIImage imageWithCGImage: imageRef]];

                    CGImageRelease(imageRef);

                    i++;
            }
    }

    // Cleanup
    CGLayerRelease(imagetochop);
    CGContextRelease(bmpContext);

    rect = CGRectInset(rect, 2, 2);
    CGContextAddRect(context, rect);
    CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:1 green:0 blue:0 alpha:1].CGColor);
    CGContextSetLineWidth(context, 2);
    CGContextStrokePath(context);
}

При вызове CGContextRef вызывается один внешний элемент, bmpContext - newCGBitmapContextWithSize: tileSize: withData. Код для этого бита ниже:

- (CGContextRef) newCGBitmapContextWithSize:(CGSize)size withData:(BOOL)includeData {

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    int width = (int)ceilf(size.width);
    int height = (int)ceilf(size.height);
    size_t bitsPerComponent = 8;
    size_t bytesPerPixel    = 4;
    size_t bytesPerRow      = (width * bitsPerComponent * bytesPerPixel + 7) / 8;
    size_t dataSize         = bytesPerRow * height;

    unsigned char *data = NULL; 
    if (includeData) {
            data = malloc(dataSize);
            memset(data, 0, dataSize);
    }

    CGContextRef context = CGBitmapContextCreate(data, size.width, size.height,
            bitsPerComponent, bytesPerRow, colorSpace,
            kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGColorSpaceRelease(colorSpace);
    return context;
}

Сначала я думал, что это вызов "drawInRect", который почему-то не работает, теперь я убежден, что это не так. Я думаю, что это как-то связано с вызовом CGBitmapContextCreate.

Спасибо!

2 ответа

Решение

Мне кажется, что вы делаете гораздо больше работы, чем нужно; возможно, вы обдумываете проблему, как разделить изображение на плитки. Возможно, вас заинтересует гораздо более простой способ. Это то, что я делаю в приложении Theme моего Diabelli. Это Swift, но я не думаю, что у вас возникнут проблемы с его чтением (у меня есть старый код Objective-C, если он вам действительно нужен).

Очевидно, я перебираю "плитки", на которые нужно разделить изображение. Я уже определил количество строк и столбцов, а также размер плитки, w от h, Исходное изображение im, Это все, что мне нужно сделать:

for row in 0..<ROWS {
    for col in 0..<COLS {
        UIGraphicsBeginImageContextWithOptions(CGSize(
            width: CGFloat(w),height: CGFloat(h)), true, 0)
        im.draw(at: CGPoint(x: CGFloat(-w*col),y: CGFloat(-h*row)))
        let tileImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        // do something with tileImage
    }
}

Мне удалось решить эту проблему, переключившись на 16 бит на компонент цвета и компонентов с плавающей запятой

- (CGContextRef) newCGBitmapContextWithSize:(CGSize)size withData:(BOOL)includeData {

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
int width = (int)ceilf(size.width);
int height = (int)ceilf(size.height);
size_t bitsPerComponent = 16; //8; <--CHANGED
size_t bytesPerPixel    = 8;  //4; <--CHANGED
size_t bytesPerRow      = (width * bitsPerComponent * bytesPerPixel + 7) / 8;
size_t dataSize         = bytesPerRow * height;

unsigned char *data = NULL; 
if (includeData) {
        data = malloc(dataSize);
        memset(data, 0, dataSize);
}

CGContextRef context = CGBitmapContextCreate(data, size.width, size.height,
        bitsPerComponent, bytesPerRow, colorSpace,
        kCGImageAlphaPremultipliedLast |
          kCGBitmapFloatComponents | kCGBitmapByteOrder16Little); // <-- CHANGED

CGColorSpaceRelease(colorSpace);
return context;
}

Это работало на всех устройствах, упомянутых выше.

Другие вопросы по тегам