History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/print/PSPathGraphics.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/print/PSPathGraphics.java+780−0
@@ -0,0 +1,780 @@
1/*
2 * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.print;
27
28import java.awt.Color;
29import java.awt.Font;
30import java.awt.Graphics;
31import java.awt.Graphics2D;
32import java.awt.Image;
33import java.awt.Shape;
34import java.awt.Transparency;
35
36import java.awt.font.FontRenderContext;
37import java.awt.font.TextLayout;
38
39import java.awt.geom.AffineTransform;
40import java.awt.geom.Area;
41import java.awt.geom.PathIterator;
42import java.awt.geom.Point2D;
43import java.awt.geom.Rectangle2D;
44import java.awt.geom.Line2D;
45
46import java.awt.image.BufferedImage;
47import sun.awt.image.ByteComponentRaster;
48
49import java.awt.print.PageFormat;
50import java.awt.print.Printable;
51import java.awt.print.PrinterException;
52import java.awt.print.PrinterJob;
53
54/**
55 * This class converts paths into PostScript
56 * by breaking all graphics into fills and
57 * clips of paths.
58 */
59
60class PSPathGraphics extends PathGraphics {
61
62 /**
63 * For a drawing application the initial user space
64 * resolution is 72dpi.
65 */
66 private static final int DEFAULT_USER_RES = 72;
67
68 PSPathGraphics(Graphics2D graphics, PrinterJob printerJob,
69 Printable painter, PageFormat pageFormat, int pageIndex,
70 boolean canRedraw) {
71 super(graphics, printerJob, painter, pageFormat, pageIndex, canRedraw);
72 }
73
74 /**
75 * Creates a new <code>Graphics</code> object that is
76 * a copy of this <code>Graphics</code> object.
77 * @return a new graphics context that is a copy of
78 * this graphics context.
79 * @since JDK1.0
80 */
81 public Graphics create() {
82
83 return new PSPathGraphics((Graphics2D) getDelegate().create(),
84 getPrinterJob(),
85 getPrintable(),
86 getPageFormat(),
87 getPageIndex(),
88 canDoRedraws());
89 }
90
91
92 /**
93 * Override the inherited implementation of fill
94 * so that we can generate PostScript in user space
95 * rather than device space.
96 */
97 public void fill(Shape s, Color color) {
98 deviceFill(s.getPathIterator(new AffineTransform()), color);
99 }
100
101 /**
102 * Draws the text given by the specified string, using this
103 * graphics context's current font and color. The baseline of the
104 * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in this
105 * graphics context's coordinate system.
106 * @param str the string to be drawn.
107 * @param x the <i>x</i> coordinate.
108 * @param y the <i>y</i> coordinate.
109 * @see java.awt.Graphics#drawBytes
110 * @see java.awt.Graphics#drawChars
111 * @since JDK1.0
112 */
113 public void drawString(String str, int x, int y) {
114 drawString(str, (float) x, (float) y);
115 }
116
117 /**
118 * Renders the text specified by the specified <code>String</code>,
119 * using the current <code>Font</code> and <code>Paint</code> attributes
120 * in the <code>Graphics2D</code> context.
121 * The baseline of the first character is at position
122 * (<i>x</i>,&nbsp;<i>y</i>) in the User Space.
123 * The rendering attributes applied include the <code>Clip</code>,
124 * <code>Transform</code>, <code>Paint</code>, <code>Font</code> and
125 * <code>Composite</code> attributes. For characters in script systems
126 * such as Hebrew and Arabic, the glyphs can be rendered from right to
127 * left, in which case the coordinate supplied is the location of the
128 * leftmost character on the baseline.
129 * @param s the <code>String</code> to be rendered
130 * @param x,&nbsp;y the coordinates where the <code>String</code>
131 * should be rendered
132 * @see #setPaint
133 * @see java.awt.Graphics#setColor
134 * @see java.awt.Graphics#setFont
135 * @see #setTransform
136 * @see #setComposite
137 * @see #setClip
138 */
139 public void drawString(String str, float x, float y) {
140 drawString(str, x, y, getFont(), getFontRenderContext(), 0f);
141 }
142
143
144 protected boolean canDrawStringToWidth() {
145 return true;
146 }
147
148 protected int platformFontCount(Font font, String str) {
149 PSPrinterJob psPrinterJob = (PSPrinterJob) getPrinterJob();
150 return psPrinterJob.platformFontCount(font, str);
151 }
152
153 protected void drawString(String str, float x, float y,
154 Font font, FontRenderContext frc, float w) {
155 if (str.length() == 0) {
156 return;
157 }
158
159 /* If the Font has layout attributes we need to delegate to TextLayout.
160 * TextLayout renders text as GlyphVectors. We try to print those
161 * using printer fonts - ie using Postscript text operators so
162 * we may be reinvoked. In that case the "!printingGlyphVector" test
163 * prevents us recursing and instead sends us into the body of the
164 * method where we can safely ignore layout attributes as those
165 * are already handled by TextLayout.
166 */
167 if (font.hasLayoutAttributes() && !printingGlyphVector) {
168 TextLayout layout = new TextLayout(str, font, frc);
169 layout.draw(this, x, y);
170 return;
171 }
172
173 Font oldFont = getFont();
174 if (!oldFont.equals(font)) {
175 setFont(font);
176 } else {
177 oldFont = null;
178 }
179
180 boolean drawnWithPS = false;
181
182 float translateX = 0f, translateY = 0f;
183 boolean fontisTransformed = getFont().isTransformed();
184
185 if (fontisTransformed) {
186 AffineTransform fontTx = getFont().getTransform();
187 int transformType = fontTx.getType();
188 /* TYPE_TRANSLATION is a flag bit but we can do "==" here
189 * because we want to detect when its just that bit set and
190 *
191 */
192 if (transformType == AffineTransform.TYPE_TRANSLATION) {
193 translateX = (float)(fontTx.getTranslateX());
194 translateY = (float)(fontTx.getTranslateY());
195 if (Math.abs(translateX) < 0.00001) translateX = 0f;
196 if (Math.abs(translateY) < 0.00001) translateY = 0f;
197 fontisTransformed = false;
198 }
199 }
200
201 boolean directToPS = !fontisTransformed;
202
203 if (!PSPrinterJob.shapeTextProp && directToPS) {
204
205 PSPrinterJob psPrinterJob = (PSPrinterJob) getPrinterJob();
206 if (psPrinterJob.setFont(getFont())) {
207
208 /* Set the text color.
209 * We should not be in this shape printing path
210 * if the application is drawing with non-solid
211 * colors. We should be in the raster path. Because
212 * we are here in the shape path, the cast of the
213 * paint to a Color should be fine.
214 */
215 try {
216 psPrinterJob.setColor((Color)getPaint());
217 } catch (ClassCastException e) {
218 if (oldFont != null) {
219 setFont(oldFont);
220 }
221 throw new IllegalArgumentException(
222 "Expected a Color instance");
223 }
224
225 psPrinterJob.setTransform(getTransform());
226 psPrinterJob.setClip(getClip());
227
228 drawnWithPS = psPrinterJob.textOut(this, str,
229 x+translateX, y+translateY,
230 font, frc, w);
231 }
232 }
233
234 /* The text could not be converted directly to PS text
235 * calls so decompose the text into a shape.
236 */
237 if (drawnWithPS == false) {
238 if (oldFont != null) {
239 setFont(oldFont);
240 oldFont = null;
241 }
242 super.drawString(str, x, y, font, frc, w);
243 }
244
245 if (oldFont != null) {
246 setFont(oldFont);
247 }
248 }
249
250 /**
251 * The various <code>drawImage()</code> methods for
252 * <code>WPathGraphics</code> are all decomposed
253 * into an invocation of <code>drawImageToPlatform</code>.
254 * The portion of the passed in image defined by
255 * <code>srcX, srcY, srcWidth, and srcHeight</code>
256 * is transformed by the supplied AffineTransform and
257 * drawn using PS to the printer context.
258 *
259 * @param img The image to be drawn.
260 * This method does nothing if <code>img</code> is null.
261 * @param xform Used to tranform the image before drawing.
262 * This can be null.
263 * @param bgcolor This color is drawn where the image has transparent
264 * pixels. If this parameter is null then the
265 * pixels already in the destination should show
266 * through.
267 * @param srcX With srcY this defines the upper-left corner
268 * of the portion of the image to be drawn.
269 *
270 * @param srcY With srcX this defines the upper-left corner
271 * of the portion of the image to be drawn.
272 * @param srcWidth The width of the portion of the image to
273 * be drawn.
274 * @param srcHeight The height of the portion of the image to
275 * be drawn.
276 * @param handlingTransparency if being recursively called to
277 * print opaque region of transparent image
278 */
279 protected boolean drawImageToPlatform(Image image, AffineTransform xform,
280 Color bgcolor,
281 int srcX, int srcY,
282 int srcWidth, int srcHeight,
283 boolean handlingTransparency) {
284
285 BufferedImage img = getBufferedImage(image);
286 if (img == null) {
287 return true;
288 }
289
290 PSPrinterJob psPrinterJob = (PSPrinterJob) getPrinterJob();
291
292 /* The full transform to be applied to the image is the
293 * caller's transform concatenated on to the transform
294 * from user space to device space. If the caller didn't
295 * supply a transform then we just act as if they passed
296 * in the identify transform.
297 */
298 AffineTransform fullTransform = getTransform();
299 if (xform == null) {
300 xform = new AffineTransform();
301 }
302 fullTransform.concatenate(xform);
303
304 /* Split the full transform into a pair of
305 * transforms. The first transform holds effects
306 * such as rotation and shearing. The second transform
307 * is setup to hold only the scaling effects.
308 * These transforms are created such that a point,
309 * p, in user space, when transformed by 'fullTransform'
310 * lands in the same place as when it is transformed
311 * by 'rotTransform' and then 'scaleTransform'.
312 *
313 * The entire image transformation is not in Java in order
314 * to minimize the amount of memory needed in the VM. By
315 * dividing the transform in two, we rotate and shear
316 * the source image in its own space and only go to
317 * the, usually, larger, device space when we ask
318 * PostScript to perform the final scaling.
319 */
320 double[] fullMatrix = new double[6];
321 fullTransform.getMatrix(fullMatrix);
322
323 /* Calculate the amount of scaling in the x
324 * and y directions. This scaling is computed by
325 * transforming a unit vector along each axis
326 * and computing the resulting magnitude.
327 * The computed values 'scaleX' and 'scaleY'
328 * represent the amount of scaling PS will be asked
329 * to perform.
330 * Clamp this to the device scale for better quality printing.
331 */
332 Point2D.Float unitVectorX = new Point2D.Float(1, 0);
333 Point2D.Float unitVectorY = new Point2D.Float(0, 1);
334 fullTransform.deltaTransform(unitVectorX, unitVectorX);
335 fullTransform.deltaTransform(unitVectorY, unitVectorY);
336
337 Point2D.Float origin = new Point2D.Float(0, 0);
338 double scaleX = unitVectorX.distance(origin);
339 double scaleY = unitVectorY.distance(origin);
340
341 double devResX = psPrinterJob.getXRes();
342 double devResY = psPrinterJob.getYRes();
343 double devScaleX = devResX / DEFAULT_USER_RES;
344 double devScaleY = devResY / DEFAULT_USER_RES;
345
346 /* check if rotated or sheared */
347 int transformType = fullTransform.getType();
348 boolean clampScale = ((transformType &
349 (AffineTransform.TYPE_GENERAL_ROTATION |
350 AffineTransform.TYPE_GENERAL_TRANSFORM)) != 0);
351 if (clampScale) {
352 if (scaleX > devScaleX) scaleX = devScaleX;
353 if (scaleY > devScaleY) scaleY = devScaleY;
354 }
355
356 /* We do not need to draw anything if either scaling
357 * factor is zero.
358 */
359 if (scaleX != 0 && scaleY != 0) {
360
361 /* Here's the transformation we will do with Java2D,
362 */
363 AffineTransform rotTransform = new AffineTransform(
364 fullMatrix[0] / scaleX, //m00
365 fullMatrix[1] / scaleY, //m10
366 fullMatrix[2] / scaleX, //m01
367 fullMatrix[3] / scaleY, //m11
368 fullMatrix[4] / scaleX, //m02
369 fullMatrix[5] / scaleY); //m12
370
371 /* The scale transform is not used directly: we instead
372 * directly multiply by scaleX and scaleY.
373 *
374 * Conceptually here is what the scaleTransform is:
375 *
376 * AffineTransform scaleTransform = new AffineTransform(
377 * scaleX, //m00
378 * 0, //m10
379 * 0, //m01
380 * scaleY, //m11
381 * 0, //m02
382 * 0); //m12
383 */
384
385 /* Convert the image source's rectangle into the rotated
386 * and sheared space. Once there, we calculate a rectangle
387 * that encloses the resulting shape. It is this rectangle
388 * which defines the size of the BufferedImage we need to
389 * create to hold the transformed image.
390 */
391 Rectangle2D.Float srcRect = new Rectangle2D.Float(srcX, srcY,
392 srcWidth,
393 srcHeight);
394
395 Shape rotShape = rotTransform.createTransformedShape(srcRect);
396 Rectangle2D rotBounds = rotShape.getBounds2D();
397
398 /* add a fudge factor as some fp precision problems have
399 * been observed which caused pixels to be rounded down and
400 * out of the image.
401 */
402 rotBounds.setRect(rotBounds.getX(), rotBounds.getY(),
403 rotBounds.getWidth()+0.001,
404 rotBounds.getHeight()+0.001);
405
406 int boundsWidth = (int) rotBounds.getWidth();
407 int boundsHeight = (int) rotBounds.getHeight();
408
409 if (boundsWidth > 0 && boundsHeight > 0) {
410
411
412 /* If the image has transparent or semi-transparent
413 * pixels then we'll have the application re-render
414 * the portion of the page covered by the image.
415 * This will be done in a later call to print using the
416 * saved graphics state.
417 * However several special cases can be handled otherwise:
418 * - bitmask transparency with a solid background colour
419 * - images which have transparency color models but no
420 * transparent pixels
421 * - images with bitmask transparency and an IndexColorModel
422 * (the common transparent GIF case) can be handled by
423 * rendering just the opaque pixels.
424 */
425 boolean drawOpaque = true;
426 if (!handlingTransparency && hasTransparentPixels(img)) {
427 drawOpaque = false;
428 if (isBitmaskTransparency(img)) {
429 if (bgcolor == null) {
430 if (drawBitmaskImage(img, xform, bgcolor,
431 srcX, srcY,
432 srcWidth, srcHeight)) {
433 // image drawn, just return.
434 return true;
435 }
436 } else if (bgcolor.getTransparency()
437 == Transparency.OPAQUE) {
438 drawOpaque = true;
439 }
440 }
441 if (!canDoRedraws()) {
442 drawOpaque = true;
443 }
444 } else {
445 // if there's no transparent pixels there's no need
446 // for a background colour. This can avoid edge artifacts
447 // in rotation cases.
448 bgcolor = null;
449 }
450 // if src region extends beyond the image, the "opaque" path
451 // may blit b/g colour (including white) where it shoudn't.
452 if ((srcX+srcWidth > img.getWidth(null) ||
453 srcY+srcHeight > img.getHeight(null))
454 && canDoRedraws()) {
455 drawOpaque = false;
456 }
457 if (drawOpaque == false) {
458
459 fullTransform.getMatrix(fullMatrix);
460 AffineTransform tx =
461 new AffineTransform(
462 fullMatrix[0] / devScaleX, //m00
463 fullMatrix[1] / devScaleY, //m10
464 fullMatrix[2] / devScaleX, //m01
465 fullMatrix[3] / devScaleY, //m11
466 fullMatrix[4] / devScaleX, //m02
467 fullMatrix[5] / devScaleY); //m12
468
469 Rectangle2D.Float rect =
470 new Rectangle2D.Float(srcX, srcY, srcWidth, srcHeight);
471
472 Shape shape = fullTransform.createTransformedShape(rect);
473 // Region isn't user space because its potentially
474 // been rotated for landscape.
475 Rectangle2D region = shape.getBounds2D();
476
477 region.setRect(region.getX(), region.getY(),
478 region.getWidth()+0.001,
479 region.getHeight()+0.001);
480
481 // Try to limit the amount of memory used to 8Mb, so
482 // if at device resolution this exceeds a certain
483 // image size then scale down the region to fit in
484 // that memory, but never to less than 72 dpi.
485
486 int w = (int)region.getWidth();
487 int h = (int)region.getHeight();
488 int nbytes = w * h * 3;
489 int maxBytes = 8 * 1024 * 1024;
490 double origDpi = (devResX < devResY) ? devResX : devResY;
491 int dpi = (int)origDpi;
492 double scaleFactor = 1;
493
494 double maxSFX = w/(double)boundsWidth;
495 double maxSFY = h/(double)boundsHeight;
496 double maxSF = (maxSFX > maxSFY) ? maxSFY : maxSFX;
497 int minDpi = (int)(dpi/maxSF);
498 if (minDpi < DEFAULT_USER_RES) minDpi = DEFAULT_USER_RES;
499
500 while (nbytes > maxBytes && dpi > minDpi) {
501 scaleFactor *= 2;
502 dpi /= 2;
503 nbytes /= 4;
504 }
505 if (dpi < minDpi) {
506 scaleFactor = (origDpi / minDpi);
507 }
508
509 region.setRect(region.getX()/scaleFactor,
510 region.getY()/scaleFactor,
511 region.getWidth()/scaleFactor,
512 region.getHeight()/scaleFactor);
513
514 /*
515 * We need to have the clip as part of the saved state,
516 * either directly, or all the components that are
517 * needed to reconstitute it (image source area,
518 * image transform and current graphics transform).
519 * The clip is described in user space, so we need to
520 * save the current graphics transform anyway so just
521 * save these two.
522 */
523 psPrinterJob.saveState(getTransform(), getClip(),
524 region, scaleFactor, scaleFactor);
525 return true;
526
527 /* The image can be rendered directly by PS so we
528 * copy it into a BufferedImage (this takes care of
529 * ColorSpace and BufferedImageOp issues) and then
530 * send that to PS.
531 */
532 } else {
533
534 /* Create a buffered image big enough to hold the portion
535 * of the source image being printed.
536 */
537 BufferedImage deepImage = new BufferedImage(
538 (int) rotBounds.getWidth(),
539 (int) rotBounds.getHeight(),
540 BufferedImage.TYPE_3BYTE_BGR);
541
542 /* Setup a Graphics2D on to the BufferedImage so that the
543 * source image when copied, lands within the image buffer.
544 */
545 Graphics2D imageGraphics = deepImage.createGraphics();
546 imageGraphics.clipRect(0, 0,
547 deepImage.getWidth(),
548 deepImage.getHeight());
549
550 imageGraphics.translate(-rotBounds.getX(),
551 -rotBounds.getY());
552 imageGraphics.transform(rotTransform);
553
554 /* Fill the BufferedImage either with the caller supplied
555 * color, 'bgColor' or, if null, with white.
556 */
557 if (bgcolor == null) {
558 bgcolor = Color.white;
559 }
560
561 /* REMIND: no need to use scaling here. */
562 imageGraphics.drawImage(img,
563 srcX, srcY,
564 srcX + srcWidth, srcY + srcHeight,
565 srcX, srcY,
566 srcX + srcWidth, srcY + srcHeight,
567 bgcolor, null);
568
569 /* In PSPrinterJob images are printed in device space
570 * and therefore we need to set a device space clip.
571 * FIX: this is an overly tight coupling of these
572 * two classes.
573 * The temporary clip set needs to be an intersection
574 * with the previous user clip.
575 * REMIND: two xfms may lose accuracy in clip path.
576 */
577 Shape holdClip = getClip();
578 Shape oldClip =
579 getTransform().createTransformedShape(holdClip);
580 AffineTransform sat = AffineTransform.getScaleInstance(
581 scaleX, scaleY);
582 Shape imgClip = sat.createTransformedShape(rotShape);
583 Area imgArea = new Area(imgClip);
584 Area oldArea = new Area(oldClip);
585 imgArea.intersect(oldArea);
586 psPrinterJob.setClip(imgArea);
587
588 /* Scale the bounding rectangle by the scale transform.
589 * Because the scaling transform has only x and y
590 * scaling components it is equivalent to multiply
591 * the x components of the bounding rectangle by
592 * the x scaling factor and to multiply the y components
593 * by the y scaling factor.
594 */
595 Rectangle2D.Float scaledBounds
596 = new Rectangle2D.Float(
597 (float) (rotBounds.getX() * scaleX),
598 (float) (rotBounds.getY() * scaleY),
599 (float) (rotBounds.getWidth() * scaleX),
600 (float) (rotBounds.getHeight() * scaleY));
601
602
603 /* Pull the raster data from the buffered image
604 * and pass it along to PS.
605 */
606 ByteComponentRaster tile =
607 (ByteComponentRaster)deepImage.getRaster();
608
609 psPrinterJob.drawImageBGR(tile.getDataStorage(),
610 scaledBounds.x, scaledBounds.y,
611 (float)Math.rint(scaledBounds.width+0.5),
612 (float)Math.rint(scaledBounds.height+0.5),
613 0f, 0f,
614 deepImage.getWidth(), deepImage.getHeight(),
615 deepImage.getWidth(), deepImage.getHeight());
616
617 /* Reset the device clip to match user clip */
618 psPrinterJob.setClip(
619 getTransform().createTransformedShape(holdClip));
620
621
622 imageGraphics.dispose();
623 }
624
625 }
626 }
627
628 return true;
629 }
630
631 /** Redraw a rectanglular area using a proxy graphics
632 * To do this we need to know the rectangular area to redraw and
633 * the transform & clip in effect at the time of the original drawImage
634 *
635 */
636
637 public void redrawRegion(Rectangle2D region, double scaleX, double scaleY,
638 Shape savedClip, AffineTransform savedTransform)
639
640 throws PrinterException {
641
642 PSPrinterJob psPrinterJob = (PSPrinterJob)getPrinterJob();
643 Printable painter = getPrintable();
644 PageFormat pageFormat = getPageFormat();
645 int pageIndex = getPageIndex();
646
647 /* Create a buffered image big enough to hold the portion
648 * of the source image being printed.
649 */
650 BufferedImage deepImage = new BufferedImage(
651 (int) region.getWidth(),
652 (int) region.getHeight(),
653 BufferedImage.TYPE_3BYTE_BGR);
654
655 /* Get a graphics for the application to render into.
656 * We initialize the buffer to white in order to
657 * match the paper and then we shift the BufferedImage
658 * so that it covers the area on the page where the
659 * caller's Image will be drawn.
660 */
661 Graphics2D g = deepImage.createGraphics();
662 ProxyGraphics2D proxy = new ProxyGraphics2D(g, psPrinterJob);
663 proxy.setColor(Color.white);
664 proxy.fillRect(0, 0, deepImage.getWidth(), deepImage.getHeight());
665 proxy.clipRect(0, 0, deepImage.getWidth(), deepImage.getHeight());
666
667 proxy.translate(-region.getX(), -region.getY());
668
669 /* Calculate the resolution of the source image.
670 */
671 float sourceResX = (float)(psPrinterJob.getXRes() / scaleX);
672 float sourceResY = (float)(psPrinterJob.getYRes() / scaleY);
673
674 /* The application expects to see user space at 72 dpi.
675 * so change user space from image source resolution to
676 * 72 dpi.
677 */
678 proxy.scale(sourceResX / DEFAULT_USER_RES,
679 sourceResY / DEFAULT_USER_RES);
680 proxy.translate(
681 -psPrinterJob.getPhysicalPrintableX(pageFormat.getPaper())
682 / psPrinterJob.getXRes() * DEFAULT_USER_RES,
683 -psPrinterJob.getPhysicalPrintableY(pageFormat.getPaper())
684 / psPrinterJob.getYRes() * DEFAULT_USER_RES);
685 /* NB User space now has to be at 72 dpi for this calc to be correct */
686 proxy.transform(new AffineTransform(getPageFormat().getMatrix()));
687
688 proxy.setPaint(Color.black);
689
690 painter.print(proxy, pageFormat, pageIndex);
691
692 g.dispose();
693
694 /* In PSPrinterJob images are printed in device space
695 * and therefore we need to set a device space clip.
696 */
697 psPrinterJob.setClip(savedTransform.createTransformedShape(savedClip));
698
699
700 /* Scale the bounding rectangle by the scale transform.
701 * Because the scaling transform has only x and y
702 * scaling components it is equivalent to multiply
703 * the x components of the bounding rectangle by
704 * the x scaling factor and to multiply the y components
705 * by the y scaling factor.
706 */
707 Rectangle2D.Float scaledBounds
708 = new Rectangle2D.Float(
709 (float) (region.getX() * scaleX),
710 (float) (region.getY() * scaleY),
711 (float) (region.getWidth() * scaleX),
712 (float) (region.getHeight() * scaleY));
713
714
715 /* Pull the raster data from the buffered image
716 * and pass it along to PS.
717 */
718 ByteComponentRaster tile = (ByteComponentRaster)deepImage.getRaster();
719
720 psPrinterJob.drawImageBGR(tile.getDataStorage(),
721 scaledBounds.x, scaledBounds.y,
722 scaledBounds.width,
723 scaledBounds.height,
724 0f, 0f,
725 deepImage.getWidth(), deepImage.getHeight(),
726 deepImage.getWidth(), deepImage.getHeight());
727
728
729 }
730
731
732 /*
733 * Fill the path defined by <code>pathIter</code>
734 * with the specified color.
735 * The path is provided in current user space.
736 */
737 protected void deviceFill(PathIterator pathIter, Color color) {
738
739 PSPrinterJob psPrinterJob = (PSPrinterJob) getPrinterJob();
740 psPrinterJob.deviceFill(pathIter, color, getTransform(), getClip());
741 }
742
743 /*
744 * Draw the bounding rectangle using path by calling draw()
745 * function and passing a rectangle shape.
746 */
747 protected void deviceFrameRect(int x, int y, int width, int height,
748 Color color) {
749
750 draw(new Rectangle2D.Float(x, y, width, height));
751 }
752
753 /*
754 * Draw a line using path by calling draw() function and passing
755 * a line shape.
756 */
757 protected void deviceDrawLine(int xBegin, int yBegin,
758 int xEnd, int yEnd, Color color) {
759
760 draw(new Line2D.Float(xBegin, yBegin, xEnd, yEnd));
761 }
762
763 /*
764 * Fill the rectangle with the specified color by calling fill().
765 */
766 protected void deviceFillRect(int x, int y, int width, int height,
767 Color color) {
768 fill(new Rectangle2D.Float(x, y, width, height));
769 }
770
771
772 /*
773 * This method should not be invoked by PSPathGraphics.
774 * FIX: Rework PathGraphics so that this method is
775 * not an abstract method there.
776 */
777 protected void deviceClip(PathIterator pathIter) {
778 }
779
780}