1/* 2 * Copyright (c) 2007, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/** 25 * @test 26 * @bug 6531728 27 * @summary Test printing of images which need to have src area clipped 28 * @run main/manual=yesno/timeout=900 ClippedImages 29 */ 30 31import java.io.*; 32import java.awt.*; 33import java.awt.geom.*; 34import java.awt.event.*; 35import java.awt.print.*; 36import java.awt.image.BufferedImage; 37import javax.print.*; 38import javax.print.attribute.*; 39 40public class ClippedImages extends Frame implements ActionListener { 41 42 private ClippedImageCanvas c; 43 44 public static void main(String args[]) { 45 46 ClippedImages f = new ClippedImages(); 47 f.setVisible(true); 48 } 49 50 public ClippedImages() { 51 super("Clipped Src Area Image Printing Test"); 52 c = new ClippedImageCanvas(); 53 add("Center", c); 54 55 Button paintButton = new Button("Toggle Contents"); 56 paintButton.addActionListener(this); 57 58 Button printThisButton = new Button("Print This"); 59 printThisButton.addActionListener(this); 60 61 Button printAllButton = new Button("Print All"); 62 printAllButton.addActionListener(this); 63 64 Panel p = new Panel(); 65 p.add(paintButton); 66 p.add(printThisButton); 67 p.add(printAllButton); 68 add("South", p); 69 add("North", getInstructions()); 70 addWindowListener(new WindowAdapter() { 71 public void windowClosing(WindowEvent e) { 72 System.exit(0); 73 } 74 }); 75 76 pack(); 77 } 78 79 private TextArea getInstructions() { 80 TextArea ta = new TextArea(18, 60); 81 ta.setFont(new Font("Dialog", Font.PLAIN, 11)); 82 ta.setText 83 ("This is a manual test as it requires that you compare "+ 84 "the on-screen rendering with the printed output.\n"+ 85 "Select the 'Print All' button to print out the test\n"+ 86 "It will generate 4 sides of content: as it will print "+ 87 "each of 2 sets of transformed images in portrait, \n"+ 88 "and landscape orientations. \n"+ 89 "The sets of images are in turn made up\n"+ 90 "of two similar sets of pages: one is 'random' images,\n "+ 91 " the other is 16 squares.\n"+ 92 "Use the 'Toggle Contents' button to view the screen rendering\n"+ 93 "For each page compare the printed content to the same\n"+ 94 "on-screen one taking careful note of\n"+ 95 "a) the positions of the red/blue circles on the corners\n"+ 96 "b) that numerical text on the image is displayed similarly\n"+ 97 "e) that the green quadrilaterals match on-screen\n"+ 98 "f) that the rendering is clipped at the default (typically 1 inch) "+ 99 "margins of the page.\n"+ 100 "The test PASSES if the onscreen and printed rendering match"); 101 return ta; 102 } 103 104 public void actionPerformed(ActionEvent e) { 105 106 if (e.getActionCommand().equals("Print This")) { 107 printOne(); 108 } else if (e.getActionCommand().equals("Print All")) { 109 printAll(); 110 } else if (e.getActionCommand().equals("Toggle Contents")) { 111 c.toggleContents(); 112 c.repaint(); 113 } 114 } 115 116 private void printOne() { 117 PrinterJob pj = PrinterJob.getPrinterJob(); 118 119 PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet(); 120 if (pj != null && (false||pj.printDialog(attrs))) { 121 c.setPrinterJob(pj, false); 122 pj.setPrintable(c); 123 try { 124 pj.print(attrs); 125 } catch (PrinterException pe) { 126 pe.printStackTrace(); 127 throw new RuntimeException("Exception whilst printing."); 128 } finally { 129 System.out.println("PRINT RETURNED OK."); 130 } 131 } 132 } 133 134 private void printAll() { 135 PrinterJob pj = PrinterJob.getPrinterJob(); 136 PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet(); 137 if (pj != null && (false||pj.printDialog(attrs))) { 138 c.setPrinterJob(pj, true); 139 pj.setPageable(c); 140 try { 141 pj.print(attrs); 142 } catch (PrinterException pe) { 143 pe.printStackTrace(); 144 throw new RuntimeException("Exception whilst printing."); 145 } finally { 146 System.out.println("PRINT RETURNED OK."); 147 } 148 } 149 } 150} 151 152class ClippedImageCanvas extends Component implements Printable, Pageable { 153 154 BufferedImage img = null; 155 int sw=50, sh=50; 156 157 ClippedImageCanvas() { 158 img = new BufferedImage(sw, sh, BufferedImage.TYPE_INT_RGB); 159 Graphics2D g2d = img.createGraphics(); 160 g2d.setColor(Color.red); 161 g2d.fillRect(0 ,0, sw, sh); 162 g2d.setColor(Color.black); 163 int cnt = 0; 164 Font font = new Font("Serif", Font.PLAIN, 11); 165 g2d.setFont(font); 166 FontMetrics fm = g2d.getFontMetrics(); 167 for (int y=12;y<sh;y+=12) { 168 int x = 0; 169 while (x < sw) { 170 String s = (new Integer(++cnt)).toString(); 171 g2d.drawString(s, x, y); 172 x+= fm.stringWidth(s); 173 } 174 } 175 } 176 177 private boolean paintSquares = true; 178 void toggleContents() { 179 paintSquares = !paintSquares; 180 } 181 182 public int getNumberOfPages() { 183 if (pageable) { 184 return 4; 185 } else { 186 return 1; 187 } 188 } 189 190 boolean pageable = false; 191 PrinterJob myPrinterJob; 192 void setPrinterJob(PrinterJob job, boolean pageable) { 193 this.myPrinterJob = job; 194 this.pageable = pageable; 195 } 196 197 public PageFormat getPageFormat(int pageIndex) 198 throws IndexOutOfBoundsException { 199 200 if (pageIndex < 0 || pageIndex >= getNumberOfPages()) { 201 throw new IndexOutOfBoundsException(); 202 } 203 204 PageFormat pf = myPrinterJob.defaultPage(); 205 switch (pageIndex % 2) { 206 207 case 0 : 208 pf.setOrientation(PageFormat.PORTRAIT); 209 break; 210 211 case 1: 212 pf.setOrientation(PageFormat.LANDSCAPE); 213 break; 214 } 215 return pf; 216 } 217 218 String getOrientStr(PageFormat pf) { 219 if (pf.getOrientation() == PageFormat.PORTRAIT) { 220 return "Portrait Orientation, "; 221 } else { 222 return "Landscape Orientation,"; 223 } 224 } 225 226 public Printable getPrintable(int pageIndex) 227 throws IndexOutOfBoundsException { 228 229 if (pageIndex < 0 || pageIndex >= getNumberOfPages()) { 230 throw new IndexOutOfBoundsException(); 231 } 232 if (pageIndex < 2) { 233 paintSquares = true; 234 } else { 235 paintSquares = false; 236 } 237 return this; 238 } 239 240 public int print(Graphics g, PageFormat pgFmt, int pgIndex) { 241 242 if (pgIndex > getNumberOfPages()-1) { 243 return Printable.NO_SUCH_PAGE; 244 } 245 Graphics2D g2d = (Graphics2D)g; 246 g2d.translate(pgFmt.getImageableX(), pgFmt.getImageableY()); 247 g.drawString(getOrientStr(pgFmt), 0, 12); 248 paint(g2d); 249 return Printable.PAGE_EXISTS; 250 } 251 252 private void drawImage(Graphics g, 253 int dx1, int dy1, int dx2, int dy2, 254 int sx1, int sy1, int sx2, int sy2) { 255 256 int rx = (dx1 < dx2) ? dx1 : dx2; 257 int ry = (dy1 < dy2) ? dy1 : dy2; 258 int rw = dx2-dx1; 259 if (rw < 0) rw = -rw; 260 int rh = dy2-dy1; 261 if (rh < 0) rh = -rh; 262 263 g.setColor(Color.green); 264 g.drawRect(rx-1 ,ry-1, rw+1, rh+1); 265 g.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null); 266 g.setColor(Color.blue); 267 int r=5; 268 g.drawOval(dx1-r, dy1-r, 2*r, 2*r); 269 g.setColor(Color.red); 270 g.drawOval(dx2-r, dy2-r, 2*r, 2*r); 271 } 272 273 private AffineTransform savedTx = null; 274 275 private void saveTx(Graphics2D g2d) { 276 savedTx = g2d.getTransform(); 277 } 278 279 private void restoreTx(Graphics2D g2d) { 280 g2d.setTransform(savedTx); 281 } 282 283 public void paint(Graphics g) { 284 Dimension size = getSize(); 285 g.setColor(Color.black); 286 for (int p=0;p<size.width;p+=20) { 287 g.drawLine(p, 0, p, size.height); 288 } 289 for (int p=0;p<size.height;p+=20) { 290 g.drawLine(0, p, size.width, p); 291 } 292 if (paintSquares) { 293 paintSquares(g); 294 } else { 295 paintRandom(g); 296 } 297 } 298 299 private void paintRandom(Graphics g) { 300 301 int dx, dy, dw, dh; 302 303 Graphics2D g2d = (Graphics2D)g; 304 g.setColor(Color.black); 305 306 saveTx(g2d); 307 int sx = -20, sy=-20; 308 309 dx=300; dy=10; dw=50; dh=50; 310 311 drawImage(g, dx, dy, dx+dw, dy+dh ,sx,sy,1,1); 312 313 dx=20; dy=20; dw=400; dh=80; 314 g2d.shear(0.0, Math.PI/20); 315 drawImage(g, dx, dy, dx+dw, dy+dh, sx, sy, dw/2, dh/2); 316 317 dx=125; dy=40; 318 restoreTx(g2d); 319 320 g2d.rotate(Math.PI/4); 321 drawImage(g, dx, dy, dx+dw, dy+dh, sx, sy, dw/2, dh/2); 322 323 restoreTx(g2d); 324 325 dx=290; dy=180; dw=20; dh=20; 326 drawImage(g, dx, dy, dx+dw*10, dy+dh*10, 30, sy, dw, dh); 327 g2d.scale(-1, -1); 328 dx=-280; dy=-200; 329 drawImage(g, dx, dy, dx+dw*2, dy+dh*2, 30, sy, dw, dh); 330 331 restoreTx(g2d); 332 333 g2d.scale(1, -1); 334 dx=430; dy=-150; 335 drawImage(g, dx, dy, dx+dw*5, dy+dh*2, 30, sy, dw, dh); 336 337 restoreTx(g2d); 338 339 dx = 10; dy = 290; dw = 200; dh = 200; 340 drawImage(g, dx, dy, dx+dw, dy+dh, sx, sy, sw, sh); 341 342 dx = 0; dy = 400; dw=-30; dh=-50; 343 drawImage(g, dx, dy, dx-dw, dy-dh, dx, dy, dx-dw, dy-dh); 344 } 345 346 private void paintSquares(Graphics g) { 347 348 /* drawImage is required to handle mapping sx1,sy1 -> dx1,dy1 and 349 * sx2,sy2 -> dx2,dy2 which may imply flips and scales. 350 * To test this we need to test all combinations of these parameters 351 * with drawImage. 352 * If we have a source rectangle with vertices, sA, sB, sC, sD 353 * there are 4 combinations : sA+sD, sD+sA, sB+sC, sC+sB. 354 * Similarly for the destination with vertices, dA, dB, dC, dD 355 * there are 4 combinations : dA+dD, dD+dA, dB+dC, dC+dB. 356 * Thus we need 16 calls to test all combinations. 357 * Note that we set the source area coordinates (x and y -20->80) 358 * to be beyond the image size (50x50) so clipping is always needed. 359 */ 360 int sxa = -20, sya = -20; 361 int sxb = 80, syb = -20; 362 int sxc = -20, syc = 80; 363 int sxd = 80, syd = 80; 364 365 int dxa = 0, dya = 0; 366 int dxb = 80, dyb = 0; 367 int dxc = 0, dyc = 80; 368 int dxd = 80, dyd = 80; 369 370 int incX = 100; 371 int incY = 100; 372 373 g.translate(20, 20); 374 375 /* sA + sD -> dA + dD - the normal untransformed case */ 376 drawImage(g, dxa, dya, dxd, dyd, sxa, sya, sxd, syd); 377 g.translate(incX, 0); 378 379 /* sD + sA -> dA + dD */ 380 drawImage(g, dxa, dya, dxd, dyd, sxd, syd, sxa, sya); 381 g.translate(incX, 0); 382 383 /* sB + sC -> dA + dD */ 384 drawImage(g, dxa, dya, dxd, dyd, sxb, syb, sxc, syc); 385 g.translate(incX, 0); 386 387 /* sC + sB -> dA + dD */ 388 drawImage(g, dxa, dya, dxd, dyd, sxc, syc, sxb, syb); 389 390 g.translate(-3*incX, incY); 391 /******/ 392 393 /* sA + sD -> dD + dA */ 394 drawImage(g, dxd, dyd, dxa, dya, sxa, sya, sxd, syd); 395 g.translate(incX, 0); 396 397 /* sD + sA -> dD + dA */ 398 drawImage(g, dxd, dyd, dxa, dya, sxd, syd, sxa, sya); 399 g.translate(incX, 0); 400 401 /* sB + sC -> dD + dA */ 402 drawImage(g, dxd, dyd, dxa, dya, sxb, syb, sxc, syc); 403 g.translate(incX, 0); 404 405 /* sC + sB -> dD + dA */ 406 drawImage(g, dxd, dyd, dxa, dya, sxc, syc, sxb, syb); 407 408 g.translate(-3*incX, incY); 409 /******/ 410 411 /* sA + sD -> dB + dC */ 412 drawImage(g, dxb, dyb, dxc, dyc, sxa, sya, sxd, syd); 413 g.translate(incX, 0); 414 415 /* sD + sA -> dB + dC */ 416 drawImage(g, dxb, dyb, dxc, dyc, sxd, syd, sxa, sya); 417 g.translate(incX, 0); 418 419 /* sB + sC -> dB + dC */ 420 drawImage(g, dxb, dyb, dxc, dyc, sxb, syb, sxc, syc); 421 g.translate(incX, 0); 422 423 /* sC + sB -> dB + dC */ 424 drawImage(g, dxb, dyb, dxc, dyc, sxc, syc, sxb, syb); 425 426 g.translate(-3*incX, incY); 427 /******/ 428 429 430 /* sA + sD -> dC + dB */ 431 drawImage(g, dxc, dyc, dxb, dyb, sxa, sya, sxd, syd); 432 g.translate(incX, 0); 433 434 /* sD + sA -> dC + dB */ 435 drawImage(g, dxc, dyc, dxb, dyb, sxd, syd, sxa, sya); 436 g.translate(incX, 0); 437 438 /* sB + sC -> dC + dB */ 439 drawImage(g, dxc, dyc, dxb, dyb, sxb, syb, sxc, syc); 440 g.translate(incX, 0); 441 442 /* sC + sB -> dC + dB */ 443 drawImage(g, dxc, dyc, dxb, dyb, sxc, syc, sxb, syb); 444 } 445 446 447 448 /* Size is chosen to match default imageable width of a NA letter 449 * page. This means there will be clipping, what is clipped will 450 * depend on PageFormat orientation. 451 */ 452 public Dimension getPreferredSize() { 453 return new Dimension(468, 468); 454 } 455 456} 457