Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit d25a309
Author: Dustin L. Howett <duhowett@microsoft.com>
Date:   Tue Dec 13 17:00:20 2016 -0800

    CR Feedback (Test Harness)

commit bdc4c1f
Author: Dustin L. Howett <duhowett@microsoft.com>
Date:   Tue Dec 13 17:00:05 2016 -0800

    CR Feedback (CGIWICBitmap)

commit bc63c8e
Author: Dustin L. Howett <duhowett@microsoft.com>
Date:   Tue Dec 13 16:34:40 2016 -0800

    Fix the unpremultiplier to match Windows'.

commit 2647ae3
Author: Dustin L. Howett <duhowett@microsoft.com>
Date:   Tue Dec 13 15:38:04 2016 -0800

    Clean up some EXPECT/ASSERT/_MSG in ImageIO Tests.

commit b769558
Author: Dustin L. Howett <duhowett@microsoft.com>
Date:   Tue Dec 13 15:29:35 2016 -0800

    Fix some flawed CoreGraphics tests (wrong expected data).

commit 830d03c
Author: Dustin L. Howett <duhowett@microsoft.com>
Date:   Tue Dec 13 15:09:40 2016 -0800

    Fix CoreGraphics.Drawing's image loader & add a premul alpha test.

commit f8cce71
Author: Dustin L. Howett <duhowett@microsoft.com>
Date:   Tue Dec 13 15:07:22 2016 -0800

    Use CGImage's WIC ingestor in CGImageSource. FIX TESTS.

commit a1f32dd
Author: Dustin L. Howett <duhowett@microsoft.com>
Date:   Tue Dec 13 12:50:13 2016 -0800

    Update CGImage's Big List of Formats.

commit 32eb393
Author: Dustin L. Howett <duhowett@microsoft.com>
Date:   Mon Dec 12 12:08:44 2016 -0800

    Add support for copying subregions from CGIWICBitmap.

    Refs microsoft#1379.

commit e0a1531
Author: Dustin L. Howett <duhowett@microsoft.com>
Date:   Thu Dec 8 18:11:25 2016 -0800

    Streamline ImageIO's image generator to use CGImage's WIC source+fmt.

commit 7f203a1
Author: Dustin L. Howett <duhowett@microsoft.com>
Date:   Thu Dec 8 18:10:20 2016 -0800

    When !buffer, convert CGBitmapContext's image on output.
  • Loading branch information
DHowett committed Dec 14, 2016
1 parent 9c21411 commit b370835
Show file tree
Hide file tree
Showing 14 changed files with 766 additions and 644 deletions.
35 changes: 27 additions & 8 deletions Frameworks/CoreGraphics/CGContext.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2269,12 +2269,19 @@ void CGContextDrawGlyphRun(CGContextRef context, const DWRITE_GLYPH_RUN* glyphRu
struct __CGBitmapContext : CoreFoundation::CppBase<__CGBitmapContext, __CGContext> {
woc::unique_cf<CGImageRef> _image;

__CGBitmapContext(ID2D1RenderTarget* renderTarget) : Parent(renderTarget) {
__CGBitmapContext(ID2D1RenderTarget* renderTarget, REFWICPixelFormatGUID outputPixelFormat) : Parent(renderTarget), _outputPixelFormat(outputPixelFormat) {
}

inline void SetImage(CGImageRef image) {
_image.reset(CGImageRetain(image));
}

inline REFWICPixelFormatGUID GetOutputPixelFormat() const {
return _outputPixelFormat;
}

private:
WICPixelFormatGUID _outputPixelFormat;
};

/**
Expand Down Expand Up @@ -2311,11 +2318,15 @@ CGContextRef CGBitmapContextCreateWithData(void* data,

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

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

// if data is null, enough memory is allocated via CGIWICBitmap
Expand All @@ -2330,7 +2341,8 @@ CGContextRef CGBitmapContextCreateWithData(void* data,

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

/**
Expand Down Expand Up @@ -2412,7 +2424,14 @@ size_t CGBitmapContextGetBytesPerRow(CGContextRef context) {
*/
CGImageRef CGBitmapContextCreateImage(CGContextRef context) {
NOISY_RETURN_IF_NULL(context, nullptr);
return CGImageCreateCopy(CGBitmapContextGetImage(context));
if (CFGetTypeID(context) != __CGBitmapContext::GetTypeID()) {
TraceError(TAG, L"Image requested from non-bitmap CGContext.");
return nullptr;
}

// This copy is a no-op if the output format requested matches the backing image format.
__CGBitmapContext* bitmapContext = (__CGBitmapContext*)context;
return _CGImageCreateCopyWithPixelFormat(bitmapContext->_image.get(), bitmapContext->GetOutputPixelFormat());
}

CGImageRef CGBitmapContextGetImage(CGContextRef context) {
Expand All @@ -2424,9 +2443,9 @@ CGImageRef CGBitmapContextGetImage(CGContextRef context) {
return ((__CGBitmapContext*)context)->_image.get();
}

CGContextRef _CGBitmapContextCreateWithRenderTarget(ID2D1RenderTarget* renderTarget, CGImageRef img) {
CGContextRef _CGBitmapContextCreateWithRenderTarget(ID2D1RenderTarget* renderTarget, CGImageRef img, WICPixelFormatGUID outputPixelFormat) {
RETURN_NULL_IF(!renderTarget);
__CGBitmapContext* context = __CGBitmapContext::CreateInstance(kCFAllocatorDefault, renderTarget);
__CGBitmapContext* context = __CGBitmapContext::CreateInstance(kCFAllocatorDefault, renderTarget, outputPixelFormat);
__CGContextPrepareDefaults(context);
context->SetImage(img);
return context;
Expand Down
36 changes: 14 additions & 22 deletions Frameworks/ImageIO/CGImageDestination.mm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#import <ImageIO/CGImageDestination.h>
#import "CGImageDestinationInternal.h"
#import <StubReturn.h>
#import <CGImageInternal.h>
#include <windows.h>
#include <string>

Expand Down Expand Up @@ -979,6 +980,14 @@ void CGImageDestinationAddImage(CGImageDestinationRef idst, CGImageRef image, CF
}
}

// Turn image into a WIC Bitmap
ComPtr<IWICBitmap> inputImage;
status = _CGImageGetWICImageSource(image, &inputImage);
if (!SUCCEEDED(status)) {
NSTraceInfo(TAG, @"_CGImageGetWICImageSource failed with status=%x\n", status);
return;
}

IWICMetadataQueryWriter* propertyWriter = imageFrameMetadataWriter.Get();

// Set the pixel format based on file format and write necessary metadata
Expand All @@ -998,7 +1007,11 @@ void CGImageDestinationAddImage(CGImageDestinationRef idst, CGImageRef image, CF
writeGIFProperties(propertyWriter, properties, imageWidth, imageHeight);
break;
case typePNG:
formatGUID = GUID_WICPixelFormat32bppRGBA;
status = inputImage->GetPixelFormat(&formatGUID);
if (!SUCCEEDED(status)) {
NSTraceInfo(TAG, @"Get Image Source Pixel Format failed with status=%x\n", status);
return;
}
writePNGProperties(propertyWriter, properties, imageWidth, imageHeight);
break;
case typeBMP:
Expand All @@ -1015,27 +1028,6 @@ void CGImageDestinationAddImage(CGImageDestinationRef idst, CGImageRef image, CF
return;
}

CGDataProviderRef provider = CGImageGetDataProvider(image);
NSData* imageByteData = (id)CGDataProviderCopyData(provider);

// Turn image into a WIC Bitmap
ComPtr<IWICBitmap> inputImage;

// All our input coming in from CGImagesource is in 32bppRGBA
ComPtr<IWICImagingFactory> imageFactory = imageDestination.idFactory;
status = imageFactory->CreateBitmapFromMemory(imageWidth,
imageHeight,
GUID_WICPixelFormat32bppRGBA,
imageWidth * 4,
imageHeight * imageWidth * 4,
(unsigned char*)[imageByteData bytes],
&inputImage);
[imageByteData release];
if (!SUCCEEDED(status)) {
NSTraceInfo(TAG, @"CreateBitmapFromMemory failed with status=%x\n", status);
return;
}

ComPtr<IWICBitmapSource> inputBitmapSource;
status = WICConvertBitmapSource(formatGUID, inputImage.Get(), &inputBitmapSource);
if (!SUCCEEDED(status)) {
Expand Down
79 changes: 8 additions & 71 deletions Frameworks/ImageIO/CGImageSource.mm
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <wrl/client.h>
#include "COMIncludes_End.h"

#import <CGImageInternal.h>

using namespace Microsoft::WRL;

static const wchar_t* TAG = L"CGImageSource";
Expand Down Expand Up @@ -1684,48 +1686,10 @@ CGImageRef CGImageSourceCreateImageAtIndex(CGImageSourceRef isrc, size_t index,
ComPtr<IWICBitmapFrameDecode> imageFrame;
RETURN_NULL_IF_FAILED(imageDecoder->GetFrame(index, &imageFrame));

unsigned int frameWidth = 0;
unsigned int frameHeight = 0;
RETURN_NULL_IF_FAILED(imageFrame->GetSize(&frameWidth, &frameHeight));

ComPtr<IWICFormatConverter> imageFormatConverter;
RETURN_NULL_IF_FAILED(imageFactory->CreateFormatConverter(&imageFormatConverter));

if (options && CFDictionaryContainsKey(options, kCGImageSourceShouldAllowFloat)) {
UNIMPLEMENTED_WITH_MSG("kCGImageSourceShouldAllowFloat is not supported in current implementation.");
}
ComPtr<IWICBitmap> imageBitmap;
RETURN_NULL_IF_FAILED(imageFactory->CreateBitmapFromSource(imageFrame.Get(), WICBitmapCacheOnDemand, &imageBitmap));

RETURN_NULL_IF_FAILED(imageFormatConverter->Initialize(
imageFrame.Get(), GUID_WICPixelFormat32bppRGBA, WICBitmapDitherTypeNone, nullptr, 0.f, WICBitmapPaletteTypeCustom));

const unsigned int frameSize = frameWidth * frameHeight * 4;
unsigned char* frameByteArray = static_cast<unsigned char*>(IwMalloc(frameSize));
if (!frameByteArray) {
NSTraceInfo(TAG, @"CGImageSourceCreateImageAtIndex cannot allocate memory");
return nullptr;
}

auto cleanup = wil::ScopeExit([&]() { IwFree(frameByteArray); });
RETURN_NULL_IF_FAILED(imageFormatConverter->CopyPixels(0, frameWidth * 4, frameSize, frameByteArray));
cleanup.Dismiss();

NSData* frameData = [NSData dataWithBytesNoCopy:frameByteArray length:frameSize freeWhenDone:YES];
CGDataProviderRef frameDataProvider = CGDataProviderCreateWithCFData((CFDataRef)frameData);
CGColorSpaceRef colorspaceRgb = CGColorSpaceCreateDeviceRGB();
CGImageRef imageRef = CGImageCreate(frameWidth,
frameHeight,
8,
32,
frameWidth * 4,
colorspaceRgb,
kCGImageAlphaLast,
frameDataProvider,
nullptr,
true,
kCGRenderingIntentDefault);
CGDataProviderRelease(frameDataProvider);
CGColorSpaceRelease(colorspaceRgb);
return imageRef;
return _CGImageCreateWithWICBitmap(imageBitmap.Get());
}

/**
Expand Down Expand Up @@ -1825,37 +1789,10 @@ CGImageRef CGImageSourceCreateThumbnailAtIndex(CGImageSourceRef isrc, size_t ind
UNIMPLEMENTED_WITH_MSG("kCGImageSourceShouldAllowFloat is not supported in current implementation.");
}

RETURN_NULL_IF_FAILED(imageFormatConverter->Initialize(
imageScaler.Get(), GUID_WICPixelFormat32bppRGBA, WICBitmapDitherTypeNone, nullptr, 0.f, WICBitmapPaletteTypeCustom));

const unsigned int thumbnailSize = thumbnailWidth * thumbnailHeight * 4;
unsigned char* thumbnailByteArray = static_cast<unsigned char*>(IwMalloc(thumbnailSize));
if (!thumbnailByteArray) {
NSTraceInfo(TAG, @"CGImageSourceCreateThumbnailAtIndex cannot allocate memory");
return nullptr;
}
ComPtr<IWICBitmap> imageBitmap;
RETURN_NULL_IF_FAILED(imageFactory->CreateBitmapFromSource(imageScaler.Get(), WICBitmapCacheOnDemand, &imageBitmap));

auto cleanup = wil::ScopeExit([&]() { IwFree(thumbnailByteArray); });
RETURN_NULL_IF_FAILED(imageFormatConverter->CopyPixels(0, thumbnailWidth * 4, thumbnailSize, thumbnailByteArray));
cleanup.Dismiss();

NSData* thumbnailData = [NSData dataWithBytesNoCopy:thumbnailByteArray length:thumbnailSize freeWhenDone:YES];
CGDataProviderRef thumbnailDataProvider = CGDataProviderCreateWithCFData((CFDataRef)thumbnailData);
CGColorSpaceRef colorspaceRgb = CGColorSpaceCreateDeviceRGB();
CGImageRef imageRef = CGImageCreate(thumbnailWidth,
thumbnailHeight,
8,
32,
thumbnailWidth * 4,
colorspaceRgb,
kCGImageAlphaLast,
thumbnailDataProvider,
nullptr,
true,
kCGRenderingIntentDefault);
CGDataProviderRelease(thumbnailDataProvider);
CGColorSpaceRelease(colorspaceRgb);
return imageRef;
return _CGImageCreateWithWICBitmap(imageBitmap.Get());
}

/**
Expand Down
2 changes: 1 addition & 1 deletion Frameworks/QuartzCore/CALayer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ CGContextRef CreateLayerContentsBitmapContext32(int width, int height, float sca
RETURN_NULL_IF_FAILED(factory->CreateWicBitmapRenderTarget(customWICBtmap.Get(), D2D1::RenderTargetProperties(), &renderTarget));
renderTarget->SetDpi(c_windowsDPI * scale, c_windowsDPI * scale);

return _CGBitmapContextCreateWithRenderTarget(renderTarget.Get(), image.get());
return _CGBitmapContextCreateWithRenderTarget(renderTarget.Get(), image.get(), GUID_WICPixelFormat32bppPBGRA);
}

return nullptr;
Expand Down
3 changes: 2 additions & 1 deletion Frameworks/include/CGContextInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <COMIncludes.h>
#import <DWrite.h>
#import <D2d1.h>
#import <wincodec.h>
#include <COMIncludes_End.h>

#import "CoreGraphicsInternal.h"
Expand All @@ -40,6 +41,6 @@ COREGRAPHICS_EXPORT bool CGContextIsPointInPath(CGContextRef c, bool eoFill, flo
COREGRAPHICS_EXPORT void CGContextDrawGlyphRun(CGContextRef ctx, const DWRITE_GLYPH_RUN* glyphRun);

// Bitmap Context Internal
COREGRAPHICS_EXPORT CGContextRef _CGBitmapContextCreateWithRenderTarget(ID2D1RenderTarget* renderTarget, CGImageRef img = nullptr);
COREGRAPHICS_EXPORT CGContextRef _CGBitmapContextCreateWithRenderTarget(ID2D1RenderTarget* renderTarget, CGImageRef img, WICPixelFormatGUID outputPixelFormat);
COREGRAPHICS_EXPORT CGContextRef _CGBitmapContextCreateWithFormat(int width, int height, __CGSurfaceFormat fmt);
COREGRAPHICS_EXPORT CGImageRef CGBitmapContextGetImage(CGContextRef ctx);
34 changes: 28 additions & 6 deletions Frameworks/include/CGIWICBitmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ class CGIWICBitmap : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::Runtime
}

// IWICBitmap interface
// TODO #1124: Today we do not support locking a region of the WIC bitmap for rendering. We only support locking the complete bitmap.
// TODO #1379: Today we do not support locking of a region smaller than the entire bitmap.
// This will suffice CoreText requirement but needs to be revisted for CoreGraphics usage in future.

HRESULT STDMETHODCALLTYPE Lock(_In_ const WICRect* region, _In_ DWORD flags, _COM_Outptr_ IWICBitmapLock** outLock) {
Expand Down Expand Up @@ -187,17 +187,39 @@ class CGIWICBitmap : public Microsoft::WRL::RuntimeClass<Microsoft::WRL::Runtime
_Out_writes_all_(cbBufferSize) BYTE* buffer) {
RETURN_HR_IF_NULL(E_POINTER, buffer);

const WICRect fullRect = { 0, 0, m_width, m_height };
Microsoft::WRL::ComPtr<IWICBitmapLock> lock;
RETURN_IF_FAILED(Lock(copyRect, 0, &lock));
// TODO #1379: Support sub-regional locking.
RETURN_IF_FAILED(Lock(&fullRect, 0, &lock));

if (!copyRect) {
copyRect = &fullRect;
}

RETURN_HR_IF(E_INVALIDARG, copyRect->Width == 0 || copyRect->Height == 0 || copyRect->X < 0 || copyRect->Y < 0);

UINT sourceDataStride;
UINT sourceDataSize;
BYTE* sourceData;
RETURN_IF_FAILED(lock->GetStride(&sourceDataStride));
RETURN_IF_FAILED(lock->GetDataPointer(&sourceDataSize, &sourceData));

RETURN_HR_IF(E_INVALIDARG, sourceDataSize > bufferSize);

// TODO #1379 - should support regional copying.
RETURN_HR_IF(E_UNEXPECTED, memcpy_s(buffer, bufferSize, sourceData, sourceDataSize) != 0);
if (copyRect->X == 0 && copyRect->Y == 0 && copyRect->Width == m_width && copyRect->Height == m_height) {
RETURN_HR_IF(E_INVALIDARG, sourceDataSize > bufferSize);
RETURN_HR_IF(E_UNEXPECTED, memcpy_s(buffer, bufferSize, sourceData, sourceDataSize) != 0);
} else {
// Once we support sub-regional locking we can fix this stride copier.
RETURN_HR_IF(E_NOTIMPL, sourceDataStride < fullRect.Width);
size_t bytesPerPixel = sourceDataStride / fullRect.Width;
ptrdiff_t xOffBytes = copyRect->X * bytesPerPixel;
for (size_t i = 0, j = copyRect->Y; i < copyRect->Height; ++i, ++j) {
RETURN_HR_IF(E_UNEXPECTED,
memcpy_s(buffer + (stride * i),
bufferSize - (stride * i),
sourceData + xOffBytes + (sourceDataStride * j),
stride));
}
}
return S_OK;
}

Expand Down
Loading

0 comments on commit b370835

Please sign in to comment.