title: Save UIImage as 8-bit Grayscale Bitmap
body: <p>I am trying to output a UIImage to an 8-bit grayscale bitmap, but I'm not very familiar with image manipulation, so I am at a loss on how to do this.  I followed this stackoverflow post (<a href="https://stackoverflow.com/questions/25126772/objective-c-save-uiimage-as-a-bmp-file">Objective C - save UIImage as a BMP file</a>) to create a UIImage category which can successfully generated a RGB 32-bit image, but I have been unable to manipulate the code to get it to output it in 8-bit grayscale.  I am trying to get the raw bytes for this image in order to pass on to a provided C library.</p>
  
  <p>Does it matter what kind of UIImage I am trying to generate the bitmap for?  Can it be any number of bits per pixel, bits per component, and alpha setting?  I have tried using this code on the 8-bit UIImage without alpha and a 32 bit with alpha, and both didn't create a bitmap that could be opened by OS X.</p>
  
  <p>I hope someone can help!  I've been banging my head for a few days!</p>
  
  <pre><code>- (NSData *)bitmapData
  {
      NSData          *bitmapData = nil;
      CGImageRef      image = self.CGImage;
      CGContextRef    context = NULL;
      CGColorSpaceRef colorSpace;
      UInt8           *rawData;
  
      size_t bitsPerPixel = 8;
      size_t bitsPerComponent = 8;
      size_t bytesPerPixel = bitsPerPixel / bitsPerComponent;
  
      size_t width = CGImageGetWidth(image);
      size_t height = CGImageGetHeight(image);
  
      size_t bytesPerRow = width * bytesPerPixel;
      size_t bufferLength = bytesPerRow * height;
  
      colorSpace = CGColorSpaceCreateDeviceGray();
  
      if (colorSpace)
      {
          // Allocate memory for raw image data
          rawData = (UInt8 *)calloc(bufferLength, sizeof(UInt8));
  
          if (rawData)
          {
              CGBitmapInfo bitmapInfo = (CGBitmapInfo)kCGImageAlphaNone;
              context = CGBitmapContextCreate(rawData,
                                              width,
                                              height,
                                              bitsPerComponent,
                                              bytesPerRow,
                                              colorSpace,
                                              bitmapInfo);
  
              if (context)
              {
                  CGRect rect = CGRectMake(0, 0, width, height);
  
                  CGContextTranslateCTM(context, 0, height);
                  CGContextScaleCTM(context, 1.0, -1.0);
                  CGContextDrawImage(context, rect, image);
  
                  bitmapData = [NSData dataWithBytes:rawData length:bufferLength];
  
                  CGContextRelease(context);
              }
  
              free(rawData);
          }
  
          CGColorSpaceRelease(colorSpace);
      }
  
      return bitmapData;
  }
  
  - (NSData *)bitmapFileHeaderData
  {
      CGImageRef image = self.CGImage;
      UInt32     width = (UInt32)CGImageGetWidth(image);
      UInt32     height = (UInt32)CGImageGetHeight(image);
  
      t_bitmap_header header;
  
      header.fileType = 0x4D42;
      header.fileSize = (height * width) + 54;
      header.reserved1 = 0;
      header.reserved2 = 0;
      header.bitmapOffset = 54;
      header.headerSize = 40;
      header.width = width;
      header.height = height;
      header.colorPlanes = 1;
      header.bitsPerPixel = 8;
      header.compression = 0;
      header.bitmapSize = height * width;
      header.horizontalResolution = 0;
      header.verticalResolution = 0;
      header.colorsUsed = 0;
      header.colorsImportant = 0;
  
      return [NSData dataWithBytes:&amp;header length:sizeof(t_bitmap_header)];
  }
  
  - (NSData *)bitmapDataWithFileHeader
  {
      NSMutableData *data = [NSMutableData dataWithData:[self bitmapFileHeaderData]];
      [data appendData:[self bitmapData]];
  
      return [NSData dataWithData:data];
  }
  </code></pre>