Skip to content

Commit

Permalink
Implementation of CGBitmapContext.
Browse files Browse the repository at this point in the history
Added custom iwic bitmap to support copying, and backed data buffer.
Added colour conversion format check for pixel formats.
Added tests to draw, render and validate changes.
CGImage changed to use OnLoad caching.
  • Loading branch information
msft-Jeyaram committed Nov 16, 2016
1 parent ba6c5ca commit 09b56ed
Show file tree
Hide file tree
Showing 8 changed files with 302 additions and 166 deletions.
74 changes: 0 additions & 74 deletions Frameworks/CoreGraphics/CGBitmapContext.mm

This file was deleted.

123 changes: 95 additions & 28 deletions Frameworks/CoreGraphics/CGContext.mm
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//******************************************************************************
//
// Copyright (c) 2016 Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
Expand All @@ -25,9 +25,12 @@
#import <CoreGraphics/CGLayer.h>
#import <CoreGraphics/CGAffineTransform.h>
#import <CoreGraphics/CGGradient.h>
#import <LoggingNative.h>
#import <CoreGraphics/D2DWrapper.h>
#import "CGColorSpaceInternal.h"
#import "CGContextInternal.h"
#import "CGPathInternal.h"
#import "CGIWICBitmap.h"

#import <CFCppBase.h>

Expand All @@ -37,8 +40,6 @@
#import <d2d1effects_2.h>
#import <wrl/client.h>
#include <COMIncludes_end.h>
#import <LoggingNative.h>
#import <CoreGraphics/D2DWrapper.h>

#import <list>
#import <vector>
Expand Down Expand Up @@ -1937,78 +1938,144 @@ inline void SetImage(CGImageRef image) {

/**
@Status Caveat
@Notes Limited bitmap formats available. Decode, shouldInterpolate, intent parameters
and some byte orders ignored.
*/
We only support formats that are 32 bits per pixel, colorspace and bitmapinfo that are ARGB.
*/
CGContextRef CGBitmapContextCreate(void* data,
size_t width,
size_t height,
size_t bitsPerComponent,
size_t bytesPerRow,
CGColorSpaceRef colorSpace,
CGBitmapInfo bitmapInfo) {
UNIMPLEMENTED();
return nullptr;
return CGBitmapContextCreateWithData(data, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo, nullptr, nullptr);
}

/**
@Status Caveat
@Notes releaseCallback and releaseInfo is ignored.
We only support formats that are 32 bits per pixel, colorspace and bitmapinfo that are ARGB.
*/
CGContextRef CGBitmapContextCreateWithData(void* data,
size_t width,
size_t height,
size_t bitsPerComponent,
size_t bytesPerRow,
CGColorSpaceRef space,
uint32_t bitmapInfo,
CGBitmapContextReleaseDataCallback releaseCallback,
void* releaseInfo) {
RETURN_NULL_IF(!width);
RETURN_NULL_IF(!height);
RETURN_NULL_IF(!space);

// bitsperpixel = ((bytesPerRow/width) * 8bits/byte)
size_t bitsPerPixel = ((bytesPerRow / width) << 3);
REFGUID pixelFormat = _CGImageGetWICPixelFormatFromImageProperties(bitsPerComponent, bitsPerPixel, space, bitmapInfo);

if (!_CGIsValidRenderTargetPixelFormat(pixelFormat)) {
UNIMPLEMENTED_WITH_MSG("CGBitmapContext does not currently support conversion and can only render into 32bpp PRGBA buffers.");
return nullptr;
}

// if data is null, enough memory is allocated via CGIWICBitmap
ComPtr<IWICBitmap> customBitmap = Make<CGIWICBitmap>(data, pixelFormat, height, width);
RETURN_NULL_IF(!customBitmap);

woc::unique_cf<CGImageRef> image(_CGImageCreateWithWICBitmap(customBitmap.Get()));
RETURN_NULL_IF(!image);

ComPtr<ID2D1Factory> factory;
RETURN_NULL_IF_FAILED(_CGGetD2DFactory(&factory));

ComPtr<ID2D1RenderTarget> renderTarget;
RETURN_NULL_IF_FAILED(factory->CreateWicBitmapRenderTarget(customBitmap.Get(), D2D1::RenderTargetProperties(), &renderTarget));
return _CGBitmapContextCreateWithRenderTarget(renderTarget.Get(), image.get());
}

/**
@Status Interoperable
*/
CGBitmapInfo CGBitmapContextGetBitmapInfo(CGContextRef context) {
NOISY_RETURN_IF_NULL(context, kCGBitmapByteOrderDefault);
return CGImageGetBitmapInfo(CGBitmapContextGetImage(context));
}

/**
@Status Interoperable
*/
CGImageAlphaInfo CGBitmapContextGetAlphaInfo(CGContextRef context) {
NOISY_RETURN_IF_NULL(context, kCGImageAlphaNone);
return CGImageGetAlphaInfo(CGBitmapContextGetImage(context));
}

/**
@Status Interoperable
*/
size_t CGBitmapContextGetBitsPerComponent(CGContextRef context) {
NOISY_RETURN_IF_NULL(context, 0);
return CGImageGetBitsPerComponent(CGBitmapContextGetImage(context));
}

/**
@Status Interoperable
*/
size_t CGBitmapContextGetBitsPerPixel(CGContextRef context) {
NOISY_RETURN_IF_NULL(context, 0);
return CGImageGetBitsPerPixel(CGBitmapContextGetImage(context));
}

/**
@Status Interoperable
*/
CGColorSpaceRef CGBitmapContextGetColorSpace(CGContextRef context) {
NOISY_RETURN_IF_NULL(context, StubReturn());
UNIMPLEMENTED();
return nullptr;
NOISY_RETURN_IF_NULL(context, nullptr);
return CGImageGetColorSpace(CGBitmapContextGetImage(context));
}

/**
@Status Interoperable
*/
size_t CGBitmapContextGetWidth(CGContextRef context) {
NOISY_RETURN_IF_NULL(context, StubReturn());
UNIMPLEMENTED();
return StubReturn();
NOISY_RETURN_IF_NULL(context, 0);
return CGImageGetWidth(CGBitmapContextGetImage(context));
}

/**
@Status Interoperable
*/
size_t CGBitmapContextGetHeight(CGContextRef context) {
NOISY_RETURN_IF_NULL(context, StubReturn());
UNIMPLEMENTED();
return StubReturn();
NOISY_RETURN_IF_NULL(context, 0);
return CGImageGetHeight(CGBitmapContextGetImage(context));
}

/**
@Status Interoperable
*/
size_t CGBitmapContextGetBytesPerRow(CGContextRef context) {
NOISY_RETURN_IF_NULL(context, StubReturn());
UNIMPLEMENTED();
return StubReturn();
NOISY_RETURN_IF_NULL(context, 0);
return CGImageGetBytesPerRow(CGBitmapContextGetImage(context));
}

/**
@Status Interoperable
*/
void* CGBitmapContextGetData(CGContextRef context) {
NOISY_RETURN_IF_NULL(context, StubReturn());
UNIMPLEMENTED();
return StubReturn();
NOISY_RETURN_IF_NULL(context, nullptr);
return _CGImageGetRawBytes(CGBitmapContextGetImage(context));
}

/**
@Status Caveat
@Notes Has no copy-on-write semantics; bitmap returned is the source bitmap representing
@Notes Has no copy-on-write semantics; bitmap returned is the copy of the source bitmap representing
the CGContext
*/
CGImageRef CGBitmapContextCreateImage(CGContextRef context) {
NOISY_RETURN_IF_NULL(context, StubReturn());
UNIMPLEMENTED();
return StubReturn();
NOISY_RETURN_IF_NULL(context, nullptr);
return CGImageCreateCopy(CGBitmapContextGetImage(context));
}

CGImageRef CGBitmapContextGetImage(CGContextRef context) {
NOISY_RETURN_IF_NULL(context, StubReturn());
NOISY_RETURN_IF_NULL(context, nullptr);
if (CFGetTypeID(context) != __CGBitmapContext::GetTypeID()) {
TraceError(TAG, L"Image requested from non-bitmap CGContext.");
return nullptr;
Expand Down
20 changes: 17 additions & 3 deletions Frameworks/CoreGraphics/CGImage.mm
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ CGImageRef CGImageCreateCopy(CGImageRef ref) {

ComPtr<IWICBitmap> image;

RETURN_NULL_IF_FAILED(imageFactory->CreateBitmapFromSource(ref->ImageSource().Get(), WICBitmapCacheOnDemand, &image));
RETURN_NULL_IF_FAILED(imageFactory->CreateBitmapFromSource(ref->ImageSource().Get(), WICBitmapCacheOnLoad, &image));

CGImageRef imageRef = __CGImage::CreateInstance();
imageRef->SetImageSource(image)
Expand Down Expand Up @@ -225,7 +225,7 @@ CGColorSpaceRef CGImageGetColorSpace(CGImageRef img) {
@Status Interoperable
*/
CGBitmapInfo CGImageGetBitmapInfo(CGImageRef img) {
RETURN_RESULT_IF_NULL(img, 0);
RETURN_RESULT_IF_NULL(img, kCGBitmapByteOrderDefault);
return img->BitmapInfo();
}

Expand Down Expand Up @@ -375,6 +375,20 @@ CGImageRef CGImageCreateWithMaskingColors(CGImageRef image, const CGFloat* compo

#pragma region WIC_HELPERS

bool _CGIsValidRenderTargetPixelFormat(WICPixelFormatGUID pixelFormat) {
auto iterator = s_ValidRenderTargetPixelFormat.find(pixelFormat);
return iterator != s_ValidRenderTargetPixelFormat.end();
}

const __CGImagePixelProperties* _CGGetPixelFormatProperties(WICPixelFormatGUID pixelFormat) {
RETURN_NULL_IF(pixelFormat == GUID_WICPixelFormatUndefined);

auto iterator = s_PixelFormats.find(pixelFormat);
RETURN_NULL_IF(iterator == s_PixelFormats.end());

return &iterator->second;
}

IWICBitmap* _CGImageGetImageSource(CGImageRef image) {
RETURN_NULL_IF(!image);
return image->ImageSource().Get();
Expand Down Expand Up @@ -424,7 +438,7 @@ CGImageRef _CGImageCreateCopyWithPixelFormat(CGImageRef image, WICPixelFormatGUI
image->ImageSource().Get(), pixelFormat, WICBitmapDitherTypeNone, nullptr, 0.f, WICBitmapPaletteTypeMedianCut));

ComPtr<IWICBitmap> convertedImage;
RETURN_NULL_IF_FAILED(imageFactory->CreateBitmapFromSource(converter.Get(), WICBitmapCacheOnDemand, &convertedImage));
RETURN_NULL_IF_FAILED(imageFactory->CreateBitmapFromSource(converter.Get(), WICBitmapCacheOnLoad, &convertedImage));

CGImageRef imageRef = __CGImage::CreateInstance();
imageRef->SetImageSource(convertedImage);
Expand Down
Loading

0 comments on commit 09b56ed

Please sign in to comment.