Skip to content

Commit 2fb7574

Browse files
author
murrell
committed
add alpha masks support to quartz()
git-svn-id: https://svn.r-project.org/R/trunk@87394 00db46b3-68df-0310-9c12-caf00c1e9a41
1 parent c0427dc commit 2fb7574

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

doc/NEWS.Rd

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,12 @@
120120

121121
\item The \code{sunspot.month} data have been updated to Oct 2024;
122122
because of recalibration also historical numbers are changed, and we
123-
keep the previous data as \code{sunspot.m2014} for reproducibility.
123+
keep the previous data as \code{sunspot.m2014} for
124+
reproducibility.
125+
126+
\item The `quartz()` device now supports alpha masks.
127+
Thanks to \I{George Stagg}, \I{Heather Turner}, and
128+
\I{Tomek Gieorgijewski}.
124129

125130
\item The \code{print()} method for date-time objects (\code{POSIX.t})
126131
gets an optional \code{digits} argument for \emph{fractional}

src/library/grDevices/src/devQuartz.c

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,12 @@ static int QuartzCreateMask(SEXP mask,
10321032

10331033
cs = CGColorSpaceCreateDeviceGray();
10341034

1035+
/* For alpha masks, create a bitmap with only an alpha channel */
1036+
uint32_t bitmapInfo = kCGImageAlphaNone;
1037+
if (R_GE_maskType(mask) == R_GE_alphaMask) {
1038+
bitmapInfo = kCGImageAlphaOnly;
1039+
}
1040+
10351041
/* Create bitmap grahics context
10361042
* drawing is redirected to this context */
10371043
quartz_bitmap = CGBitmapContextCreate(NULL,
@@ -1040,7 +1046,7 @@ static int QuartzCreateMask(SEXP mask,
10401046
8,
10411047
0,
10421048
cs,
1043-
kCGImageAlphaNone);
1049+
bitmapInfo);
10441050

10451051
quartz_mask->context = quartz_bitmap;
10461052
xd->masks[index] = quartz_mask;
@@ -1055,6 +1061,31 @@ static int QuartzCreateMask(SEXP mask,
10551061
eval(R_fcall, R_GlobalEnv);
10561062
UNPROTECT(1);
10571063

1064+
/* When working with an alpha mask, convert into a grayscale bitmap */
1065+
if (R_GE_maskType(mask) == R_GE_alphaMask) {
1066+
CGContextRef alpha_bitmap = quartz_bitmap;
1067+
1068+
/* Create a new grayscale bitmap with no alpha channel */
1069+
int stride = CGBitmapContextGetBytesPerRow(alpha_bitmap);
1070+
quartz_bitmap = CGBitmapContextCreate(NULL,
1071+
(size_t) devWidth,
1072+
(size_t) devHeight,
1073+
8,
1074+
stride,
1075+
cs,
1076+
kCGImageAlphaNone);
1077+
quartz_mask->context = quartz_bitmap;
1078+
1079+
void *alpha_data = CGBitmapContextGetData(alpha_bitmap);
1080+
void *gray_data = CGBitmapContextGetData(quartz_bitmap);
1081+
1082+
/* Copy the alpha channel data into the grayscale bitmap */
1083+
memcpy(gray_data, alpha_data, stride * devHeight);
1084+
1085+
/* We're finished with the alpha channel bitmap now */
1086+
CGContextRelease(alpha_bitmap);
1087+
}
1088+
10581089
/* Create image from bitmap context */
10591090
CGImageRef maskImage;
10601091
maskImage = CGBitmapContextCreateImage(quartz_bitmap);
@@ -2730,10 +2761,6 @@ static SEXP RQuartz_setMask(SEXP mask, SEXP ref, pDevDesc dd) {
27302761
if (isNull(mask)) {
27312762
/* Set NO mask */
27322763
index = -1;
2733-
} else if (R_GE_maskType(mask) == R_GE_alphaMask) {
2734-
warning(_("Ignored alpha mask (not supported on this device)"));
2735-
/* Set NO mask */
2736-
index = -1;
27372764
} else {
27382765
if (isNull(ref)) {
27392766
/* Create a new mask */
@@ -2953,8 +2980,10 @@ static SEXP RQuartz_capabilities(SEXP capabilities) {
29532980
SET_VECTOR_ELT(capabilities, R_GE_capability_clippingPaths, clippingPaths);
29542981
UNPROTECT(1);
29552982

2956-
PROTECT(masks = allocVector(INTSXP, 1));
2983+
2984+
PROTECT(masks = allocVector(INTSXP, 2));
29572985
INTEGER(masks)[0] = R_GE_luminanceMask;
2986+
INTEGER(masks)[1] = R_GE_alphaMask;
29582987
SET_VECTOR_ELT(capabilities, R_GE_capability_masks, masks);
29592988
UNPROTECT(1);
29602989

0 commit comments

Comments
 (0)