-
Notifications
You must be signed in to change notification settings - Fork 806
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementation of Tiled Images + tests #1542
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1950,30 +1950,43 @@ void CGContextEOFillPath(CGContextRef context) { | |
|
||
#pragma region Drawing Operations - CGImage | ||
|
||
/** | ||
@Status Interoperable | ||
*/ | ||
void CGContextDrawImage(CGContextRef context, CGRect rect, CGImageRef image) { | ||
NOISY_RETURN_IF_NULL(context); | ||
NOISY_RETURN_IF_NULL(image); | ||
static HRESULT __CreateD2DBitmapFromCGImage(CGContextRef context, CGImageRef image, ID2D1Bitmap** bitmap) { | ||
RETURN_HR_IF_NULL(E_INVALIDARG, context); | ||
RETURN_HR_IF_NULL(E_INVALIDARG, image); | ||
RETURN_HR_IF_NULL(E_POINTER, bitmap); | ||
|
||
// Obtain the pixel format for the image | ||
WICPixelFormatGUID imagePixelFormat = _CGImageGetWICPixelFormat(image); | ||
ComPtr<IWICBitmap> bmap; | ||
RETURN_IF_FAILED(_CGImageGetWICImageSource(image, &bmap)); | ||
|
||
CFRetain(image); | ||
woc::unique_cf<CGImageRef> refImage; | ||
refImage.reset(image); | ||
ComPtr<ID2D1Bitmap> d2dBitmap; | ||
RETURN_IF_FAILED(context->DeviceContext()->CreateBitmapFromWicBitmap(bmap.Get(), nullptr, &d2dBitmap)); | ||
*bitmap = d2dBitmap.Detach(); | ||
return S_OK; | ||
} | ||
|
||
static CGImageRef __CGContextCreateRenderableImage(CGImageRef image) { | ||
RETURN_NULL_IF(!image); | ||
WICPixelFormatGUID imagePixelFormat = _CGImageGetWICPixelFormat(image); | ||
if (!_CGIsValidRenderTargetPixelFormat(imagePixelFormat)) { | ||
// convert it to a valid pixelformat | ||
refImage.reset(_CGImageCreateCopyWithPixelFormat(image, GUID_WICPixelFormat32bppPBGRA)); | ||
return _CGImageCreateCopyWithPixelFormat(image, GUID_WICPixelFormat32bppPBGRA); | ||
} | ||
|
||
ComPtr<IWICBitmap> bmap; | ||
FAIL_FAST_IF_FAILED(_CGImageGetWICImageSource(refImage.get(), &bmap)); | ||
CGImageRetain(image); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: these can be one line #Resolved |
||
return image; | ||
} | ||
|
||
/** | ||
@Status Interoperable | ||
*/ | ||
void CGContextDrawImage(CGContextRef context, CGRect rect, CGImageRef image) { | ||
NOISY_RETURN_IF_NULL(context); | ||
NOISY_RETURN_IF_NULL(image); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: should this be noisy or a simple no-op? #ByDesign There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
||
woc::unique_cf<CGImageRef> refImage{ __CGContextCreateRenderableImage(image) }; | ||
|
||
ComPtr<ID2D1Bitmap> d2dBitmap; | ||
FAIL_FAST_IF_FAILED(context->DeviceContext()->CreateBitmapFromWicBitmap(bmap.Get(), nullptr, &d2dBitmap)); | ||
FAIL_FAST_IF_FAILED(__CreateD2DBitmapFromCGImage(context, refImage.get(), &d2dBitmap)); | ||
|
||
// Flip the image to account for change in coordinate system origin. | ||
CGAffineTransform flipImage = CGAffineTransformMakeTranslation(rect.origin.x, rect.origin.y + (rect.size.height / 2.0)); | ||
|
@@ -2022,13 +2035,58 @@ void _CGContextDrawImageRect(CGContextRef context, CGImageRef image, CGRect src, | |
} | ||
|
||
/** | ||
@Status Stub | ||
@Status Interoperable | ||
*/ | ||
void CGContextDrawTiledImage(CGContextRef context, CGRect rect, CGImageRef image) { | ||
// TODO #1417: This can be combined with brushes (brush + tiled fill); | ||
NOISY_RETURN_IF_NULL(context); | ||
UNIMPLEMENTED(); | ||
NOISY_RETURN_IF_NULL(image); | ||
|
||
woc::unique_cf<CGImageRef> refImage{ __CGContextCreateRenderableImage(image) }; | ||
|
||
ComPtr<ID2D1Bitmap> d2dBitmap; | ||
FAIL_FAST_IF_FAILED(__CreateD2DBitmapFromCGImage(context, refImage.get(), &d2dBitmap)); | ||
|
||
ComPtr<ID2D1BitmapBrush> bitmapBrush; | ||
ComPtr<ID2D1DeviceContext> deviceContext = context->DeviceContext(); | ||
FAIL_FAST_IF_FAILED(deviceContext->CreateBitmapBrush(d2dBitmap.Get(), &bitmapBrush)); | ||
|
||
// set the bitmap properties for the brush to be repeated | ||
bitmapBrush->SetExtendModeX(D2D1_EXTEND_MODE_WRAP); | ||
bitmapBrush->SetExtendModeY(D2D1_EXTEND_MODE_WRAP); | ||
|
||
// |1 0 0| is the transformation matrix for flipping a rect about its Y midpoint m. (m = (y + h/2)) | ||
// |0 -1 0| | ||
// |0 2m 1| | ||
// | ||
// Combined with [scale sx * sy] * [translate X, Y], that becomes: | ||
// |sx 0 0| | ||
// | 0 -sy 0| | ||
// | x -y+2m 0| | ||
// Or, the transformation matrix for drawing a flipped rect at a scale and offset. | ||
D2D1_SIZE_U bitmapSize = d2dBitmap->GetPixelSize(); | ||
CGFloat sx = rect.size.width / bitmapSize.width; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. check that width, height != 0 #Resolved |
||
CGFloat sy = rect.size.height / bitmapSize.height; | ||
CGFloat m = rect.origin.y + (rect.size.height / 2.f); | ||
|
||
CGAffineTransform transform{ sx, 0, 0, -sy, rect.origin.x, (2 * m) - rect.origin.y }; | ||
transform = CGAffineTransformConcat(transform, CGContextGetUserSpaceToDeviceSpaceTransform(context)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I saw the same block of code (with identical comments) for transforms in @DHowett-MSFT's PR. can we make a utility function out of this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Definitely., it's being used by all brushes that have image as source. #ByDesign |
||
|
||
// set the transform for the brush and alpha | ||
bitmapBrush->SetTransform(__CGAffineTransformToD2D_F(transform)); | ||
bitmapBrush->SetOpacity(context->CurrentGState().alpha); | ||
|
||
// set the interpolationMode | ||
bitmapBrush->SetInterpolationMode(D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR); | ||
|
||
// Area to fill | ||
D2D1_SIZE_F targetSize = deviceContext->GetSize(); | ||
D2D1_RECT_F region = D2D1::RectF(0, 0, targetSize.width, targetSize.height); | ||
|
||
deviceContext->BeginDraw(); | ||
deviceContext->FillRectangle(®ion, bitmapBrush.Get()); | ||
FAIL_FAST_IF_FAILED(deviceContext->EndDraw()); | ||
} | ||
|
||
#pragma endregion | ||
|
||
#pragma region Drawing Operations - Gradient + Shading | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This requires a conversion into a valid render target format first.
There is some work around this in #1528. #ByDesign
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see. I don't think this needs to be in two functions :P They'll always be found together. #ByDesign
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see it being used separately in CGImage usage in one of your CR, i'll leave it be for now.
In reply to: 92528114 [](ancestors = 92528114)