2009-07-15 43 views
10

Tôi có mã này để che một hình ảnh. Về cơ bản, tôi chỉ làm việc với hình ảnh PNG. Vì vậy, tôi có hình ảnh PNG 300x400 với 24 bit màu (PNG-24). Tôi không chắc chắn nếu nó cũng có một kênh alpha. Nhưng không có sự minh bạch trong nó.Bất kỳ ý tưởng nào tại sao mã mặt nạ hình ảnh này không hoạt động?

Sau đó, có mặt nạ hình ảnh là PNG-8bit không có kênh alpha. Nó chỉ là đen, xám và trắng.

Tôi tạo cả hai hình ảnh dưới dạng UIImage. Cả hai hiển thị chính xác khi đưa chúng vào UIImageView.

Sau đó, tôi tạo ra một UIImage ra trong số họ, trong đó có kết quả của các hoạt động tạo mặt nạ, với mã này:

+ (UIImage*)maskImage:(UIImage*)image withMask:(UIImage*)maskImage { 
CGImageRef maskRef = maskImage.CGImage; 
CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), 
      CGImageGetHeight(maskRef), 
      CGImageGetBitsPerComponent(maskRef), 
      CGImageGetBitsPerPixel(maskRef), 
      CGImageGetBytesPerRow(maskRef), 
      CGImageGetDataProvider(maskRef), NULL, false); 
CGImageRef masked = CGImageCreateWithMask([image CGImage], mask); 
return [UIImage imageWithCGImage:masked]; 
} 

đây là những gì tôi làm với điều đó:

UIImage *image = [UIImage imageNamed:@"coloredImagePNG24.png"]; 
UIImage *maskImage = [UIImage imageNamed:@"theMaskPNG8_Grayscale_NoAlpha.png"]; 
UIImage *maskedImage = [MyGraphicUtils maskImage:image withMask:maskImage]; 
UIImageView *testImageView = [[UIImageView alloc] initWithImage:maskedImage]; 
testImageView.backgroundColor = [UIColor clearColor]; 
testImageView.opaque = NO; 

Sau tất cả những gì, colorImagePNG24.png vẫn giữ nguyên nguyên vẹn. Không có mặt nạ nào đang xảy ra. Nhưng bây giờ điều kỳ lạ là: Nếu tôi xoay nó lại, tức là sử dụng hình ảnh này làm mặt nạ và mặt nạ làm mặt nạ màu, sau đó tôi nhận được một thứ rất xấu trong màu xám (nhưng bị che khuất;)).

Bất kỳ ý tưởng nào có vấn đề với mã của tôi?

CẬP NHẬT: Tôi vừa googled cho một b/w png khác để sử dụng làm mặt nạ. Và sau đó điều này đã làm việc! Nhưng cái tôi tự làm ra không hoạt động. Vì vậy, tôi giả định rằng mã có vấn đề giải mã hình ảnh lớn. Tôi sẽ phải "bình thường hóa" các hình ảnh theo một định dạng cụ thể, để nó hoạt động.

Trả lời

0

Xem nếu nó hoạt động tốt hơn bất kỳ theo cách này:

+ (UIImage*)maskImage:(UIImage*)image withMask:(UIImage*)maskImage { 
    UIGraphicsBeginImageContext(image.size); 
    CGImageRef maskRef = maskImage.CGImage; 
    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), CGImageGetHeight(maskRef), CGImageGetBitsPerComponent(maskRef), CGImageGetBitsPerPixel(maskRef), CGImageGetBytesPerRow(maskRef), CGImageGetDataProvider(maskRef), NULL, false); 
    CGImageRef masked = CGImageCreateWithMask(image.CGImage, mask); 
    UIImage* result = [UIImage imageWithData:UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext())]; 
    UIGraphicsEndImageContext(); 
    CGImageRelease(mask); 
    CGImageRelease(masked); 
    return result; 
} 
+1

Mặc dù trông khá, trong trường hợp của tôi nó chỉ làm cho hình ảnh hoàn toàn trong suốt. Xem cập nhật của tôi ở trên. Tôi đã tìm ra điều gì đó kỳ lạ. – Thanks

+1

Tôi đã sử dụng một biến thể trên đoạn mã trên với các mặt nạ được tạo trong Photoshop được chuyển đổi thành "Grayscale" và được xuất dưới dạng PNG 24 bit. – Ramin

+0

Nếu bạn muốn sử dụng mã trên, hãy đảm bảo tệp hình ảnh của bạn chứa mặt nạ là PNG 24 bit làm _not_ có kênh alpha. Pixelmator, ví dụ, không cho bạn biết thông tin này. Bạn cần sử dụng Photoshop hoặc GIMP. –

0

Dave, tôi đã nghe nói về hình ảnh PNG có một kênh Alpha có thể ảnh hưởng đến mã như vậy.

Tôi chỉ googled PNG Alpha Channel và đã đưa ra liên kết này: link text

Vì vậy, hãy chắc chắn rằng bạn đang sử dụng PNG có một Alpha Channel thiết lập đúng

3

Các CGImageMaskCreate không không làm gì bạn mong đợi. Đặc biệt:

Đối với mặt nạ hình ảnh đó là 2, 4, hoặc 8 bit cho mỗi thành phần, mỗi thành phần được ánh xạ tới một phạm vi từ 0 đến 1 bởi nhân rộng sử dụng công thức này:

1/(2^bit cho mỗi thành phần - 1)

Ví dụ: mặt nạ 4 bit có giá trị nằm trong khoảng từ 0 đến 15. Các giá trị này được chia tỷ lệ 1/15 sao cho mỗi thành phần nằm trong khoảng từ 0 đến 1. Giá trị thành phần đó rescale to 0 hoặc 1 hoạt động giống như cách chúng hoạt động đối với mặt nạ hình ảnh 1 bit. Các giá trị có tỷ lệ giữa 0 và 1 hoạt động như một alpha nghịch đảo. Tức là, màu tô được tô như thể nó có giá trị alpha (1 - MaskSampleValue). Ví dụ, nếu giá trị mẫu của mặt nạ 8 bit có tỷ lệ là 0,8, màu tô hiện tại được vẽ như thể nó có giá trị alpha là 0,2, tức là (1–0,8).

Tôi đoán là hàm sẽ diễn giải lại dữ liệu RGB của bạn ở định dạng khác này, làm méo mó các giá trị màu. Bạn đã thử sử dụng mặt nạ CGImage trực tiếp chưa?

Nhanh chỉnh sửa: những gì tôi có nghĩa là bằng cách "trực tiếp" chỉ là để viết

+ (UIImage*)maskImage:(UIImage*)image withMask:(UIImage*)maskImage 
{ 
    CGImageRef masked = CGImageCreateWithMask([image CGImage], [maskImage CGImage]); 
    return [UIImage imageWithCGImage:masked]; 
} 
5

Như bạn khám phá, cách bạn lưu tập tin có thể tạo sự khác biệt, bởi vì Lõi đồ họa là rất cụ thể về định dạng của bit nó sử dụng cho mặt nạ.

tôi đã tìm thấy rằng cách tốt nhất và đáng tin cậy nhất để tạo ra một mặt nạ hình ảnh từ một hình ảnh tùy ý là để làm điều này:

  1. Tạo một bối cảnh đồ họa bitmap đó là trong một định dạng có thể chấp nhận đối với mặt nạ hình ảnh (bạn không thể sử dụng UIGraphicsBeginImageContext() cho việc này)
  2. Vẽ hình ảnh của bạn vào ngữ cảnh đồ họa bitmap này
  3. Tạo mặt nạ hình ảnh từ các bit của ngữ cảnh đồ họa bitmap.

Hãy thử chức năng này:

CGImageRef createMaskWithImage(CGImageRef image) 
{ 
    int maskWidth    = CGImageGetWidth(image); 
    int maskHeight    = CGImageGetHeight(image); 
    // round bytesPerRow to the nearest 16 bytes, for performance's sake 
    int bytesPerRow    = (maskWidth + 15) & 0xfffffff0; 
    int bufferSize    = bytesPerRow * maskHeight; 

    // allocate memory for the bits 
    CFMutableDataRef dataBuffer = CFDataCreateMutable(kCFAllocatorDefault, 0); 
    CFDataSetLength(dataBuffer, bufferSize); 

    // the data will be 8 bits per pixel, no alpha 
    CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceGray(); 
    CGContextRef ctx   = CGBitmapContextCreate(CFDataGetMutableBytePtr(dataBuffer), 
                 maskWidth, maskHeight, 
                 8, bytesPerRow, colourSpace, kCGImageAlphaNone); 
    // drawing into this context will draw into the dataBuffer. 
    CGContextDrawImage(ctx, CGRectMake(0, 0, maskWidth, maskHeight), image); 
    CGContextRelease(ctx); 

    // now make a mask from the data. 
    CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(dataBuffer); 
    CGImageRef mask     = CGImageMaskCreate(maskWidth, maskHeight, 8, 8, bytesPerRow, 
                 dataProvider, NULL, FALSE); 

    CGDataProviderRelease(dataProvider); 
    CGColorSpaceRelease(colourSpace); 
    CFRelease(dataBuffer); 

    return mask; 
} 
-6

Bạn không thể tạo một hình ảnh, của bất cứ loại nào, với đồ họa lõi KHÔNG có một kênh alpha.

+2

Chính xác là sai. Bạn có thể. – awolf

6

Mã này có thể giúp bạn

- (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage { 

    CGImageRef maskRef = maskImage.CGImage; 

    CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), 
     CGImageGetHeight(maskRef), 
     CGImageGetBitsPerComponent(maskRef), 
     CGImageGetBitsPerPixel(maskRef), 
     CGImageGetBytesPerRow(maskRef), 
     CGImageGetDataProvider(maskRef), NULL, false); 

    CGImageRef masked = CGImageCreateWithMask([image CGImage], mask); 
    return [UIImage imageWithCGImage:masked]; 

} 

tham khảo này example demonstration

+7

Tính năng này hoạt động miễn là UIImage kết quả được hiển thị bằng UIImageView hoặc được vẽ theo ngữ cảnh hình ảnh mới theo cách thủ công. Nếu bạn cố gắng lưu hình ảnh vào tệp bằng cách sử dụng UIImagePNGRepresentation (yourMaskedImage), bạn sẽ mất mặt nạ. Chỉ cần FYI - Tôi đã kéo tóc của tôi ra trên này một chút. Ngoài ra ở cuối mã, bạn nên giải phóng một số tham chiếu để tránh rò rỉ bộ nhớ: CGImageRelease (maskedImageRef); CGImageRelease (mặt nạ); –

+0

Alex bình luận của người Ukraine giúp rất nhiều, cảm ơn! – Chengjiong

+0

Giờ bị lãng phí và bình luận của @ AlextheUkraan là câu trả lời. Cảm ơn bạn rất nhiều! – mxcl

1

Các dòng mã sau đây làm việc cho tôi

+(UIImage*)maskImageExt:(UIImage *)image withMask:(UIImage *)maskImage { 
     CGImageRef maskRef = maskImage.CGImage; 
     CGImageRef imageRef = image.CGImage; 

     CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), 
            CGImageGetHeight(maskRef), 
            CGImageGetBitsPerComponent(maskRef), 
            CGImageGetBitsPerPixel(maskRef), 
            CGImageGetBytesPerRow(maskRef), 
            CGImageGetDataProvider(maskRef), NULL, true); 

CGImageRef maskImageRef = CGImageCreateWithMask([image CGImage], mask); 

CGContextRef context = CGBitmapContextCreate(nil, 
              CGImageGetWidth(imageRef), 
              CGImageGetHeight(imageRef), 
              CGImageGetBitsPerComponent(imageRef), 
              CGImageGetBytesPerRow(imageRef), 
              CGImageGetColorSpace(imageRef), 
              CGImageGetBitmapInfo(imageRef)); 
CGRect imageRect = CGRectMake(0, 0, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); 
CGContextDrawImage(context, imageRect, maskImageRef); 
CGImageRef maskedImageRef = CGBitmapContextCreateImage(context); 
UIImage *maskedImage = [UIImage imageWithCGImage:maskedImageRef]; 

CGImageRelease(mask); 
CGContextRelease(context); 
CGImageRelease(maskedImageRef); 

return maskedImage; 

}

Các vấn đề liên quan