in pdfbox/src/main/java/org/apache/pdfbox/rendering/PageDrawer.java [1767:1937]
private TransparencyGroup(PDTransparencyGroup form, boolean isSoftMask, Matrix ctm,
PDColor backdropColor) throws IOException
{
Graphics2D savedGraphics = graphics;
List<Path2D> savedLastClips = lastClips;
Shape savedInitialClip = initialClip;
// get the CTM x Form Matrix transform
Matrix transform = Matrix.concatenate(ctm, form.getMatrix());
// transform the bbox
PDRectangle formBBox = form.getBBox();
if (formBBox == null)
{
// PDFBOX-5471
// check done here and not in caller to avoid getBBox() creating rectangle twice
LOG.warn("transparency group ignored because BBox is null");
formBBox = new PDRectangle();
}
GeneralPath transformedBox = formBBox.transform(transform);
// clip the bbox to prevent giant bboxes from consuming all memory
Area transformed = new Area(transformedBox);
transformed.intersect(getGraphicsState().getCurrentClippingPath());
Rectangle2D clipRect = transformed.getBounds2D();
if (clipRect.isEmpty())
{
image = null;
bbox = null;
minX = 0;
minY = 0;
maxX = 0;
maxY = 0;
width = 0;
height = 0;
return;
}
this.bbox = new PDRectangle((float)clipRect.getX(), (float)clipRect.getY(),
(float)clipRect.getWidth(), (float)clipRect.getHeight());
// apply the underlying Graphics2D device's DPI transform
AffineTransform xformOriginal = xform;
xform = AffineTransform.getScaleInstance(xformScalingFactorX, xformScalingFactorY);
Rectangle2D bounds = xform.createTransformedShape(clipRect).getBounds2D();
minX = (int) Math.floor(bounds.getMinX());
minY = (int) Math.floor(bounds.getMinY());
maxX = (int) Math.floor(bounds.getMaxX()) + 1;
maxY = (int) Math.floor(bounds.getMaxY()) + 1;
width = maxX - minX;
height = maxY - minY;
// FIXME - color space
if (isGray(form.getGroup().getColorSpace(form.getResources())))
{
image = create2ByteGrayAlphaImage(width, height);
}
else
{
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
}
boolean needsBackdrop = !isSoftMask && !form.getGroup().isIsolated() &&
hasBlendMode(form, new HashSet<>());
BufferedImage backdropImage = null;
// Position of this group in parent group's coordinates
int backdropX = 0;
int backdropY = 0;
if (needsBackdrop)
{
if (transparencyGroupStack.isEmpty())
{
// Use the current page as the parent group.
backdropImage = renderer.getPageImage();
if (backdropImage == null)
{
needsBackdrop = false;
}
else
{
backdropX = minX;
backdropY = backdropImage.getHeight() - maxY;
}
}
else
{
TransparencyGroup parentGroup = transparencyGroupStack.peek();
backdropImage = parentGroup.image;
backdropX = minX - parentGroup.minX;
backdropY = parentGroup.maxY - maxY;
}
}
Graphics2D g = image.createGraphics();
if (needsBackdrop)
{
// backdropImage must be included in group image but not in group alpha.
g.drawImage(backdropImage, 0, 0, width, height,
backdropX, backdropY, backdropX + width, backdropY + height, null);
g = new GroupGraphics(image, g);
}
if (isSoftMask && backdropColor != null)
{
// "If the subtype is Luminosity, the transparency group XObject G shall be
// composited with a fully opaque backdrop whose colour is everywhere defined
// by the soft-mask dictionary's BC entry."
g.setBackground(new Color(backdropColor.toRGB()));
g.clearRect(0, 0, width, height);
}
// flip y-axis
g.translate(0, image.getHeight());
g.scale(1, -1);
boolean savedFlipTG = flipTG;
flipTG = false;
// apply device transform (DPI)
// the initial translation is ignored, because we're not writing into the initial graphics device
g.transform(xform);
PDRectangle pageSizeOriginal = pageSize;
pageSize = new PDRectangle(minX / xformScalingFactorX,
minY / xformScalingFactorY,
(float) (bounds.getWidth() / xformScalingFactorX),
(float) (bounds.getHeight() / xformScalingFactorY));
int clipWindingRuleOriginal = clipWindingRule;
clipWindingRule = -1;
GeneralPath linePathOriginal = linePath;
linePath = new GeneralPath();
// adjust the origin
g.translate(-clipRect.getX(), -clipRect.getY());
graphics = g;
setRenderingHints();
try
{
if (isSoftMask)
{
processSoftMask(form);
}
else
{
transparencyGroupStack.push(this);
processTransparencyGroup(form);
if (!transparencyGroupStack.isEmpty())
{
transparencyGroupStack.pop();
}
}
if (needsBackdrop)
{
((GroupGraphics) graphics).removeBackdrop(backdropImage, backdropX, backdropY);
}
}
finally
{
flipTG = savedFlipTG;
lastClips = savedLastClips;
graphics.dispose();
graphics = savedGraphics;
initialClip = savedInitialClip;
clipWindingRule = clipWindingRuleOriginal;
linePath = linePathOriginal;
pageSize = pageSizeOriginal;
xform = xformOriginal;
}
}