Question

I am working with a music player that takes images from the ID3 resources from the MP3. I've encountered that certain ArtWorks have transparency. (The images have transparent parts). This is causing my app to load those images very slow. I need to find out a way to remove the transparency of the UIImage before showing it. Or are there any other suggestions?

"Replace the transparent part of the image with a color such as white"

Here's my code if necessary:

NSURL *url = ad.audioPlayer.url;
AVAsset *asset = [AVAsset assetWithURL:url];
for (AVMetadataItem *metadataItem in asset.commonMetadata) {
    if ([metadataItem.commonKey isEqualToString:@"artwork"]){
        NSDictionary *imageDataDictionary = (NSDictionary *)metadataItem.value;
        NSData *imageData = [imageDataDictionary objectForKey:@"data"];
        UIImage *image = [UIImage imageWithData:imageData];

        // This is the image and the place in code where I want to convert it

       _artworkImageView.image = image;
       _bgImage.image = [image applyDarkEffect];

    }
}
Was it helpful?

Solution 2

Try this...

//First create a white image that has an equal size with your image.

        CGImageRef sourceImage = yourImage.CGImage;

        CFDataRef theData;
        theData = CGDataProviderCopyData(CGImageGetDataProvider(sourceImage));

        UInt8 *pixelData = (UInt8 *) CFDataGetBytePtr(theData);

        int dataLength = CFDataGetLength(theData);

        int red = 0;
        int green = 1;
        int blue = 2;
        int alpha = 3;

        for (int i = 0; i < (dataLength); i += 4) {

        //create white pixels    

            int r = 255;
            int b = 255;
            int g = 255;
            int al = 255;


            pixelData[i + red] = r;
            pixelData[i + blue] = b;
            pixelData[i + green] = g;
            pixelData[i + alpha] = al;


        }

        CGContextRef context;
        context = CGBitmapContextCreate(pixelData,
                                        CGImageGetWidth(sourceImage),
                                        CGImageGetHeight(sourceImage),
                                        8,
                                        CGImageGetBytesPerRow(sourceImage),
                                        CGImageGetColorSpace(sourceImage),
                                        kCGImageAlphaPremultipliedLast);

        CGImageRef newCGImage = CGBitmapContextCreateImage(context);

        CGContextRelease(context);
        CFRelease(theData);

        //Now that you have your image use CIFilter "CISourceOverCompositing".
        //this adds your white image as the background.

        UIImageOrientation originalOrientation = origim.imageOrientation;
        data3 = UIImagePNGRepresentation(origim);
        CIImage *result = [CIImage imageWithData:data3];
        CIImage *result2 = [CIImage imageWithCGImage:newCGImage];

        CIContext *contextt = [CIContext contextWithOptions:nil];

        CIFilter *addBackground = [CIFilter filterWithName:@"CISourceOverCompositing"];
        [addBackground setDefaults];
        [addBackground setValue:result forKey:@"inputImage"];
        [addBackground setValue:result2 forKey:@"inputBackgroundImage"];
        result = [addBackground valueForKey:@"outputImage"];

        CGImageRef imgRef = [contextt createCGImage:result fromRect:result.extent];
        image = [[UIImage alloc] initWithCGImage:imgRef scale:1.0 orientation:originalOrientation];
        CGImageRelease(imgRef);

OTHER TIPS

I also had the sample problem and actually I did not want to remove the alpha channel but just to replace the transparent color with white color. I tried to remove alpha color as suggested in the comment in Remove alpha channel from UIImage but the annoying thing was after doing that the transparent color became black and I could not figure out how to make it white..

Eventually I ended up with just drawing a white background under the image with transparent parts without touching the alpha channel.

Code here:

// check if there is alpha channel
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(wholeTemplate.CGImage);
if (alpha == kCGImageAlphaPremultipliedLast || alpha == kCGImageAlphaPremultipliedFirst ||
    alpha == kCGImageAlphaLast || alpha == kCGImageAlphaFirst || alpha == kCGImageAlphaOnly)
{
    // create the context with information from the original image
    CGContextRef bitmapContext = CGBitmapContextCreate(NULL,
                                                       wholeTemplate.size.width,
                                                       wholeTemplate.size.height,
                                                       CGImageGetBitsPerComponent(wholeTemplate.CGImage),
                                                       CGImageGetBytesPerRow(wholeTemplate.CGImage),
                                                       CGImageGetColorSpace(wholeTemplate.CGImage),
                                                       CGImageGetBitmapInfo(wholeTemplate.CGImage)
                                                       );

    // draw white rect as background
    CGContextSetFillColorWithColor(bitmapContext, [UIColor whiteColor].CGColor);
    CGContextFillRect(bitmapContext, CGRectMake(0, 0, wholeTemplate.size.width, wholeTemplate.size.height));

    // draw the image
    CGContextDrawImage(bitmapContext, CGRectMake(0, 0, wholeTemplate.size.width, wholeTemplate.size.height), wholeTemplate.CGImage);
    CGImageRef resultNoTransparency = CGBitmapContextCreateImage(bitmapContext);

    // get the image back
    wholeTemplate = [UIImage imageWithCGImage:resultNoTransparency];

    // do not forget to release..
    CGImageRelease(resultNoAlpha);
    CGContextRelease(bitmapContext);
}

Try this code ....

+ (UIImage *)removeTransparentArea:(UIImage *)image {
  CGRect newRect = [self cropRectForImage:image];
  CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, newRect);
  UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
  CGImageRelease(imageRef);

  return finalImage;
}

+ (CGRect)cropRectForImage:(UIImage *)image {

  CGImageRef cgImage = image.CGImage;
  CGContextRef context = [self createARGBBitmapContextFromImage:cgImage];
  if (context == NULL) return CGRectZero;

  int width = image.size.width;
  int height = image.size.height;
  CGRect rect = CGRectMake(0, 0, width, height);

  CGContextDrawImage(context, rect, cgImage);

  unsigned char *data = CGBitmapContextGetData(context);
  CGContextRelease(context);

  //Filter through data and look for non-transparent pixels.
  int lowX = width;
  int lowY = height;

  int highX = 0;
  int highY = 0;
  if (data != NULL) {
    for (int y=0; y<height; y++) {
      for (int x=0; x<width; x++) {
        int pixelIndex = ((width * y) + x) * 4 /* 4 for A, R, G, B */;
        if (data[pixelIndex] != 0) { //Alpha value is not zero; pixel is not transparent.
          if (x < lowX) lowX = x;
          if (x > highX) highX = x;
          if (y < lowY) lowY = y;
          if (y > highY) highY = y;
        }
      }
    }
    free(data);
  } else {
    return CGRectZero;
  }

  return CGRectMake(lowX, lowY, highX-lowX, highY-lowY);
}


+ (CGContextRef)createARGBBitmapContextFromImage:(CGImageRef)inImage {

  CGContextRef context = NULL;
  CGColorSpaceRef colorSpace;
  void *bitmapData;
  int bitmapByteCount;
  int bitmapBytesPerRow;

  // Get image width, height. We'll use the entire image.
  size_t width = CGImageGetWidth(inImage);
  size_t height = CGImageGetHeight(inImage);

  // Declare the number of bytes per row. Each pixel in the bitmap in this
  // example is represented by 4 bytes; 8 bits each of red, green, blue, and
  // alpha.
  bitmapBytesPerRow = ((int)width * 4);
  bitmapByteCount = (bitmapBytesPerRow * (int)height);

  // Use the generic RGB color space.
  colorSpace = CGColorSpaceCreateDeviceRGB();
  if (colorSpace == NULL) return NULL;

  // Allocate memory for image data. This is the destination in memory
  // where any drawing to the bitmap context will be rendered.
  bitmapData = malloc( bitmapByteCount );
  if (bitmapData == NULL)
  {
    CGColorSpaceRelease(colorSpace);
    return NULL;
  }

  // Create the bitmap context. We want pre-multiplied ARGB, 8-bits
  // per component. Regardless of what the source image format is
  // (CMYK, Grayscale, and so on) it will be converted over to the format
  // specified here by CGBitmapContextCreate.
  context = CGBitmapContextCreate (bitmapData,
                                   width,
                                   height,
                                   8,      // bits per component
                                   bitmapBytesPerRow,
                                   colorSpace,
                                   kCGImageAlphaPremultipliedFirst);
  if (context == NULL) free (bitmapData);

  // Make sure and release colorspace before returning
  CGColorSpaceRelease(colorSpace);

  return context;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top