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,
42 const String& documentTitle,
43 const int totalWidth_,
44 const int totalHeight_)
45 : out (resultingPostScript),
46 totalWidth (totalWidth_),
47 totalHeight (totalHeight_),
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)
201 if (++itemsOnLine == 6)
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);
247 if (++itemsOnLine == 4)
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;
272 const float cp1y = lastY + (i.y1 - lastY) * 2.0f / 3.0f;
273 const float cp2x = cp1x + (i.x2 - lastX) / 3.0f;
274 const float cp2y = cp1y + (i.y2 - lastY) / 3.0f;
276 writeXY (cp1x, cp1y);
277 writeXY (cp2x, cp2y);
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());
358void LowLevelGraphicsPostScriptRenderer::fillRectList (
const RectangleList<float>& list)
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)
424 const uint8* pixelData = srcData.getPixelPointer (x, y);
426 if (x >= sx && y >= sy)
430 PixelARGB p (*(
const PixelARGB*) pixelData);
432 pixel = Colours::white.overlaidWith (Colour (p));
436 pixel = Colour (*((
const PixelRGB*) pixelData));
445 pixel = Colours::transparentWhite;
448 const uint8 pixelValues[3] = { pixel.getRed(), pixel.getGreen(), pixel.getBlue() };
453 if (charsOnLine > 100)
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));
475 RectangleList<int> imageClip;
476 sourceImage.createSolidAreaMask (imageClip, 0.5f);
481 for (
auto& i : imageClip)
483 if (++itemsOnLine == 6)
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.
unsigned char uint8
A platform-independent 8-bit unsigned integer type.