31#define WARN_ABOUT_NON_POSTSCRIPT_OPERATIONS 0
34#if JUCE_DEBUG && WARN_ABOUT_NON_POSTSCRIPT_OPERATIONS
35 #define notPossibleInPostscriptAssert jassertfalse
37 #define notPossibleInPostscriptAssert
41LowLevelGraphicsPostScriptRenderer::LowLevelGraphicsPostScriptRenderer (OutputStream&
resultingPostScript,
50 stateStack.add (
new SavedState());
51 stateStack.getLast()->clip = Rectangle<int> (totalWidth_, totalHeight_);
53 const float scale =
jmin ((520.0f / (
float) totalWidth_), (750.0f / (
float) totalHeight));
55 out <<
"%!PS-Adobe-3.0 EPSF-3.0"
56 "\n%%BoundingBox: 0 0 600 824"
58 "\n%%Creator: Raw Material Software Limited - JUCE"
59 "\n%%Title: " << documentTitle <<
60 "\n%%CreationDate: none"
61 "\n%%LanguageLevel: 2"
64 "\n%%BeginResource: JRes"
65 "\n/bd {bind def} bind def"
66 "\n/c {setrgbcolor} bd"
71 "\n/cp {closepath} bd"
72 "\n/pr {3 index 3 index moveto 1 index 0 rlineto 0 1 index rlineto pop neg 0 rlineto pop pop closepath} bd"
73 "\n/doclip {initclip newpath} bd"
74 "\n/endclip {clip newpath} bd"
81 "\n%%EndPageSetup\n\n"
82 <<
"40 800 translate\n"
83 << scale <<
' ' << scale <<
" scale\n\n";
87bool LowLevelGraphicsPostScriptRenderer::isVectorDevice()
const
92void LowLevelGraphicsPostScriptRenderer::setOrigin (
Point<int> o)
96 stateStack.getLast()->xOffset += o.
x;
97 stateStack.getLast()->yOffset += o.
y;
102void LowLevelGraphicsPostScriptRenderer::addTransform (
const AffineTransform& )
108float LowLevelGraphicsPostScriptRenderer::getPhysicalPixelScaleFactor() {
return 1.0f; }
110bool LowLevelGraphicsPostScriptRenderer::clipToRectangle (
const Rectangle<int>& r)
113 return stateStack.getLast()->clip.clipTo (r.translated (stateStack.getLast()->xOffset, stateStack.getLast()->yOffset));
116bool LowLevelGraphicsPostScriptRenderer::clipToRectangleList (
const RectangleList<int>& clipRegion)
119 return stateStack.getLast()->clip.clipTo (clipRegion);
122void LowLevelGraphicsPostScriptRenderer::excludeClipRectangle (
const Rectangle<int>& r)
125 stateStack.getLast()->clip.subtract (r.translated (stateStack.getLast()->xOffset, stateStack.getLast()->yOffset));
128void LowLevelGraphicsPostScriptRenderer::clipToPath (
const Path& path,
const AffineTransform& transform)
133 p.applyTransform (
transform.translated ((
float) stateStack.getLast()->xOffset, (
float) stateStack.getLast()->yOffset));
138void LowLevelGraphicsPostScriptRenderer::clipToImageAlpha (
const Image& ,
const AffineTransform& )
144bool LowLevelGraphicsPostScriptRenderer::clipRegionIntersects (
const Rectangle<int>& r)
146 return stateStack.getLast()->clip.intersectsRectangle (r.translated (stateStack.getLast()->xOffset, stateStack.getLast()->yOffset));
149Rectangle<int> LowLevelGraphicsPostScriptRenderer::getClipBounds()
const
151 return stateStack.getLast()->clip.getBounds().translated (-stateStack.getLast()->xOffset,
152 -stateStack.getLast()->yOffset);
155bool LowLevelGraphicsPostScriptRenderer::isClipEmpty()
const
157 return stateStack.getLast()->clip.isEmpty();
161LowLevelGraphicsPostScriptRenderer::SavedState::SavedState()
167void LowLevelGraphicsPostScriptRenderer::saveState()
169 stateStack.add (
new SavedState (*stateStack.getLast()));
172void LowLevelGraphicsPostScriptRenderer::restoreState()
174 jassert (stateStack.size() > 0);
176 if (stateStack.size() > 0)
177 stateStack.removeLast();
180void LowLevelGraphicsPostScriptRenderer::beginTransparencyLayer (
float)
184void LowLevelGraphicsPostScriptRenderer::endTransparencyLayer()
189void LowLevelGraphicsPostScriptRenderer::writeClip()
199 for (
auto& i : stateStack.getLast()->clip)
207 out << i.getX() <<
' ' << -i.getY() <<
' '
208 << i.getWidth() <<
' ' << -i.getHeight() <<
" pr ";
215void LowLevelGraphicsPostScriptRenderer::writeColour (Colour colour)
217 Colour c (Colours::white.overlaidWith (colour));
223 out << String (c.getFloatRed(), 3) <<
' '
224 << String (c.getFloatGreen(), 3) <<
' '
225 << String (c.getFloatBlue(), 3) <<
" c\n";
229void LowLevelGraphicsPostScriptRenderer::writeXY (
const float x,
const float y)
const
231 out << String (x, 2) <<
' '
232 << String (-y, 2) <<
' ';
235void LowLevelGraphicsPostScriptRenderer::writePath (
const Path& path)
const
243 Path::Iterator i (path);
253 switch (i.elementType)
256 writeXY (i.x1, i.y1);
263 writeXY (i.x1, i.y1);
271 const float cp1x = lastX + (i.x1 - lastX) * 2.0f / 3.0f;
273 const float cp2x =
cp1x + (i.x2 - lastX) / 3.0f;
278 writeXY (i.x2, i.y2);
286 writeXY (i.x1, i.y1);
287 writeXY (i.x2, i.y2);
288 writeXY (i.x3, i.y3);
307void LowLevelGraphicsPostScriptRenderer::writeTransform (
const AffineTransform&
trans)
const
310 <<
trans.mat00 <<
' '
311 <<
trans.mat10 <<
' '
312 <<
trans.mat01 <<
' '
313 <<
trans.mat11 <<
' '
314 <<
trans.mat02 <<
' '
315 <<
trans.mat12 <<
" ] concat ";
319void LowLevelGraphicsPostScriptRenderer::setFill (
const FillType& fillType)
321 stateStack.getLast()->fillType = fillType;
324void LowLevelGraphicsPostScriptRenderer::setOpacity (
float )
333void LowLevelGraphicsPostScriptRenderer::fillRect (
const Rectangle<int>& r,
const bool )
335 fillRect (r.toFloat());
338void LowLevelGraphicsPostScriptRenderer::fillRect (
const Rectangle<float>& r)
340 if (stateStack.getLast()->fillType.isColour())
343 writeColour (stateStack.getLast()->fillType.colour);
345 auto r2 = r.translated ((
float) stateStack.getLast()->xOffset,
346 (
float) stateStack.getLast()->yOffset);
348 out <<
r2.getX() <<
' ' << -
r2.getBottom() <<
' ' <<
r2.getWidth() <<
' ' <<
r2.getHeight() <<
" rectfill\n";
354 fillPath (p, AffineTransform());
360 fillPath (list.toPath(), AffineTransform());
364void LowLevelGraphicsPostScriptRenderer::fillPath (
const Path& path,
const AffineTransform& t)
366 if (stateStack.getLast()->fillType.isColour())
371 p.applyTransform (t.translated ((
float) stateStack.getLast()->xOffset,
372 (
float) stateStack.getLast()->yOffset));
375 writeColour (stateStack.getLast()->fillType.colour);
379 else if (stateStack.getLast()->fillType.isGradient())
383 notPossibleInPostscriptAssert;
390 p.applyTransform (t.translated ((
float) stateStack.getLast()->xOffset, (
float) stateStack.getLast()->yOffset));
395 auto bounds = stateStack.getLast()->clip.getBounds();
399 writeColour (stateStack.getLast()->fillType.gradient->getColourAtPosition (0.5f));
400 out << bounds.getX() <<
' ' << -bounds.getBottom() <<
' ' << bounds.getWidth() <<
' ' << bounds.getHeight() <<
" rectfill\n";
407void LowLevelGraphicsPostScriptRenderer::writeImage (
const Image&
im,
408 const int sx,
const int sy,
409 const int maxW,
const int maxH)
const
413 const int w =
jmin (maxW,
im.getWidth());
414 const int h =
jmin (maxH,
im.getHeight());
417 const Image::BitmapData srcData (
im, 0, 0, w, h);
420 for (
int y = h; --y >= 0;)
422 for (
int x = 0; x < w; ++x)
426 if (x >=
sx && y >=
sy)
430 PixelARGB p (*(
const PixelARGB*)
pixelData);
432 pixel = Colours::white.overlaidWith (Colour (p));
445 pixel = Colours::transparentWhite;
464void LowLevelGraphicsPostScriptRenderer::drawImage (
const Image& sourceImage,
const AffineTransform& transform)
466 const int w = sourceImage.getWidth();
467 const int h = sourceImage.getHeight();
472 writeTransform (
transform.translated ((
float) stateStack.getLast()->xOffset, (
float) stateStack.getLast()->yOffset)
473 .scaled (1.0f, -1.0f));
476 sourceImage.createSolidAreaMask (
imageClip, 0.5f);
489 out << i.getX() <<
' ' << i.getY() <<
' ' << i.getWidth() <<
' ' << i.getHeight() <<
" pr ";
492 out <<
" clip newpath\n";
494 out << w <<
' ' << h <<
" scale\n";
495 out << w <<
' ' << h <<
" 8 [" << w <<
" 0 0 -" << h <<
' ' << (
int) 0 <<
' ' << h <<
" ]\n";
497 writeImage (sourceImage, 0, 0, w, h);
499 out <<
"false 3 colorimage grestore\n";
505void LowLevelGraphicsPostScriptRenderer::drawLine (
const Line <float>& line)
508 p.addLineSegment (line, 1.0f);
509 fillPath (p, AffineTransform());
513void LowLevelGraphicsPostScriptRenderer::setFont (
const Font&
newFont)
515 stateStack.getLast()->font =
newFont;
518const Font& LowLevelGraphicsPostScriptRenderer::getFont()
520 return stateStack.getLast()->font;
523void LowLevelGraphicsPostScriptRenderer::drawGlyph (
int glyphNumber,
const AffineTransform& transform)
526 Font& font = stateStack.getLast()->font;
527 font.getTypefacePtr()->getOutlineForGlyph (
glyphNumber, p);
ResamplingQuality
Types of rendering quality that can be specified when drawing images.
@ quadraticTo
For this type, x1, y1, x2, y2 indicate the control point and endpoint of a quadratic curve.
@ closePath
Indicates that the sub-path is being closed.
@ lineTo
For this type, x1 and y1 indicate the end point of the line.
@ cubicTo
For this type, x1, y1, x2, y2, x3, y3 indicate the two control points and the endpoint of a cubic cur...
@ startNewSubPath
For this type, x1 and y1 will be set to indicate the first point in the subpath.
A pair of (x, y) coordinates.
constexpr bool isOrigin() const noexcept
Returns true if the point is (0, 0).
ValueType y
The point's Y coordinate.
ValueType x
The point's X coordinate.
static String toHexString(IntegerType number)
Returns a string representing this numeric value in hexadecimal.
constexpr Type jmin(Type a, Type b)
Returns the smaller of two values.
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
unsigned char uint8
A platform-independent 8-bit unsigned integer type.