/* * ImageI/O-Ext - OpenSource Java Image translation Library * http://www.geo-solutions.it/ * http://java.net/projects/imageio-ext/ * (C) 2007 - 2011, GeoSolutions * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * either version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package it.geosolutions.imageio.utilities; import java.awt.Point; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.media.jai.JAI; import javax.media.jai.PlanarImage; import javax.media.jai.TileScheduler; /** * @author Daniele Romagnoli, GeoSolutions SaS */ public class TilesByteGetter { byte[] bb; RenderedImage ri; int tileWidth; int tileHeight; int width; int height; final static boolean usePrefetching; static int multithreadingLevel; static { String mt = System.getProperty("it.geosolutions.tilesgetter.multithreading"); if (mt != null) { try { multithreadingLevel = Integer.parseInt(mt); } catch (NumberFormatException nfe){ System.out.println("Error parsing " + mt + " as integer; using default 1"); multithreadingLevel = 1; } } else { multithreadingLevel = 1; } usePrefetching = Boolean.getBoolean("it.geosolutions.tilesgetter.usePrefetching"); System.out.println("Multithreading level: " + multithreadingLevel + " prefetching: " + usePrefetching); } public TilesByteGetter(RenderedImage ri){ this.ri = ri; tileWidth = ri.getTileWidth(); tileHeight = ri.getTileHeight(); width = ri.getWidth(); height = ri.getHeight(); } private class ByteGetter implements Callable<Integer> { RenderedImage ri; int tileX; int tileY; public ByteGetter(RenderedImage ri, final int tileX, final int tileY) { this.ri = ri; this.tileX = tileX; this.tileY = tileY; } public Integer call() { try { Raster tile = ri.getTile(tileX, tileY); final int nBands = ri.getSampleModel().getNumBands(); DataBufferByte dbb = (DataBufferByte) tile.getDataBuffer(); byte[] bytes = dbb.getData(); final int h; final int w; if ((tileWidth * (tileX + 1) > width)) { w = width - (tileX * tileWidth); } else { w = tileWidth; } if ((tileHeight * (tileY + 1) > height)) { h = height - (tileY * tileHeight); } else { h = tileHeight; } final int localStripeLength = w * nBands; final int stripeLength = tileWidth * nBands; int tileSkipX = stripeLength * tileX; int offset; for (int j=0; j < h; j++) { offset = (((j + tileHeight * tileY) * width * nBands) + tileSkipX); System.arraycopy(bytes, stripeLength * j, bb, offset, localStripeLength); } } catch (Exception e){ } return 1; } } public byte[] getBytes() throws InterruptedException{ if (ri instanceof BufferedImage){ Raster wr = ri.getTile(0, 0); return ((DataBufferByte) wr.getDataBuffer()).getData(); } else { final int nX = ri.getNumXTiles(); final int nY = ri.getNumYTiles(); if (nX == 1 && nY == 1) { Raster wr = ri.getTile(0, 0); return ((DataBufferByte) wr.getDataBuffer()).getData(); } else { final int size = ri.getHeight() * ri.getWidth() * ri.getSampleModel().getNumBands(); bb = new byte[size]; if (multithreadingLevel != 1) { final int minTx = ri.getMinTileX(); final int minTy = ri.getMinTileY(); int TH = multithreadingLevel; final TileScheduler ts = JAI.getDefaultInstance().getTileScheduler(); final List<Point> tiles = new ArrayList<Point>(); final LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(); final List<Callable<Integer>> queueX = new ArrayList<Callable<Integer>>(); final ThreadPoolExecutor ex = new ThreadPoolExecutor(TH, TH, 10000L, TimeUnit.SECONDS, queue); ex.prestartAllCoreThreads(); int tx = 0; int ty = 0; for (int j = 0; j < nY; j++) { for (int i = 0; i < nX; i++) { tx = minTx + i; ty = minTy + j; tiles.add(new Point( tx, ty)); queueX.add(new ByteGetter(ri, tx, ty)); } } Point[] tilesArray = (Point[]) tiles.toArray(new Point[tiles.size()]); ts.prefetchTiles(PlanarImage.wrapRenderedImage(ri), tilesArray); ex.invokeAll(queueX); ex.shutdown(); } else { if (usePrefetching){ final int minTx = ri.getMinTileX(); final int minTy = ri.getMinTileY(); TileScheduler ts = JAI.getDefaultInstance().getTileScheduler(); List<Point> tiles = new ArrayList<Point>(); int tx = 0; int ty = 0; for (int j = 0; j < nY; j++) { for (int i = 0; i < nX; i++) { tx = minTx + i; ty = minTy + j; tiles.add(new Point( tx, ty)); } } Point[] tilesArray = (Point[]) tiles.toArray(new Point[tiles.size()]); ts.prefetchTiles(PlanarImage.wrapRenderedImage(ri), tilesArray); } bb = ((DataBufferByte)ri.getData().getDataBuffer()).getData(); } return bb; } } } }