Search code examples
c#iosxamarin.iosimagingbit-depth

Convert 24bit image to 8bit in monotouch?


We have an image processing windows application where we are using lead tools for converting and images from 24/48 bit images to 8 bit images.

As an experiment I'm porting the application to iPad using MonoTouch and C#, now the LeadTools components are incompatible with Monotouch. Is there any alternate I can use? if not how can I convert 24/48 bit images to 8 bit?


Solution

  • To use Apple's imaging tools here is where I would start:

    1. Convert your raw bytes into a pixel format supported by the platform. See the Quartz 2D documentation on supported pixel formats.
      Note that iOS doesn't currently have a 24 or 48 bit format. However, if your 24 bit format is 8 bits per channel (RGB) you could add 8 bits of ignored alpha. (Alpha options are in MonoTouch.CoreGraphics.CGImageAlphaInfo)

    2. Convert your raw bytes into a CGImage. Here is an example of how to do that

          var provider = new CGDataProvider(bytes, 0, bytes.Length);
          int bitsPerComponent = 8;
          int components = 4;
          int height = bytes.Length / components / width;
          int bitsPerPixel = components * bitsPerComponent;
          int bytesPerRow = components * width;   // Tip:  When you create a bitmap graphics context, you’ll get the best performance if you make sure the data and bytesPerRow are 16-byte aligned.
          bool shouldInterpolate = false;
          var colorSpace = CGColorSpace.CreateDeviceRGB();
          var cgImage = new CGImage(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, 
                                    colorSpace, CGImageAlphaInfo.Last, provider,
                                    null, shouldInterpolate, CGColorRenderingIntent.Default);
      
    3. Use a Core Image Filter to convert to Monochrome

          var mono = new CIColorMonochrome
          {
              Color = CIColor.FromRgb(1, 1, 1),
              Intensity = 1.0f,
              Image = CIImage.FromCGImage(image)
          };
          CIImage output = mono.OutputImage;
          var context = CIContext.FromOptions(null);
          var renderedImage = context.CreateCGImage(output, output.Extent);
      
    4. Finally you can retrieve the raw bytes of that image by drawing into a CGBitmapContext constructed according to your desired parameters.

    I suspect this pipeline could be optimized, but it is a place to start. I'd be interested to hear what you end up with.