/** * Paint the image onto a Graphics object. The painting is performed tile-by-tile, and includes a * grey region covering the unused portion of image tiles as well as the general background. At * this point the image must be byte data. */ public synchronized void paintComponent(Graphics g) { Graphics2D g2D = null; if (g instanceof Graphics2D) { g2D = (Graphics2D) g; } else { return; } // if source is null, it's just a component if (source == null) { g2D.setColor(getBackground()); g2D.fillRect(0, 0, componentWidth, componentHeight); return; } int transX = -originX; int transY = -originY; // Get the clipping rectangle and translate it into image coordinates. Rectangle clipBounds = g.getClipBounds(); if (clipBounds == null) { clipBounds = new Rectangle(0, 0, componentWidth, componentHeight); } // clear the background (clip it) [minimal optimization here] if (transX > 0 || transY > 0 || transX < (componentWidth - source.getWidth()) || transY < (componentHeight - source.getHeight())) { g2D.setColor(getBackground()); g2D.fillRect(0, 0, componentWidth, componentHeight); } clipBounds.translate(-transX, -transY); // Determine the extent of the clipping region in tile coordinates. int txmin, txmax, tymin, tymax; int ti, tj; txmin = XtoTileX(clipBounds.x); txmin = Math.max(txmin, minTileX); txmin = Math.min(txmin, maxTileX); txmax = XtoTileX(clipBounds.x + clipBounds.width - 1); txmax = Math.max(txmax, minTileX); txmax = Math.min(txmax, maxTileX); tymin = YtoTileY(clipBounds.y); tymin = Math.max(tymin, minTileY); tymin = Math.min(tymin, maxTileY); tymax = YtoTileY(clipBounds.y + clipBounds.height - 1); tymax = Math.max(tymax, minTileY); tymax = Math.min(tymax, maxTileY); Insets insets = getInsets(); // Loop over tiles within the clipping region for (tj = tymin; tj <= tymax; tj++) { for (ti = txmin; ti <= txmax; ti++) { int tx = TileXtoX(ti); int ty = TileYtoY(tj); Raster tile = source.getTile(ti, tj); if (tile != null) { DataBuffer dataBuffer = tile.getDataBuffer(); WritableRaster wr = tile.createWritableRaster(sampleModel, dataBuffer, null); BufferedImage bi = new BufferedImage(colorModel, wr, colorModel.isAlphaPremultiplied(), null); // correctly handles band offsets if (brightnessEnabled == true) { SampleModel sm = sampleModel.createCompatibleSampleModel(tile.getWidth(), tile.getHeight()); WritableRaster raster = RasterFactory.createWritableRaster(sm, null); BufferedImage bimg = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null); // don't move this code ByteLookupTable lutTable = new ByteLookupTable(0, lutData); LookupOp lookup = new LookupOp(lutTable, null); lookup.filter(bi, bimg); g2D.drawImage(bimg, biop, tx + transX + insets.left, ty + transY + insets.top); } else { AffineTransform transform; transform = AffineTransform.getTranslateInstance( tx + transX + insets.left, ty + transY + insets.top); g2D.drawRenderedImage(bi, transform); } } } } }
/** * Fills in the portions of a given <code>Raster</code> that lie outside the bounds of a given * <code>PlanarImage</code> with suitably reflected copies of the entire image. * * <p>The portion of <code>raster</code> that lies within <code>im.getBounds()</code> is not * altered. * * @param raster The <code>WritableRaster</code> the border area of which is to be filled with * suitably reflected copies of portions of the specified image. * @param im The <code>PlanarImage</code> the data of which is to be reflected and used to fill * the <code>WritableRaster</code> border. * @throws <code>IllegalArgumentException</code> if either parameter is <code>null</code>. */ public final void extend(WritableRaster raster, PlanarImage im) { if (raster == null || im == null) { throw new IllegalArgumentException(JaiI18N.getString("Generic0")); } int width = raster.getWidth(); int height = raster.getHeight(); int minX = raster.getMinX(); int maxX = minX + width; int minY = raster.getMinY(); int maxY = minY + height; int imMinX = im.getMinX(); int imMinY = im.getMinY(); int imWidth = im.getWidth(); int imHeight = im.getHeight(); int validMinX = Math.max(imMinX, minX); int validMaxX = Math.min(imMinX + imWidth, maxX); int validMinY = Math.max(imMinY, minY); int validMaxY = Math.min(imMinY + imHeight, maxY); if (validMinX > validMaxX || validMinY > validMaxY) { // Raster does not intersect image. Determine the location // and size of the smallest rectangle containing the Raster // and which intersects the image. if (validMinX > validMaxX) { // no intersetion in X if (minX == validMinX) { minX = im.getMaxX() - 1; } else { maxX = im.getMinX(); } } if (validMinY > validMaxY) { // no intersetion in Y if (minY == validMinY) { minY = im.getMaxY() - 1; } else { maxY = im.getMinY(); } } // Create minimum Raster. WritableRaster wr = raster.createCompatibleWritableRaster(minX, minY, maxX - minX, maxY - minY); // Extend the data. extend(wr, im); // Create a child with same bounds as the target Raster. Raster child = wr.createChild( raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), raster.getMinX(), raster.getMinY(), null); // Copy the data from the child. JDKWorkarounds.setRect(raster, child, 0, 0); return; } Rectangle rect = new Rectangle(); // Notionally extend the source image by treating it as a single // tile of an infinite tiled image. Adjacent tiles are reflections // of one another. // Compute the min and max X and Y tile indices of the area // intersected by the output raster. int minTileX = PlanarImage.XToTileX(minX, imMinX, imWidth); int maxTileX = PlanarImage.XToTileX(maxX - 1, imMinX, imWidth); int minTileY = PlanarImage.YToTileY(minY, imMinY, imHeight); int maxTileY = PlanarImage.YToTileY(maxY - 1, imMinY, imHeight); // Loop over the tiles for (int tileY = minTileY; tileY <= maxTileY; tileY++) { int ty = tileY * imHeight + imMinY; for (int tileX = minTileX; tileX <= maxTileX; tileX++) { int tx = tileX * imWidth + imMinX; // Don't touch the central "tile" (actual image) if (tileX == 0 && tileY == 0) { continue; } boolean flipX = (Math.abs(tileX) % 2) == 1; boolean flipY = (Math.abs(tileY) % 2) == 1; // Clip the tile bounds against the bounds of the Raster. // Keep track of the (x, y) offset of the start of the tile. rect.x = tx; rect.y = ty; rect.width = imWidth; rect.height = imHeight; int xOffset = 0; if (rect.x < minX) { xOffset = minX - rect.x; rect.x = minX; rect.width -= xOffset; } int yOffset = 0; if (rect.y < minY) { yOffset = minY - rect.y; rect.y = minY; rect.height -= yOffset; } if (rect.x + rect.width > maxX) { rect.width = maxX - rect.x; } if (rect.y + rect.height > maxY) { rect.height = maxY - rect.y; } int imX; if (flipX) { if (xOffset == 0) { imX = imMinX + imWidth - rect.width; } else { imX = imMinX; } } else { imX = imMinX + xOffset; } int imY; if (flipY) { if (yOffset == 0) { imY = imMinY + imHeight - rect.height; } else { imY = imMinY; } } else { imY = imMinY + yOffset; } // Create a child raster with coordinates within the // actual image. WritableRaster child = RasterFactory.createWritableChild( raster, rect.x, rect.y, rect.width, rect.height, imX, imY, null); // Copy the data into the Raster im.copyData(child); if (flipX) { flipX(child); } if (flipY) { flipY(child); } } } }