001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.image.renderer; 031 032import java.awt.geom.CubicCurve2D; 033import java.awt.geom.QuadCurve2D; 034import java.text.AttributedString; 035import java.util.ArrayList; 036import java.util.Arrays; 037import java.util.List; 038 039import org.openimaj.image.Image; 040import org.openimaj.image.pixel.ConnectedComponent; 041import org.openimaj.image.pixel.Pixel; 042import org.openimaj.image.processor.connectedcomponent.render.BlobRenderer; 043import org.openimaj.image.renderer.ScanRasteriser.ScanLineListener; 044import org.openimaj.image.typography.Font; 045import org.openimaj.image.typography.FontRenderer; 046import org.openimaj.image.typography.FontStyle; 047import org.openimaj.math.geometry.line.Line2d; 048import org.openimaj.math.geometry.point.Point2d; 049import org.openimaj.math.geometry.point.Point2dImpl; 050import org.openimaj.math.geometry.shape.Polygon; 051import org.openimaj.math.geometry.shape.Shape; 052 053import com.caffeineowl.graphics.bezier.BezierUtils; 054import com.caffeineowl.graphics.bezier.CubicSegmentConsumer; 055import com.caffeineowl.graphics.bezier.QuadSegmentConsumer; 056import com.caffeineowl.graphics.bezier.flatnessalgos.SimpleConvexHullSubdivCriterion; 057 058/** 059 * ImageRenderer is the abstract base class for all renderers capable of drawing 060 * to images. 061 * 062 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 063 * 064 * @param <Q> 065 * Pixel type 066 * @param <I> 067 * Image type 068 */ 069public abstract class ImageRenderer<Q, I extends Image<Q, I>> { 070 protected RenderHints hints; 071 protected I targetImage; 072 073 /** 074 * Construct with given target image. 075 * 076 * @param targetImage 077 * the target image. 078 */ 079 public ImageRenderer(final I targetImage) { 080 this(targetImage, new RenderHints()); 081 } 082 083 /** 084 * Construct with given target image and rendering hints. 085 * 086 * @param targetImage 087 * the target image. 088 * @param hints 089 * the render hints 090 */ 091 public ImageRenderer(final I targetImage, final RenderHints hints) { 092 this.targetImage = targetImage; 093 this.hints = hints; 094 } 095 096 /** 097 * Draw onto this image lines drawn with the given colour between the points 098 * given. No points are drawn. 099 * 100 * @param pts 101 * The point list to draw onto this image. 102 * @param col 103 * The colour to draw the lines 104 */ 105 public void drawConnectedPoints(final List<? extends Point2d> pts, final Q col) { 106 Point2d p0 = pts.get(0); 107 for (int i = 1; i < pts.size(); i++) { 108 final Point2d p1 = pts.get(i); 109 110 final int x0 = Math.round(p0.getX()); 111 final int y0 = Math.round(p0.getY()); 112 final int x1 = Math.round(p1.getX()); 113 final int y1 = Math.round(p1.getY()); 114 115 this.drawLine(x0, y0, x1, y1, col); 116 117 p0 = p1; 118 } 119 } 120 121 /** 122 * Draw into this image the provided image at the given coordinates. Parts 123 * of the image outside the bounds of this image will be ignored. 124 * 125 * @param image 126 * The image to draw. 127 * @param x 128 * The x-coordinate of the top-left of the image 129 * @param y 130 * The y-coordinate of the top-left of the image 131 */ 132 public void drawImage(final I image, final int x, final int y) { 133 final int stopx = Math.min(this.targetImage.getWidth(), x + image.getWidth()); 134 final int stopy = Math.min(this.targetImage.getHeight(), y + image.getHeight()); 135 final int startx = Math.max(0, x); 136 final int starty = Math.max(0, y); 137 138 for (int yy = starty; yy < stopy; yy++) 139 for (int xx = startx; xx < stopx; xx++) 140 this.targetImage.setPixel(xx, yy, image.getPixel(xx - x, yy - y)); 141 } 142 143 /** 144 * Draw into this image the provided image at the given coordinates ignoring 145 * certain pixels. Parts of the image outside the bounds of this image will 146 * be ignored. Pixels in the ignore list will be stripped from the image to 147 * draw. 148 * 149 * @param image 150 * The image to draw. 151 * @param x 152 * The x-coordinate of the top-left of the image 153 * @param y 154 * The y-coordinate of the top-left of the image 155 * @param ignoreList 156 * The list of pixels to ignore when copying the image 157 */ 158 public void drawImage(final I image, final int x, final int y, final Q... ignoreList) { 159 final int stopx = Math.min(this.targetImage.getWidth(), x + image.getWidth()); 160 final int stopy = Math.min(this.targetImage.getHeight(), y + image.getHeight()); 161 final int startx = Math.max(0, x); 162 final int starty = Math.max(0, y); 163 164 for (int yy = starty; yy < stopy; yy++) 165 for (int xx = startx; xx < stopx; xx++) { 166 final Q val = image.getPixel(xx - x, yy - y); 167 if (Arrays.binarySearch(ignoreList, val, this.targetImage.getPixelComparator()) < 0) 168 this.targetImage.setPixel(xx, yy, val); 169 } 170 171 } 172 173 /** 174 * Draw a line from the coordinates specified by <code>(x1,y1)</code> at an 175 * angle of <code>theta</code> with the given length, thickness and colour. 176 * 177 * @param x1 178 * The x-coordinate to start the line. 179 * @param y1 180 * The y-coordinate to start the line. 181 * @param theta 182 * The angle at which to draw the line. 183 * @param length 184 * The length to draw the line. 185 * @param thickness 186 * The thickness to draw the line. 187 * @param col 188 * The colour to draw the line. 189 */ 190 public abstract void drawLine(int x1, int y1, double theta, int length, int thickness, Q col); 191 192 /** 193 * Draw a line from the coordinates specified by <code>(x1,y1)</code> at an 194 * angle of <code>theta</code> with the given length and colour. 195 * Line-thickness will be 1. 196 * 197 * @param x1 198 * The x-coordinate to start the line. 199 * @param y1 200 * The y-coordinate to start the line. 201 * @param theta 202 * The angle at which to draw the line. 203 * @param length 204 * The length to draw the line. 205 * @param col 206 * The colour to draw the line. 207 */ 208 public void drawLine(final int x1, final int y1, final double theta, final int length, final Q col) { 209 this.drawLine(x1, y1, theta, length, 1, col); 210 } 211 212 /** 213 * Draw a line from the coordinates specified by <code>(x0,y0)</code> to the 214 * coordinates specified by <code>(x1,y1)</code> using the given color and 215 * thickness. 216 * 217 * @param x0 218 * The x-coordinate at the start of the line. 219 * @param y0 220 * The y-coordinate at the start of the line. 221 * @param x1 222 * The x-coordinate at the end of the line. 223 * @param y1 224 * The y-coordinate at the end of the line. 225 * @param thickness 226 * The thickness which to draw the line. 227 * @param col 228 * The colour in which to draw the line. 229 */ 230 public abstract void drawLine(int x0, int y0, int x1, int y1, int thickness, Q col); 231 232 /** 233 * Draw a line from the coordinates specified by <code>(x0,y0)</code> to the 234 * coordinates specified by <code>(x1,y1)</code> using the given color and 235 * thickness. 236 * 237 * @param x0 238 * The x-coordinate at the start of the line. 239 * @param y0 240 * The y-coordinate at the start of the line. 241 * @param x1 242 * The x-coordinate at the end of the line. 243 * @param y1 244 * The y-coordinate at the end of the line. 245 * @param thickness 246 * The thickness which to draw the line. 247 * @param col 248 * The colour in which to draw the line. 249 */ 250 public abstract void drawLine(final float x0, final float y0, final float x1, final float y1, final int thickness, 251 final Q col); 252 253 /** 254 * Draw a line from the coordinates specified by <code>(x0,y0)</code> to 255 * <code>(x1,y1)</code> using the given colour. The line thickness will be 1 256 * pixel. 257 * 258 * @param x0 259 * The x-coordinate at the start of the line. 260 * @param y0 261 * The y-coordinate at the start of the line. 262 * @param x1 263 * The x-coordinate at the end of the line. 264 * @param y1 265 * The y-coordinate at the end of the line. 266 * @param col 267 * The colour in which to draw the line. 268 */ 269 public void drawLine(final int x0, final int y0, final int x1, final int y1, final Q col) { 270 this.drawLine(x0, y0, x1, y1, 1, col); 271 } 272 273 /** 274 * Draw a line from the coordinates specified by <code>(x0,y0)</code> to 275 * <code>(x1,y1)</code> using the given colour. The line thickness will be 1 276 * pixel. 277 * 278 * @param p1 279 * The coordinate of the start of the line. 280 * @param p2 281 * The coordinate of the end of the line. 282 * @param col 283 * The colour in which to draw the line. 284 */ 285 public void drawLine(final Point2d p1, final Point2d p2, final Q col) { 286 this.drawLine(Math.round(p1.getX()), Math.round(p1.getY()), 287 Math.round(p2.getX()), Math.round(p2.getY()), 288 1, col); 289 } 290 291 /** 292 * Draw a line from the coordinates specified by <code>(x0,y0)</code> to 293 * <code>(x1,y1)</code> using the given colour and thickness. 294 * 295 * @param p1 296 * The coordinate of the start of the line. 297 * @param p2 298 * The coordinate of the end of the line. 299 * @param thickness 300 * the stroke width 301 * @param col 302 * The colour in which to draw the line. 303 */ 304 public void drawLine(final Point2d p1, final Point2d p2, final int thickness, final Q col) { 305 this.drawLine(Math.round(p1.getX()), Math.round(p1.getY()), 306 Math.round(p2.getX()), Math.round(p2.getY()), 307 thickness, col); 308 } 309 310 /** 311 * Draw a line from the specified Line2d object 312 * 313 * @param line 314 * the line 315 * @param thickness 316 * the stroke width 317 * @param col 318 * The colour in which to draw the line. 319 */ 320 public void drawLine(final Line2d line, final int thickness, final Q col) { 321 this.drawLine((int) line.begin.getX(), (int) line.begin.getY(), (int) line.end.getX(), (int) line.end.getY(), 322 thickness, col); 323 } 324 325 /** 326 * Draw the given list of lines using {@link #drawLine(Line2d, int, Object)} 327 * with the given colour and thickness. 328 * 329 * @param lines 330 * The list of lines to draw. 331 * @param thickness 332 * the stroke width 333 * @param col 334 * The colour to draw each point. 335 */ 336 public void drawLines(final Iterable<? extends Line2d> lines, final int thickness, final Q col) { 337 for (final Line2d line : lines) 338 this.drawLine(line, thickness, col); 339 } 340 341 /** 342 * Draw a dot centered on the given location (rounded to nearest integer 343 * location) at the given size and with the given color. 344 * 345 * 346 * @param p 347 * The coordinates at which to draw the point 348 * @param col 349 * The colour to draw the point 350 * @param size 351 * The size at which to draw the point. 352 */ 353 public abstract void drawPoint(Point2d p, Q col, int size); 354 355 /** 356 * Draw the given list of points using 357 * {@link #drawPoint(Point2d, Object, int)} with the given colour and size. 358 * 359 * @param pts 360 * The list of points to draw. 361 * @param col 362 * The colour to draw each point. 363 * @param size 364 * The size to draw each point. 365 */ 366 public void drawPoints(final Iterable<? extends Point2d> pts, final Q col, final int size) { 367 for (final Point2d p : pts) 368 this.drawPoint(p, col, size); 369 } 370 371 /** 372 * Draw the given polygon in the specified colour with the given thickness 373 * lines. 374 * 375 * 376 * @param p 377 * The polygon to draw. 378 * @param thickness 379 * The thickness of the lines to use 380 * @param col 381 * The colour to draw the lines in 382 */ 383 public abstract void drawPolygon(Polygon p, int thickness, Q col); 384 385 /** 386 * Draw the given polygon in the specified colour. Uses 387 * {@link #drawPolygon(Polygon, int, Object)} with line thickness 1. 388 * 389 * 390 * @param p 391 * The polygon to draw. 392 * @param col 393 * The colour to draw the polygon in. 394 */ 395 public void drawPolygon(final Polygon p, final Q col) { 396 this.drawPolygon(p, 1, col); 397 } 398 399 /** 400 * Draw a horizontal line with the specified colour. 401 * 402 * @param x1 403 * starting x (inclusive) 404 * @param x2 405 * ending x (inclusive) 406 * @param y 407 * y 408 * @param col 409 * the colour 410 */ 411 protected abstract void drawHorizLine(int x1, int x2, int y, Q col); 412 413 /** 414 * Draw the given polygon, filled with the specified colour. 415 * 416 * @param p 417 * The polygon to draw. 418 * @param col 419 * The colour to fill the polygon with. 420 */ 421 public void drawPolygonFilled(final Polygon p, final Q col) { 422 this.drawPolygon(p, col); 423 424 if (p.getNumInnerPoly() == 1) { 425 ScanRasteriser.scanFill(p.points, new ScanLineListener() { 426 @Override 427 public void process(final int x1, final int x2, final int y) { 428 ImageRenderer.this.drawHorizLine(x1, x2, y, col); 429 } 430 }); 431 } else { 432 final ConnectedComponent cc = new ConnectedComponent(p); 433 cc.process(new BlobRenderer<Q>(this.targetImage, col)); 434 } 435 } 436 437 /** 438 * Draw the given shape in the specified colour with the given thickness 439 * lines. 440 * 441 * @param s 442 * The shape to draw. 443 * @param thickness 444 * The thickness of the lines to use 445 * @param col 446 * The colour to draw the lines in 447 */ 448 public void drawShape(final Shape s, final int thickness, final Q col) { 449 this.drawPolygon(s.asPolygon(), thickness, col); 450 } 451 452 /** 453 * Draw the given shape in the specified colour. Uses 454 * {@link #drawPolygon(Polygon, int, Object)} with line thickness 1. 455 * 456 * @param p 457 * The shape to draw. 458 * @param col 459 * The colour to draw the polygon in. 460 */ 461 public void drawShape(final Shape p, final Q col) { 462 this.drawShape(p, 1, col); 463 } 464 465 /** 466 * Draw the given shape, filled with the specified colour. 467 * 468 * @param s 469 * The shape to draw. 470 * @param col 471 * The colour to fill the polygon with. 472 */ 473 public void drawShapeFilled(final Shape s, Q col) { 474 col = this.sanitise(col); 475 if (s instanceof Polygon) { 476 this.drawPolygonFilled((Polygon) s, col); 477 } else { 478 this.drawShape(s, col); 479 480 final int minx = (int) Math.max(0, Math.round(s.minX())); 481 final int maxx = (int) Math.min(this.targetImage.getWidth(), Math.round(s.maxX())); 482 final int miny = (int) Math.max(0, Math.round(s.minY())); 483 final int maxy = (int) Math.min(this.targetImage.getHeight(), Math.round(s.maxY())); 484 485 for (int y = miny; y <= maxy; y++) { 486 for (int x = minx; x <= maxx; x++) { 487 final Pixel p = new Pixel(x, y); 488 if (s.isInside(p)) 489 this.targetImage.setPixel(p.x, p.y, col); 490 } 491 } 492 } 493 } 494 495 /** 496 * Render the text in the given font with the default style. 497 * 498 * @param <F> 499 * the font 500 * @param text 501 * the text 502 * @param x 503 * the x-ordinate 504 * @param y 505 * the y-ordinate 506 * @param f 507 * the font 508 * @param sz 509 * the size 510 */ 511 public <F extends Font<F>> void drawText(final String text, final int x, final int y, final F f, final int sz) { 512 final FontStyle<Q> sty = f.createStyle(this); 513 sty.setFontSize(sz); 514 f.getRenderer(this).renderText(this, text, x, y, sty); 515 } 516 517 /** 518 * Render the text in the given font in the given colour with the default 519 * style. 520 * 521 * @param <F> 522 * the font 523 * @param text 524 * the text 525 * @param x 526 * the x-ordinate 527 * @param y 528 * the y-ordinate 529 * @param f 530 * the font 531 * @param sz 532 * the size 533 * @param col 534 * the font color 535 */ 536 public <F extends Font<F>> void drawText(final String text, final int x, final int y, final F f, final int sz, 537 final Q col) 538 { 539 final FontStyle<Q> sty = f.createStyle(this); 540 sty.setFontSize(sz); 541 sty.setColour(col); 542 f.getRenderer(this).renderText(this, text, x, y, sty); 543 } 544 545 /** 546 * Render the text in the given font with the default style. 547 * 548 * @param <F> 549 * the font 550 * @param text 551 * the text 552 * @param pt 553 * the coordinate to render at 554 * @param f 555 * the font 556 * @param sz 557 * the size 558 */ 559 public <F extends Font<F>> void drawText(final String text, final Point2d pt, final F f, final int sz) { 560 final FontStyle<Q> sty = f.createStyle(this); 561 sty.setFontSize(sz); 562 f.getRenderer(this).renderText(this, text, (int) pt.getX(), (int) pt.getY(), sty); 563 } 564 565 /** 566 * Render the text in the given font in the given colour with the default 567 * style. 568 * 569 * @param <F> 570 * the font 571 * @param text 572 * the text 573 * @param pt 574 * the coordinate to render at 575 * @param f 576 * the font 577 * @param sz 578 * the size 579 * @param col 580 * the font colour 581 */ 582 public <F extends Font<F>> void drawText(final String text, final Point2d pt, final F f, final int sz, final Q col) { 583 final FontStyle<Q> sty = f.createStyle(this); 584 sty.setFontSize(sz); 585 sty.setColour(col); 586 f.getRenderer(this).renderText(this, text, (int) pt.getX(), (int) pt.getY(), sty); 587 } 588 589 /** 590 * Render the text with the given {@link FontStyle}. 591 * 592 * @param text 593 * the text 594 * @param x 595 * the x-ordinate 596 * @param y 597 * the y-ordinate 598 * @param f 599 * the font style 600 */ 601 public void drawText(final String text, final int x, final int y, final FontStyle<Q> f) { 602 f.getRenderer(this).renderText(this, text, x, y, f); 603 } 604 605 /** 606 * Render the text with the given {@link FontStyle}. 607 * 608 * @param text 609 * the text 610 * @param pt 611 * the coordinate to render at 612 * @param f 613 * the font style 614 */ 615 public void drawText(final String text, final Point2d pt, final FontStyle<Q> f) { 616 f.getRenderer(this).renderText(this, text, (int) pt.getX(), (int) pt.getY(), f); 617 } 618 619 /** 620 * Render the text using its attributes. 621 * 622 * @param text 623 * the text 624 * @param x 625 * the x-ordinate 626 * @param y 627 * the y-ordinate 628 */ 629 public void drawText(final AttributedString text, final int x, final int y) { 630 FontRenderer.renderText(this, text, x, y); 631 } 632 633 /** 634 * Render the text using its attributes. 635 * 636 * @param text 637 * the text 638 * @param pt 639 * the coordinate to render at 640 */ 641 public void drawText(final AttributedString text, final Point2d pt) { 642 FontRenderer.renderText(this, text, (int) pt.getX(), (int) pt.getY()); 643 } 644 645 /** 646 * Draw a cubic Bezier curve into the image with 100 point accuracy. 647 * 648 * @param p1 649 * One end point of the line 650 * @param p2 651 * The other end point of the line 652 * @param c1 653 * The control point associated with p1 654 * @param c2 655 * The control point associated with p2 656 * @param thickness 657 * The thickness to draw the line 658 * @param col 659 * The colour to draw the line 660 * @return The points along the bezier curve 661 */ 662 public Point2d[] drawCubicBezier(final Point2d p1, final Point2d p2, 663 final Point2d c1, final Point2d c2, final int thickness, final Q col) 664 { 665 final List<Point2d> points = new ArrayList<Point2d>(); 666 667 final CubicCurve2D c = new CubicCurve2D.Double( 668 p1.getX(), p1.getY(), c1.getX(), c1.getY(), 669 c2.getX(), c2.getY(), p2.getX(), p2.getY()); 670 BezierUtils.adaptiveHalving(c, new SimpleConvexHullSubdivCriterion(), 671 new CubicSegmentConsumer() 672 { 673 @Override 674 public void processSegment(final CubicCurve2D segment, 675 final double startT, final double endT) 676 { 677 if (0.0 == startT) 678 points.add(new Point2dImpl( 679 (float) segment.getX1(), (float) segment.getY1())); 680 681 points.add(new Point2dImpl( 682 (float) segment.getX2(), (float) segment.getY2())); 683 } 684 } 685 ); 686 687 Point2d last = null; 688 for (final Point2d p : points) { 689 if (last != null) 690 this.drawLine((int) last.getX(), (int) last.getY(), 691 (int) p.getX(), (int) p.getY(), thickness, col); 692 last = p; 693 } 694 695 return points.toArray(new Point2d[1]); 696 } 697 698 /** 699 * Draw a Quadratic Bezier curve 700 * 701 * @param p1 702 * @param p2 703 * @param c1 704 * @param thickness 705 * @param colour 706 * @return a set of points on the curve 707 */ 708 public Point2d[] drawQuadBezier(final Point2d p1, final Point2d p2, final Point2d c1, 709 final int thickness, final Q colour) 710 { 711 final List<Point2d> points = new ArrayList<Point2d>(); 712 713 final QuadCurve2D c = new QuadCurve2D.Double( 714 p1.getX(), p1.getY(), c1.getX(), c1.getY(), p2.getX(), p2.getY()); 715 BezierUtils.adaptiveHalving(c, new SimpleConvexHullSubdivCriterion(), 716 new QuadSegmentConsumer() 717 { 718 @Override 719 public void processSegment(final QuadCurve2D segment, final double startT, final double endT) 720 { 721 if (0.0 == startT) 722 points.add(new Point2dImpl( 723 (float) segment.getX1(), (float) segment.getY1())); 724 725 points.add(new Point2dImpl( 726 (float) segment.getX2(), (float) segment.getY2())); 727 } 728 } 729 ); 730 731 Point2d last = null; 732 for (final Point2d p : points) { 733 if (last != null) 734 this.drawLine((int) last.getX(), (int) last.getY(), 735 (int) p.getX(), (int) p.getY(), thickness, colour); 736 last = p; 737 } 738 739 return points.toArray(new Point2d[1]); 740 741 } 742 743 /** 744 * Get the default foreground colour. 745 * 746 * @return the default foreground colour. 747 */ 748 public abstract Q defaultForegroundColour(); 749 750 /** 751 * Get the default foreground colour. 752 * 753 * @return the default foreground colour. 754 */ 755 public abstract Q defaultBackgroundColour(); 756 757 /** 758 * Get the target image 759 * 760 * @return the image 761 */ 762 public I getImage() { 763 return this.targetImage; 764 } 765 766 /** 767 * Change the target image of this renderer. 768 * 769 * @param image 770 * new target 771 */ 772 public void setImage(final I image) { 773 this.targetImage = image; 774 } 775 776 /** 777 * Get the render hints object associated with this renderer 778 * 779 * @return the render hints 780 */ 781 public RenderHints getRenderHints() { 782 return this.hints; 783 } 784 785 /** 786 * Set the render hints associated with this renderer 787 * 788 * @param hints 789 * the new hints 790 */ 791 public void setRenderHints(final RenderHints hints) { 792 this.hints = hints; 793 } 794 795 /** 796 * Sanitize the colour given to fit this image's pixel type. 797 * 798 * @param size 799 * The colour to sanitize 800 * @return The array 801 */ 802 protected abstract Q sanitise(Q colour); 803}