/*
 * The MIT License
 *
 * Copyright (c) 2011 Paul Solt, PaulSolt@gmail.com
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */
// http://paulsolt.com/2010/09/ios-converting-uiimage-to-rgba8-bitmaps-and-back/
// 全体的にModefied 2013/05/11 by AIG-Soft

#import "ImageHelper.h"
#import "malloc2.h"


@implementation ImageHelper

+ (unsigned char *)convertUIImageToBitmapRGBA8:(UIImage *)image
{
	// Modified 2013/5/11 AIG-Soft
	return [self convertUIImageToBitmap:image bitmapInfo:kCGImageAlphaPremultipliedLast];
}

+ (void *)convertUIImageToBitmap:(UIImage *)image bitmapInfo:(CGBitmapInfo)bitmapInfo
// Modified from original convertUIImageToBitmapRGBA8
// by 2013/5/11 AIG-Soft
// 必要に応じてというかbitmapInfoに応じて読み替える
{
	nslog(@"convertUIImageToBitmap:image=%@",image);
	
	CGImageRef imageRef = image.CGImage;

	// Create a bitmap context to draw the UIImage into
	CGContextRef context = [self newBitmapContextFromImage:imageRef bitmapInfo:bitmapInfo];
	nslog(@"context=%p",context);
	if (!context) {
		return NULL;
	}

	size_t width  = CGImageGetWidth( imageRef);
	size_t height = CGImageGetHeight(imageRef);
	nslog(@"image.size=%ld*%ld",width,height);

	CGRect rect = CGRectMake(0, 0, width, height);

	// Draw image into the context to get the raw image data
	CGContextDrawImage(context, rect, imageRef);

	// Get a pointer to the data	
	unsigned char *newBitmap  = NULL;
	unsigned char *bitmapData = (unsigned char *)CGBitmapContextGetData(context);
	if (bitmapData!=NULL) {
		// Copy the data and release the memory (return memory allocated with new)
		size_t bytesPerRow = CGBitmapContextGetBytesPerRow(context);
		size_t bufferSize  = bytesPerRow * height;
		nslog(@"bytesPerRow=%ld/bufferSize=%ld",bytesPerRow,bufferSize);

		newBitmap = (unsigned char *)malloc2(bufferSize);
		if (newBitmap!=NULL) {	// Copy the data
			memcpy((char *)newBitmap,(char *)bitmapData,bufferSize);
#if 0
			nslog(@"bitmap.dat");
			NSData *data=[NSData dataWithBytes:newBitmap length:bufferSize];
			[data writeToFile:TestFile(@"bitmap.dat") atomically:YES];
#endif
		}
		free2(bitmapData);
	} else { // bitmapData==NULL
		nslog(@"Error getting bitmap pixel data\n");
	}
	CGContextRelease(context);

	return (void *)newBitmap;
}

//----------------------------------------------------------------------------------

+ (CGContextRef)newBitmapRGBA8ContextFromImage:(CGImageRef)image
{
	// Modified 2013/5/11 AIG-Soft
	return [self newBitmapContextFromImage:image bitmapInfo:kCGImageAlphaPremultipliedLast];
}

+ (CGContextRef)newBitmapContextFromImage:(CGImageRef)image bitmapInfo:(CGBitmapInfo)bitmapInfo
// Modified from original newBitmapRGBA8ContextFromImage
// by 2013/5/11 AIG-Soft
{
	nslog(@"newBitmapContextFromImage");

	size_t width 	= CGImageGetWidth( image);
	size_t height 	= CGImageGetHeight(image);
	nslog(@"image.size=%ld*%ld",width,height);
	
	size_t bitsPerPixel 	= 32;
	size_t bitsPerComponent = 8;
	size_t bytesPerPixel 	= bitsPerPixel / bitsPerComponent;
	size_t bytesPerRow 		= width * bytesPerPixel;
	size_t bufferSize  		= bytesPerRow * height;
	nslog(@"bytesPerRow=%ld/bufferSize=%ld",bytesPerRow,bufferSize);

	CGContextRef context = NULL;

	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
	if (colorSpace==NULL) {
		nslog(@"Error allocating color space RGB");
	} else {
		// Allocate memory for image data
		uint32_t *bitmapData = (uint32_t *)malloc2(bufferSize);
		if (bitmapData==NULL) {
			nslog(@"Error allocating memory for bitmap");
		} else {
			// Create bitmap context
			context = CGBitmapContextCreate(bitmapData, 
											width, 
											height, 
											bitsPerComponent, 
											bytesPerRow, 
											colorSpace,
											bitmapInfo
											);
			if (context==NULL) {
				free2(bitmapData);
				nslog(@"Bitmap context not created");
			}
			// V2.5デバッグ : これが必須
			// png(で透明付き)だけなのかわからないが、1ライン分のデータは存在するところまでしかなく、それ以降は書き換えられないので予めクリアしておく必要がある
			//   01234567
			// 0 @@@@____	こういうデータの場合、行後ろの____分はデータが存在せず、bitmapへの展開上はy=0:x=0〜3/y=1:x=0〜5/y=2:x=0〜7
			// 1 __@@@@__	と格納される。故にy=0:x=4〜7やy=1:x=6,7は書き換えられない＝確保したバッファーの内容そのままとなる
			// 2 ____@@@@	これを回避するためバッファーをクリアしておく必要がある。
			memset(bitmapData,0,bufferSize);
		}
		CGColorSpaceRelease(colorSpace);
	}
	return context;
}

//----------------------------------------------------------------------------------

+ (UIImage *)convertBitmapRGBA8ToUIImage:(unsigned char *)buffer
							   withWidth:(int)width
							  withHeight:(int)height
// Modified 2013/5/11 AIG-Soft
{
	return [self convertBitmapUIImage:buffer withWidth:width withHeight:height bitmapInfo:kCGImageAlphaPremultipliedLast];
}

+ (UIImage *)convertBitmapUIImage:(unsigned char *)buffer
								withWidth:(int)width
							   withHeight:(int)height
								bitmapInfo:(CGBitmapInfo)bitmapInfo
// Modified from original convertBitmapRGBA8ToUIImage
// by 2013/5/11 AIG-Soft
{
	nslog(@"convertBitmapUIImage");

	UIImage *image = nil;
	
	size_t bufferSize = width * height * 4; // RGBAで4バイト
	CGDataProviderRef provider    = CGDataProviderCreateWithData(NULL, buffer, bufferSize, NULL);
	CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
	if (colorSpaceRef == NULL) {
		nslog(@"Error allocating color space");
	} else {
		size_t bitsPerComponent = 8;
		size_t bitsPerPixel = 32;
		size_t bytesPerRow  = 4 * width;

		CGImageRef iref = CGImageCreate(width, 
										height, 
										bitsPerComponent, 
										bitsPerPixel, 
										bytesPerRow, 
										colorSpaceRef, 
										bitmapInfo, 
										provider,	// data provider
										NULL,		// decode
										YES,		// should interpolate
										kCGRenderingIntentDefault);

		uint32_t* pixels = (uint32_t*)malloc2(bufferSize);
		if (pixels == NULL) {
			nslog(@"Error: Memory not allocated for bitmap");
		} else { // pixels!=NULL
			memset(pixels,0,bufferSize); // V2.5 : 念のため
			CGContextRef context = CGBitmapContextCreate(pixels,
														 width, 
														 height, 
														 bitsPerComponent, 
														 bytesPerRow, 
														 colorSpaceRef,
														 bitmapInfo);

			if (context == NULL) {
				nslog(@"Error context not created");
			} else {
				CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), iref);
				CGImageRef imageRef = CGBitmapContextCreateImage(context);

				// Support both iPad 3.2 and iPhone 4 Retina displays with the correct scale
				if ([UIImage respondsToSelector:@selector(imageWithCGImage:scale:orientation:)]) {
					float scale = [[UIScreen mainScreen] scale];
					image = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
				} else {
					image = [UIImage imageWithCGImage:imageRef];
				}
				CGImageRelease(imageRef);
				CGContextRelease(context);	
			}
			free2(pixels);
		}
		CGImageRelease(iref);
		CGColorSpaceRelease(colorSpaceRef);
	}
	CGDataProviderRelease(provider);

	return image;
}

@end