// this map translates the extensionData data we get passed in the constructor into a CLSID for WIC
// this is a pointer to navigate around static init issues
void ImageTargetFileWic::registerSelf()
{
	const int32_t PRIORITY = 2;
	ImageIoRegistrar::TargetCreationFunc func = ImageTargetFileWic::createRef;
	
	ImageIoRegistrar::registerTargetType( "png", func, PRIORITY, "png" );
	getExtensionMap()["png"] = &GUID_ContainerFormatPng;
	ImageIoRegistrar::registerTargetType( "tif", func, PRIORITY, "tif" ); ImageIoRegistrar::registerTargetType( "tiff", func, PRIORITY, "tif" );
	getExtensionMap()["tif"] = &GUID_ContainerFormatTiff;
	ImageIoRegistrar::registerTargetType( "jpg", func, PRIORITY, "jpg" ); ImageIoRegistrar::registerTargetType( "jpeg", func, PRIORITY, "jpg" ); ImageIoRegistrar::registerTargetType( "jpe", func, PRIORITY, "jpg" );
	getExtensionMap()["jpg"] = &GUID_ContainerFormatJpeg;
	ImageIoRegistrar::registerTargetType( "bmp", func, PRIORITY, "bmp" );
	getExtensionMap()["bmp"] = &GUID_ContainerFormatBmp;
// Disabling GIF because we don't handle converting to paletted formats yet
//	ImageIoRegistrar::registerTargetType( "gif", func, PRIORITY, "gif" );
//	getExtensionMap()["gif"] = GUID_ContainerFormatGif;
	ImageIoRegistrar::registerTargetType( "wmp", func, PRIORITY, "wmp" );
	getExtensionMap()["wmp"] = &GUID_ContainerFormatWmp;
}
ImageTargetFileWic::ImageTargetFileWic( DataTargetRef dataTarget, ImageSourceRef imageSource, const string &extensionData )
	: ImageTarget(), mDataTarget( dataTarget )
{
	mCodecGUID = getExtensionMap()[extensionData];

	setSize( imageSource->getWidth(), imageSource->getHeight() );

	// determine the pixel format we'll request
	WICPixelFormatGUID formatGUID;
	if( imageSource->hasAlpha() ) {
		bool premultAlpha = imageSource->isPremultiplied();
		// WIC doesn't support gray+alpha, so we need to do RGBA regardless
		if( imageSource->getDataType() == ImageIo::UINT8 )
			formatGUID = premultAlpha ? GUID_WICPixelFormat32bppPBGRA : GUID_WICPixelFormat32bppBGRA;
		else if( imageSource->getDataType() == ImageIo::UINT16 )
			formatGUID = premultAlpha ? GUID_WICPixelFormat64bppPRGBA : GUID_WICPixelFormat64bppRGBA;
		else
			formatGUID = premultAlpha ? GUID_WICPixelFormat128bppPRGBAFloat : GUID_WICPixelFormat128bppRGBAFloat;
	}
	else {
		if( imageSource->getColorModel() == ImageIo::CM_GRAY ) {
			if( imageSource->getDataType() == ImageIo::UINT8 )
				formatGUID = GUID_WICPixelFormat8bppGray;
			else if( imageSource->getDataType() == ImageIo::UINT16 )
				formatGUID = GUID_WICPixelFormat16bppGray;
			else
				formatGUID = GUID_WICPixelFormat32bppGrayFloat;
		}
		else {
			if( imageSource->getDataType() == ImageIo::UINT8 )
				formatGUID = GUID_WICPixelFormat24bppBGR;
			else if( imageSource->getDataType() == ImageIo::UINT16 )
				formatGUID = GUID_WICPixelFormat48bppRGB;
			else
				formatGUID = GUID_WICPixelFormat128bppRGBFloat;
		}
	}
	
	::HRESULT hr = S_OK;

	msw::initializeCom();

 // Create WIC factory
    IWICImagingFactory *IWICFactoryP = NULL;
    hr = ::CoCreateInstance( CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&IWICFactoryP) );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedLoad();
	shared_ptr<IWICImagingFactory> IWICFactory = msw::makeComShared( IWICFactoryP );

	IWICBitmapEncoder *encoderP = NULL;
	hr = IWICFactory->CreateEncoder( *mCodecGUID, 0, &encoderP );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedLoad();
	mEncoder = msw::makeComShared( encoderP );
	
	// create the stream		
	IWICStream *pIWICStream = NULL;
	hr = IWICFactory->CreateStream( &pIWICStream );
	if( ! SUCCEEDED(hr) )
		throw ImageIoExceptionFailedLoad();
	shared_ptr<IWICStream> stream = msw::makeComShared( pIWICStream );
	
	// initialize the stream based on properties of the cinder::DataSouce
	if( mDataTarget->providesFilePath() ) {
		hr = stream->InitializeFromFilename( toUtf16( mDataTarget->getFilePath() ).c_str(), GENERIC_WRITE );
		if( ! SUCCEEDED(hr) )
			throw ImageIoExceptionFailedLoad();
	}
	else {
		shared_ptr<msw::ComOStream> comOStream = msw::makeComShared( new msw::ComOStream( mDataTarget->getStream() ) );
		hr = stream->InitializeFromIStream( comOStream.get() );
		if( ! SUCCEEDED(hr) )
			throw ImageIoExceptionFailedLoad();		
	}
	
	hr = mEncoder->Initialize( stream.get(), WICBitmapEncoderNoCache );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedLoad();

	// create the frame encoder
	IPropertyBag2 *pPropertybag = NULL;
	IWICBitmapFrameEncode *pBitmapFrame = NULL;
	hr = mEncoder->CreateNewFrame( &pBitmapFrame, &pPropertybag );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedLoad();
	mBitmapFrame = msw::makeComShared( pBitmapFrame );

	hr = mBitmapFrame->Initialize( 0 );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedLoad();	
	
	hr = mBitmapFrame->SetSize( mWidth, mHeight );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedLoad();
	
	// ask for our ideal pixel format and then process the one we actually get
	hr = mBitmapFrame->SetPixelFormat( &formatGUID );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedLoad();
	
	setupPixelFormat( formatGUID );
	
	mData = shared_ptr<uint8_t>( new uint8_t[mHeight * mRowBytes], boost::checked_array_delete<uint8_t> );
}
ImageTargetFileWic::ImageTargetFileWic( DataTargetRef dataTarget, ImageSourceRef imageSource, ImageTarget::Options options, const string &extensionData )
	: ImageTarget(), mDataTarget( dataTarget )
{
	mCodecGUID = getExtensionMap()[extensionData];

	setSize( imageSource->getWidth(), imageSource->getHeight() );

	// determine the pixel format we'll request
	WICPixelFormatGUID formatGUID;
	if( imageSource->hasAlpha() ) {
		bool premultAlpha = imageSource->isPremultiplied();
		// WIC doesn't support gray+alpha, so we need to do RGBA regardless
		if( imageSource->getDataType() == ImageIo::UINT8 )
			formatGUID = premultAlpha ? GUID_WICPixelFormat32bppPBGRA : GUID_WICPixelFormat32bppBGRA;
		else if( imageSource->getDataType() == ImageIo::UINT16 )
			formatGUID = premultAlpha ? GUID_WICPixelFormat64bppPRGBA : GUID_WICPixelFormat64bppRGBA;
		else
			formatGUID = premultAlpha ? GUID_WICPixelFormat128bppPRGBAFloat : GUID_WICPixelFormat128bppRGBAFloat;
	}
	else {
		ImageIo::ColorModel cm = options.isColorModelDefault() ? imageSource->getColorModel() : options.getColorModel();
		if( cm == ImageIo::CM_GRAY ) {
			if( imageSource->getDataType() == ImageIo::UINT8 )
				formatGUID = GUID_WICPixelFormat8bppGray;
			else if( imageSource->getDataType() == ImageIo::UINT16 )
				formatGUID = GUID_WICPixelFormat16bppGray;
			else
				formatGUID = GUID_WICPixelFormat32bppGrayFloat;
		}
		else { // RGB
			if( imageSource->getDataType() == ImageIo::UINT8 )
				formatGUID = GUID_WICPixelFormat24bppBGR;
			else if( imageSource->getDataType() == ImageIo::UINT16 )
				formatGUID = GUID_WICPixelFormat48bppRGB;
			else
				formatGUID = GUID_WICPixelFormat128bppRGBFloat;
		}
	}
	
	::HRESULT hr = S_OK;

	msw::initializeCom();

 // Create WIC factory
    IWICImagingFactory *IWICFactoryP = NULL;
    hr = ::CoCreateInstance( CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&IWICFactoryP) );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedWrite( "Could not create WIC Factory." );
	shared_ptr<IWICImagingFactory> IWICFactory = msw::makeComShared( IWICFactoryP );

	IWICBitmapEncoder *encoderP = NULL;
	hr = IWICFactory->CreateEncoder( *mCodecGUID, 0, &encoderP );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedWrite( "Could not create WIC Encoder." );
	mEncoder = msw::makeComShared( encoderP );
	
	// create the stream		
	IWICStream *pIWICStream = NULL;
	hr = IWICFactory->CreateStream( &pIWICStream );
	if( ! SUCCEEDED(hr) )
		throw ImageIoExceptionFailedWrite( "Could not create WIC stream." );
	shared_ptr<IWICStream> stream = msw::makeComShared( pIWICStream );
	
	// initialize the stream based on properties of the cinder::DataSouce
	if( mDataTarget->providesFilePath() ) {
#if defined( CINDER_WINRT)
		std::string s = mDataTarget->getFilePath().string();
		std::wstring filePath =	std::wstring(s.begin(), s.end());                 
#else
		std::wstring filePath =	mDataTarget->getFilePath().wstring().c_str();
#endif
		hr = stream->InitializeFromFilename( filePath.c_str(), GENERIC_WRITE );
		if( ! SUCCEEDED(hr) )
			throw ImageIoExceptionFailedWrite( "Could not initialize WIC Stream from filename." );
	}
	else {
		shared_ptr<msw::ComOStream> comOStream = msw::makeComShared( new msw::ComOStream( mDataTarget->getStream() ) );
		hr = stream->InitializeFromIStream( comOStream.get() );
		if( ! SUCCEEDED(hr) )
			throw ImageIoExceptionFailedWrite( "Could not initialize WIC Stream from IStream." );
	}
	
	hr = mEncoder->Initialize( stream.get(), WICBitmapEncoderNoCache );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedWrite( "Could not initialize WIC Encoder." );

	// create the frame encoder
	IPropertyBag2 *pPropertybag = NULL;
	IWICBitmapFrameEncode *pBitmapFrame = NULL;
	hr = mEncoder->CreateNewFrame( &pBitmapFrame, &pPropertybag );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedWrite( "Could not ceate WIC Frame." );
	mBitmapFrame = msw::makeComShared( pBitmapFrame );

	// setup the propertyBag to express quality
	PROPBAG2 option = { 0 };
    option.pstrName = L"ImageQuality";
    VARIANT varValue;    
    VariantInit(&varValue);
    varValue.vt = VT_R4;
    varValue.fltVal = options.getQuality();      
    hr = pPropertybag->Write( 1, &option, &varValue );

	hr = mBitmapFrame->Initialize( pPropertybag );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedWrite( "Could not initialize WIC PROPBAG2." );
	
	hr = mBitmapFrame->SetSize( mWidth, mHeight );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedWrite( "Could not set WIC Frame size." );
	
	// ask for our ideal pixel format and then process the one we actually get
	hr = mBitmapFrame->SetPixelFormat( &formatGUID );
	if( ! SUCCEEDED( hr ) )
		throw ImageIoExceptionFailedWrite( "Could not set WIC Frame pixel format." );
	
	setupPixelFormat( formatGUID );
	
	mData = shared_ptr<uint8_t>( new uint8_t[mHeight * mRowBytes], std::default_delete<uint8_t[]>() );
}