() {
+ @Override
+ public Entry call() {
+ final String urlString = String.format( urlFormat, s, scale, c * tileWidth, r * tileHeight, z, tileWidth, tileHeight, r, c );
+ final int[] pixels = new int[ tileWidth * tileHeight ];
+ try {
+ System.out.println( "Load s=" + s + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" );
+ final URL url = new URL( urlString );
+ final BufferedImage jpg = ImageIO.read( url );
- final int[] pixels = new int[ tileWidth * tileHeight ];
- try
- {
- final URL url = new URL( urlString );
-// final Image image = toolkit.createImage( url );
- final BufferedImage jpg = ImageIO.read( url );
-
- /* This gymnastic is necessary to get reproducible gray
- * values, just opening a JPG or PNG, even when saved by
- * ImageIO, and grabbing its pixels results in gray values
- * with a non-matching gamma transfer function, I cannot tell
- * why... */
- final BufferedImage image = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB );
- image.createGraphics().drawImage( jpg, 0, 0, null );
- final PixelGrabber pg = new PixelGrabber( image, 0, 0, tileWidth, tileHeight, pixels, 0, tileWidth );
- pg.grabPixels();
-
- cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) );
-// System.out.println( "success loading r=" + r + " c=" + c + " url(" + urlString + ")" );
-
- }
- catch (final IOException e)
- {
- System.out.println( "failed loading r=" + r + " c=" + c + " url(" + urlString + ")" );
- cache.put( key, new SoftReference< Entry >( new Entry( key, pixels ) ) );
- }
- catch (final InterruptedException e)
- {
- e.printStackTrace();
- }
- return pixels;
+ /* This gymnastic is necessary to get reproducible gray
+ * values, just opening a JPG or PNG, even when saved by
+ * ImageIO, and grabbing its pixels results in gray values
+ * with a non-matching gamma transfer function, I cannot tell
+ * why... */
+ final BufferedImage image = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB );
+ image.createGraphics().drawImage( jpg, 0, 0, null );
+ final PixelGrabber pg = new PixelGrabber( image, 0, 0, tileWidth, tileHeight, pixels, 0, tileWidth );
+ pg.grabPixels();
+ System.out.println( "Successfully loaded s=" + s + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" );
+ } catch (final Exception e) {
+ System.out.println( "Failed loading s=" + s + " r=" + r + " c=" + c + " z=" + z + " url(" + urlString + ")" );
+ }
+ return new Entry(pixels);
+ }
+ });
+ } catch (ExecutionException ee) {
+ ee.printStackTrace();
}
+ return tileEntry != null ? tileEntry.data : null;
}
}
diff --git a/src/main/java/org/catmaid/Downsampler.java b/src/main/java/org/catmaid/Downsampler.java
index 49e29f9..3d86360 100644
--- a/src/main/java/org/catmaid/Downsampler.java
+++ b/src/main/java/org/catmaid/Downsampler.java
@@ -98,8 +98,8 @@ final static public void downsampleBytes( final byte[] aPixels, final byte[] bPi
}
}
}
-
- final static public void downsampleRGB( final int[] aPixels, final int[] bPixels, final int wa, final int ha )
+
+ final static public boolean downsampleRGB( final int[] aPixels, final int[] bPixels, final int wa, final int ha, int bgValue )
{
assert aPixels.length == wa * ha && bPixels.length == wa / 2 * ( ha / 2 ) : "Input dimensions do not match.";
@@ -108,15 +108,20 @@ final static public void downsampleRGB( final int[] aPixels, final int[] bPixels
final int wb = wa / 2;
final int hb = ha / 2;
final int nb = hb * wb;
-
+ boolean bresult = false;
for ( int ya = 0, yb = 0; yb < nb; ya += wa2, yb += wb )
{
final int ya1 = ya + wa;
for ( int xa = 0, xb = 0; xb < wb; xa += 2, ++xb )
{
final int xa1 = xa + 1;
- bPixels[ yb + xb ] = averageColor( ya + xa, ya + xa1, ya1 + xa, ya1 + xa1, aPixels );
+ int c = averageColor( ya + xa, ya + xa1, ya1 + xa, ya1 + xa1, aPixels );
+ bPixels[ yb + xb ] = c;
+ if ((c & 0xFFFFFF) != bgValue) {
+ bresult = true; // return true since at least one pixel is non black
+ }
}
}
+ return bresult;
}
}
diff --git a/src/main/java/org/catmaid/ScaleCATMAID.java b/src/main/java/org/catmaid/ScaleCATMAID.java
index 07ee868..aa8d5a3 100644
--- a/src/main/java/org/catmaid/ScaleCATMAID.java
+++ b/src/main/java/org/catmaid/ScaleCATMAID.java
@@ -16,14 +16,11 @@
*/
package org.catmaid;
+import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
-import java.io.File;
-import java.io.IOException;
-
-import javax.imageio.ImageIO;
/**
* A standalone command line application to generate the scale pyramid of an
@@ -68,72 +65,72 @@
*/
public class ScaleCATMAID
{
- static protected class Param
+ static class Param
{
- public int tileWidth;
- public int tileHeight;
- public long minZ;
- public long maxZ;
- public String tileFormat;
- public String format;
- public float quality;
- public int type;
+ int tileWidth;
+ int tileHeight;
+ long minX;
+ long width;
+ long minY;
+ long height;
+ long minZ;
+ long maxZ;
+ String tileFormat;
+ String format;
+ float quality;
+ int type;
+ boolean ignoreEmptyTiles;
+ int bgValue;
}
-
- private ScaleCATMAID(){}
-
- static protected Param parseParameters()
- {
+
+ private ScaleCATMAID() {}
+
+ static protected Param parseParameters() {
final Param p = new Param();
p.tileWidth = Integer.parseInt( System.getProperty( "tileWidth", "256" ) );
p.tileHeight = Integer.parseInt( System.getProperty( "tileHeight", "256" ) );
-
+
+ p.minX = Long.parseLong( System.getProperty( "minX", "0" ) );
+ p.width = Long.parseLong( System.getProperty( "width", "-1") );
+ p.minY = Long.parseLong( System.getProperty( "minY", "0" ) );
+ p.height = Long.parseLong( System.getProperty( "height", "-1" ) );
p.minZ = Long.parseLong( System.getProperty( "minZ", "0" ) );
p.maxZ = Long.parseLong( System.getProperty( "maxZ", "" + Long.MAX_VALUE ) );
final String basePath = System.getProperty( "basePath", "" );
- p.tileFormat = System.getProperty( "tileFormat", basePath + "%5$d/%8$d_%9$d_%1$d.jpg" );
-
- System.out.println( p.tileFormat );
-
p.format = System.getProperty( "format", "jpg" );
+ p.tileFormat = System.getProperty( "tileFormat", basePath + "%5$d/%8$d_%9$d_%1$d" + "." + p.format);
+
+ System.out.println("Tile pattern: " + p.tileFormat );
+
p.quality = Float.parseFloat( System.getProperty( "quality", "0.85" ) );
final String type = System.getProperty( "type", "rgb" );
if ( type.equalsIgnoreCase( "gray" ) || type.equalsIgnoreCase( "grey" ) )
p.type = BufferedImage.TYPE_BYTE_GRAY;
else
p.type = BufferedImage.TYPE_INT_RGB;
-
- return p;
- }
-
- final static protected BufferedImage open(
- final String path,
- final BufferedImage alternative,
- final int type )
- {
-// System.out.println( path );
- final File file = new File( path );
- if ( file.exists() )
- {
- try
- {
- return ImageIO.read( new File( path ) );
+ p.ignoreEmptyTiles = Boolean.valueOf(System.getProperty( "ignoreEmptyTiles"));
+ if (p.ignoreEmptyTiles) {
+ if (p.width < 0) {
+ throw new IllegalArgumentException("Width must be defined when empty files are not generated");
+ } else if (p.minX + p.width < 0) {
+ throw new IllegalArgumentException("Max X value overflow");
}
- catch ( final IOException e )
- {
- return alternative;
+ if (p.height < 0) {
+ throw new IllegalArgumentException("Height must be defined when empty files are not generated");
+ } else if (p.minY + p.height < 0) {
+ throw new IllegalArgumentException("Max Y value overflow");
}
}
- else
- return alternative;
+ p.bgValue = Integer.valueOf(System.getProperty( "bgValue", "0"));
+
+ return p;
}
-
-
+
/**
* Generate scaled tiles from a range of an existing scale level 0 tile
* stack.
*
- * @param tileFormat format string adfdressing tiles including basePath
+ * @param tileFormat format string addressing tiles including basePath
* @param tileWidth
* @param tileHeight
* @param minZ the first z-index to be scaled
@@ -142,6 +139,7 @@ final static protected BufferedImage open(
* @param quality quality for jpg-compression if format is "jpg"
* @param type the type of export tiles, e.g.
* {@link BufferedImage#TYPE_BYTE_GRAY}
+ * @param ignoreEmptyTiles - if true don't save empty tiles
*
* @throws Exception
*/
@@ -149,116 +147,162 @@ final public static void scale(
final String tileFormat,
final int tileWidth,
final int tileHeight,
+ final long minX,
+ final long width,
+ final long minY,
+ final long height,
final long minZ,
final long maxZ,
final String format,
final float quality,
- final int type ) throws Exception
+ final int type,
+ final boolean ignoreEmptyTiles,
+ final int bgValue) throws Exception
{
final BufferedImage alternative = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB );
-
+ Graphics2D alternativeG = alternative.createGraphics();
+
+ Color bgColor = new Color ( bgValue, bgValue, bgValue );
+ alternativeG.setPaint( bgColor );
+ alternativeG.fillRect ( 0, 0, alternative.getWidth(), alternative.getHeight() );
+
final int[] targetPixels = new int[ tileWidth * tileHeight ];
final BufferedImage target = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB );
final BufferedImage sourceImage = new BufferedImage( tileWidth * 2, tileHeight * 2, BufferedImage.TYPE_INT_RGB );
final Graphics2D g = sourceImage.createGraphics();
final int[] sourcePixels = new int[ tileWidth * tileHeight * 4 ];
-
+
+ final long maxY = height > 0 ? minY + height : -1;
+ final long maxX = width > 0 ? minX + width : -1;
Z: for ( long z = minZ; z <= maxZ; ++z )
{
System.out.println( "z-index: " + z );
-S: for ( int s = 1; true; ++s )
+ boolean proceedY = true;
+ boolean proceedX = true;
+S: for ( int s = 1; proceedX || proceedY; ++s )
{
- System.out.println( " scale: " + s );
+ System.out.println( "scale: " + s );
final int iScale = 1 << s;
final double scale = 1.0 / iScale;
-
+
final int s1 = s - 1;
final int iScale1 = 1 << s1;
final double scale1 = 1.0 / iScale1;
-
- boolean proceedY = true;
-Y: for ( long y = 0; proceedY; y += tileHeight )
+ int nResultTiles = 0;
+
+ proceedY = true;
+Y: for ( long y = minY / iScale1; proceedY; y += 2 * tileHeight )
{
- final long yt = y / tileHeight;
- boolean proceedX = true;
- for ( long x = 0; proceedX; x += tileWidth )
+ if (maxY > 0 && y >= maxY / iScale1) {
+ break;
+ }
+ proceedX = true;
+ final long yt = y / (2 * tileHeight);
+ for ( long x = minX / iScale1; proceedX; x += 2 * tileWidth )
{
- final long xt = x / tileWidth;
- final Image imp1 = open(
+ if (maxX > 0 && x >= maxX / iScale1) {
+ break;
+ }
+ nResultTiles++;
+ final long xt = x / (2 * tileWidth);
+ final Image imp1 = Util.readTile(
String.format( tileFormat, s1, scale1, x * iScale1, y * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt, 2 * xt ),
- alternative,
- type );
+ alternative);
- if ( imp1 == alternative )
- if ( x == 0 )
- if ( y == 0 )
- break Z;
+ if (maxX < 0) {
+ if (imp1 == alternative) {
+ if ( x == minX / iScale1 )
+ if ( y == minY / iScale1 )
+ break Z;
+ else
+ continue S;
else
- continue S;
- else
- continue Y;
-
- final Image imp2 = open(
+ continue Y;
+ }
+ }
+ final Image imp2 = Util.readTile(
String.format( tileFormat, s1, scale1, ( x + tileWidth ) * iScale1, y * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt, 2 * xt + 1 ),
- alternative,
- type );
-
- proceedX = imp2 != alternative;
-
- final Image imp3 = open(
+ alternative);
+
+ proceedX = maxX >= 0 || imp2 != alternative;
+
+ final Image imp3 = Util.readTile(
String.format( tileFormat, s1, scale1, x * iScale1, ( y + tileHeight ) * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt + 1, 2 * xt ),
- alternative,
- type );
-
- proceedY = imp3 != alternative;
-
- if ( x == 0 && y == 0 && !( proceedX || proceedY) )
+ alternative);
+
+ proceedY = maxY >= 0 || imp3 != alternative;
+
+ if (!proceedX && !proceedY && x == minX / iScale1 && y == minY / iScale1) {
break S;
-
- final Image imp4 = open(
+ }
+ final Image imp4 = Util.readTile(
String.format( tileFormat, s1, scale1, ( x + tileWidth ) * iScale1, ( y + tileHeight ) * iScale1, z, tileWidth * iScale1, tileHeight * iScale1, 2 * yt + 1, 2 * xt + 1 ),
- alternative,
- type );
-
+ alternative);
+
+ if (imp1 == alternative && imp2 == alternative && imp3 == alternative && imp4 == alternative) {
+ continue;
+ }
+
g.drawImage( imp1, 0, 0, null );
g.drawImage( imp2, tileWidth, 0, null );
g.drawImage( imp3, 0, tileHeight, null );
g.drawImage( imp4, tileWidth, tileHeight, null );
-
+
final PixelGrabber pg = new PixelGrabber( sourceImage, 0, 0, tileWidth * 2, tileHeight * 2, sourcePixels, 0, tileWidth * 2 );
pg.grabPixels();
-
- Downsampler.downsampleRGB( sourcePixels, targetPixels, tileWidth * 2, tileHeight * 2 );
-
- target.getRaster().setDataElements( 0, 0, tileWidth, tileHeight, targetPixels );
- final BufferedImage targetCopy = Util.draw( target, type );
- Util.writeTile(
- targetCopy,
- String.format( tileFormat, s, scale, x * iScale, y * iScale, z, tileWidth * iScale, tileHeight * iScale, yt, xt ),
- format,
- quality );
- }
+ boolean notEmpty = Downsampler.downsampleRGB( sourcePixels, targetPixels, tileWidth * 2, tileHeight * 2, bgColor.getRGB() );
+
+ if (notEmpty || !ignoreEmptyTiles) {
+ target.getRaster().setDataElements( 0, 0, tileWidth, tileHeight, targetPixels );
+ final BufferedImage targetCopy = Util.draw( target, type );
+ Util.writeTile(
+ targetCopy,
+ String.format( tileFormat, s, scale, x * iScale, y * iScale, z, tileWidth * iScale, tileHeight * iScale, yt, xt ),
+ format,
+ quality );
+ }
+ } // end for x
+ } // end for y
+ if (nResultTiles <= 1) {
+ proceedX = false;
+ proceedY = false;
}
- }
- }
+ } // end for s
+ } // end for z
}
final static public void scale( final Param p ) throws Exception
{
- scale(
- p.tileFormat,
- p.tileWidth,
- p.tileHeight,
- p.minZ,
- p.maxZ,
- p.format,
- p.quality,
- p.type );
+ scale(p.tileFormat,
+ p.tileWidth,
+ p.tileHeight,
+ adjustStart(p.minX, p.tileWidth),
+ adjustSize(p.width, p.tileWidth),
+ adjustStart(p.minY, p.tileHeight),
+ adjustSize(p.height, p.tileHeight),
+ p.minZ,
+ p.maxZ,
+ p.format,
+ p.quality,
+ p.type,
+ p.ignoreEmptyTiles,
+ p.bgValue);
+ }
+
+ private static final long adjustStart(long index, int tileSize) {
+ return index / tileSize * tileSize; // make it the start of the corresponding tile
+ }
+
+ private static final long adjustSize(long size, int tileSize) {
+ if (size > 0 && size % tileSize > 0) {
+ return size + tileSize - (size % tileSize); // make it the end of the corresponding tile
+ } else {
+ return size;
+ }
}
-
final static public void main( final String... args ) throws Exception
{
scale( parseParameters() );
diff --git a/src/main/java/org/catmaid/TileCATMAID.java b/src/main/java/org/catmaid/TileCATMAID.java
index 476b45e..d0ecb88 100644
--- a/src/main/java/org/catmaid/TileCATMAID.java
+++ b/src/main/java/org/catmaid/TileCATMAID.java
@@ -18,7 +18,6 @@
import java.awt.image.BufferedImage;
-import net.imglib2.FinalDimensions;
import net.imglib2.FinalInterval;
import net.imglib2.Interval;
import net.imglib2.RandomAccessible;
@@ -37,7 +36,6 @@
import org.catmaid.Tiler.Orientation;
-
/**
*
A standalone command line application to export image tiles representing
* scale level 0 of the tiled scale pyramids for the CATMAID interface from
@@ -112,14 +110,32 @@
*
first z-section index to be exported (long, 0)
* exportMaxZ
* last z-section index to be exported (long, depth-1)
+ * exportMinX
+ * first X in level 0 pixel coordinates to be exported (long, 0)
+ * exportMaxX
+ * last X in level 0 pixel coordinates to be exported (long, width-1)
+ * exportMinY
+ * first Y in level 0 pixel coordinates to be exported (long, 0)
+ * exportMaxY
+ * last Y in level 0 pixel coordinates to be exported (long, height-1)
* exportMinR
- * first row of tiles to be exported (long, 0)
+ * first row to be exported (long, 0). If defined it takes precedence in defining the target interval otherwise
+ * it is derived from exportMinY.
+ *
* exportMaxR
- * last row of tiles to be exported (long, depth-1)
+ * last row to be exported (long, 0). If defined it takes precedence in defining the target interval otherwise
+ * it is derived from exportMaxY.
+ *
* exportMinC
- * first column of tiles to be exported (long, 0)
+ * first column to be exported (long, 0). If defined it takes precedence in defining the target interval otherwise
+ * it is derived from exportMinX.
+ *
* exportMaxC
- * last column of tiles to be exported (long, depth-1)
+ * last column to be exported (long, 0). If defined it takes precedence in defining the target interval otherwise
+ * it is derived from exportMaxX.
+ *
+ *
+ *
* exportBasePath
* base path for the stakc to be exported (string, "")
* tilePattern
@@ -144,61 +160,60 @@ public class TileCATMAID
{
static public enum Interpolation { NN, NL };
- static protected class Param
+ static private class Param
{
/* CATMAID source stack, representing an xyz-orientation */
- public String sourceUrlFormat;
- public long sourceWidth;
- public long sourceHeight;
- public long sourceDepth;
- public long sourceScaleLevel;
- public int sourceTileWidth;
- public int sourceTileHeight;
- public double sourceResXY;
- public double sourceResZ;
-
+ String sourceUrlFormat;
+ long sourceWidth;
+ long sourceHeight;
+ long sourceDepth;
+ long sourceScaleLevel;
+ int sourceTileWidth;
+ int sourceTileHeight;
+ double sourceResXY;
+ double sourceResZ;
+
/* export */
/* source interval (crop area) in isotropic pixel coordinates */
- public Interval sourceInterval;
- public Tiler.Orientation orientation;
- public int tileWidth;
- public int tileHeight;
- public long minZ;
- public long maxZ;
- public long minR;
- public long maxR;
- public long minC;
- public long maxC;
- public String exportPath;
- public String tilePattern;
- public String format;
- public float quality;
- public int type;
- public TileCATMAID.Interpolation interpolation;
+ Interval sourceInterval;
+ Tiler.Orientation orientation;
+ int tileWidth;
+ int tileHeight;
+ long minZ;
+ long maxZ;
+ long minR;
+ long maxR;
+ long minC;
+ long maxC;
+ String exportPath;
+ String tilePattern;
+ String format;
+ float quality;
+ int type;
+ boolean ignoreEmptyTiles;
+ int bgValue;
+ TileCATMAID.Interpolation interpolation;
+ int tileCacheSize;
}
- static protected Param parseParameters()
+ static private Param parseParameters()
{
final Param p = new Param();
/* CATMAID source stack */
final String sourceBaseUrl = System.getProperty( "sourceBaseUrl", "" );
p.sourceUrlFormat = System.getProperty( "sourceUrlFormat", sourceBaseUrl + "%5$d/%8$d_%9$d_%1$d.jpg" );
-
+
p.sourceWidth = Long.parseLong( System.getProperty( "sourceWidth", "0" ) );
p.sourceHeight = Long.parseLong( System.getProperty( "sourceHeight", "0" ) );
p.sourceDepth = Long.parseLong( System.getProperty( "sourceDepth", "0" ) );
p.sourceScaleLevel = Long.parseLong( System.getProperty( "sourceScaleLevel", "0" ) );
-
- final int scaleXYDiv = 1 << p.sourceScaleLevel;
-
+
p.sourceTileWidth = Integer.parseInt( System.getProperty( "sourceTileWidth", "256" ) );
p.sourceTileHeight = Integer.parseInt( System.getProperty( "sourceTileHeight", "256" ) );
p.sourceResXY = Double.parseDouble( System.getProperty( "sourceResXY", "1.0" ) );
p.sourceResZ = Double.parseDouble( System.getProperty( "sourceResZ", "1.0" ) );
-
- final double scaleZDiv = scaleXYDiv * p.sourceResXY / p.sourceResZ;
-
+
/* export */
final long minX = Long.parseLong( System.getProperty( "minX", "0" ) );
final long minY = Long.parseLong( System.getProperty( "minY", "0" ) );
@@ -206,70 +221,115 @@ static protected Param parseParameters()
final long width = Long.parseLong( System.getProperty( "width", "0" ) );
final long height = Long.parseLong( System.getProperty( "height", "0" ) );
final long depth = Long.parseLong( System.getProperty( "depth", "0" ) );
+ p.tileWidth = Integer.parseInt( System.getProperty( "tileWidth", "256" ) );
+ p.tileHeight = Integer.parseInt( System.getProperty( "tileHeight", "256" ) );
+ // sourceInterval is the interval in pixel coordinates at the sourceScaleLevel
p.sourceInterval = new FinalInterval(
new long[]{ minX, minY, minZ },
new long[]{ minX + width - 1, minY + height - 1, minZ + depth - 1 } );
- final FinalDimensions orientedSourceInterval;
final String orientation = System.getProperty( "orientation", "xy" );
- if ( orientation.equalsIgnoreCase( "xz" ) )
+ final double scaleXY = (1 << p.sourceScaleLevel);
+ final double scaleZ = scaleXY * p.sourceResXY / p.sourceResZ;
+ final long exportMinX = scale(Long.parseLong( System.getProperty( "exportMinX", "0" ) ), scaleXY);
+ final long exportMinY = scale(Long.parseLong( System.getProperty( "exportMinY", "0" ) ), scaleXY);
+ final long exportMinZ = scale(Long.parseLong( System.getProperty( "exportMinZ", "0" ) ), scaleZ);
+ final long exportMaxX = scale(Long.parseLong( System.getProperty( "exportMaxX",
+ Long.toString(p.sourceInterval.dimension(0)) ) ), scaleXY);
+
+ if (exportMaxX < exportMinX) {
+ throw new IllegalArgumentException("The end of the X range must be greater than the beginning of the range");
+ }
+ final long exportMaxY = scale(Long.parseLong( System.getProperty( "exportMaxY",
+ Long.toString(p.sourceInterval.dimension(1)) ) ), scaleXY);
+ if (exportMaxY < exportMinY) {
+ throw new IllegalArgumentException("The end of the Y range must be greater than the beginning of the range");
+ }
+ final long exportMaxZ = scale(Long.parseLong( System.getProperty( "exportMaxZ",
+ Long.toString(p.sourceInterval.dimension(2)) ) ), scaleZ);
+ if (exportMaxZ < exportMinZ) {
+ throw new IllegalArgumentException("The end of the Z range must be greater than the beginning of the range");
+ }
+
+ final Interval scaledExportInterval = new FinalInterval(
+ new long[] { exportMinX, exportMinY, exportMinZ },
+ new long[] { exportMaxX, exportMaxY, exportMaxZ}
+ );
+
+ final Interval orientedScaledInterval;
+ if ( orientation.equalsIgnoreCase( "xz" ) || orientation.equalsIgnoreCase( "zx" ) )
{
p.orientation = Orientation.XZ;
- orientedSourceInterval = new FinalDimensions(
- p.sourceInterval.dimension( 0 ) / scaleXYDiv,
- ( long )( p.sourceInterval.dimension( 2 ) / scaleZDiv ),
- p.sourceInterval.dimension( 1 ) / scaleXYDiv );
+ orientedScaledInterval = new FinalInterval(
+ new long[] {
+ scaledExportInterval.min(0),
+ scaledExportInterval.min(2),
+ scaledExportInterval.min(1)
+ },
+ new long[] {
+ scaledExportInterval.max(0),
+ scaledExportInterval.max(2),
+ scaledExportInterval.max(1)
+ }
+ );
}
- else if ( orientation.equalsIgnoreCase( "zy" ) )
+ else if ( orientation.equalsIgnoreCase( "zy" ) || orientation.equalsIgnoreCase( "yz" ) )
{
p.orientation = Orientation.ZY;
- orientedSourceInterval = new FinalDimensions(
- ( long )( p.sourceInterval.dimension( 2 ) / scaleZDiv ),
- p.sourceInterval.dimension( 1 ) / scaleXYDiv,
- p.sourceInterval.dimension( 0 ) / scaleXYDiv );
+ orientedScaledInterval = new FinalInterval(
+ new long[] {
+ scaledExportInterval.min(2),
+ scaledExportInterval.min(1),
+ scaledExportInterval.min(0)
+ },
+ new long[]{
+ scaledExportInterval.max(2),
+ scaledExportInterval.max(1),
+ scaledExportInterval.max(0)
+ }
+ );
}
else
{
p.orientation = Orientation.XY;
- orientedSourceInterval = new FinalDimensions(
- p.sourceInterval.dimension( 0 ) / scaleXYDiv,
- p.sourceInterval.dimension( 1 ) / scaleXYDiv,
- ( long )( p.sourceInterval.dimension( 2 ) / scaleZDiv ) );
+ orientedScaledInterval = new FinalInterval(scaledExportInterval);
}
-
- p.tileWidth = Integer.parseInt( System.getProperty( "tileWidth", "256" ) );
- p.tileHeight = Integer.parseInt( System.getProperty( "tileHeight", "256" ) );
- p.minZ = Long.parseLong( System.getProperty( "exportMinZ", "0" ) );
- p.maxZ = Long.parseLong( System.getProperty(
- "exportMaxZ",
- Long.toString( orientedSourceInterval.dimension( 2 ) - 1 ) ) );
- p.minR = Long.parseLong( System.getProperty( "exportMinR", "0" ) );
- p.maxR = Long.parseLong( System.getProperty(
- "exportMaxR",
- Long.toString( ( long )Math.ceil( ( double )orientedSourceInterval.dimension( 1 ) / ( double )p.tileHeight ) - 1 ) ) );
- p.minC = Long.parseLong( System.getProperty( "exportMinC", "0" ) );
- p.maxC = Long.parseLong( System.getProperty(
- "exportMaxC",
- Long.toString( ( long )Math.ceil( ( double )orientedSourceInterval.dimension( 0 ) / ( double )p.tileWidth ) - 1 ) ) );
-
+
+ p.minZ = orientedScaledInterval.min( 2 );
+ p.minR = Long.parseLong( System.getProperty( "exportMinR",
+ Long.toString(( long )(orientedScaledInterval.min( 1 ) / ( double )p.tileHeight )) ) );
+ p.minC = Long.parseLong( System.getProperty( "exportMinC",
+ Long.toString(( long )(orientedScaledInterval.min( 0 ) / ( double )p.tileWidth )) ) );
+ p.maxZ = orientedScaledInterval.max( 2 );
+ p.maxR = Long.parseLong( System.getProperty( "exportMaxR",
+ Long.toString(( long )Math.ceil(orientedScaledInterval.max( 1 ) / ( double )p.tileHeight - 1) ) ) );
+ p.maxC = Long.parseLong( System.getProperty( "exportMaxC",
+ Long.toString(( long )Math.ceil(orientedScaledInterval.max( 0 ) / ( double )p.tileWidth - 1) ) ) );
+
p.exportPath = System.getProperty( "exportBasePath", "" );
- p.tilePattern = System.getProperty( "tilePattern", "/__" );
p.format = System.getProperty( "format", "jpg" );
+ p.tilePattern = System.getProperty( "tilePattern", "%5$d/%8$d_%9$d_%1$d" + "." + p.format); // default is z/row_col_scale.jpg
p.quality = Float.parseFloat( System.getProperty( "quality", "0.85" ) );
final String type = System.getProperty( "type", "rgb" );
if ( type.equalsIgnoreCase( "gray" ) || type.equalsIgnoreCase( "grey" ) )
p.type = BufferedImage.TYPE_BYTE_GRAY;
else
p.type = BufferedImage.TYPE_INT_RGB;
-
+ p.ignoreEmptyTiles = Boolean.valueOf(System.getProperty( "ignoreEmptyTiles"));
+ p.bgValue = Integer.valueOf(System.getProperty( "bgValue", "0"));
+
final String interpolation = System.getProperty( "interpolation", "NN" );
- if ( interpolation.equalsIgnoreCase( "nl" ) || interpolation.equalsIgnoreCase( "NL" ) )
+ if ( interpolation.equalsIgnoreCase( "NL" ) )
p.interpolation = Interpolation.NL;
else
p.interpolation = Interpolation.NN;
-
+ p.tileCacheSize = Integer.valueOf(System.getProperty( "tileCacheSize", "0" ));
return p;
}
-
+
+ private static long scale(long val, double scaleFactor) {
+ return (long) (val / scaleFactor);
+ }
+
/**
* Create a {@link Tiler} from a CATMAID stack.
*
@@ -278,20 +338,20 @@ else if ( orientation.equalsIgnoreCase( "zy" ) )
* @param height of scale level 0 in pixels
* @param depth of scale level 0 in pixels
* @param s scale level to be used, using anything >0 will create an
- * accordingly scaled source stack
+ * accordingly scaled source stack
* @param tileWidth
* @param tileHeight
* @param resXY x,y-resolution
- * @param real valued offset in CATMAID scale level 0 pixels
+ * @param offset in CATMAID scale level 0 pixels
* @param resZ z-resolution, what matters is only the ratio
* between z- and x,y-resolution to scale the source
* to isotropic resolution (if that is desired, you will want to do
* it when exporting re-sliced stacks, not when extracting at the
* original orientation).
- *
+ *
* @return
*/
- static public Tiler fromCATMAID(
+ static private Tiler fromCATMAID(
final String urlFormat,
final long width,
final long height,
@@ -302,7 +362,8 @@ static public Tiler fromCATMAID(
final double resXY,
final double resZ,
final RealLocalizable offset,
- final Interpolation interpolation )
+ final Interpolation interpolation,
+ final int cacheSize )
{
final CATMAIDRandomAccessibleInterval catmaidStack =
new CATMAIDRandomAccessibleInterval(
@@ -312,7 +373,8 @@ static public Tiler fromCATMAID(
depth,
s,
tileWidth,
- tileHeight );
+ tileHeight,
+ cacheSize );
/* scale and re-raster */
final double scaleXY = 1.0 / ( 1 << s );
@@ -321,53 +383,49 @@ static public Tiler fromCATMAID(
final double offsetX = offset.getDoublePosition( 0 ) * scaleXY;
final double offsetY = offset.getDoublePosition( 1 ) * scaleXY;
final double offsetZ = offset.getDoublePosition( 2 ) * scaleZ;
-
+
final AffineTransform3D transform = new AffineTransform3D();
transform.set(
1, 0, 0, -offsetX,
0, 1, 0, -offsetY,
0, 0, scaleZ, -offsetZ );
- final RealRandomAccessible< ARGBType > interpolant;
+ final RealRandomAccessible< ARGBType > interpolatedStack;
switch ( interpolation )
{
case NL:
- interpolant = Views.interpolate( catmaidStack, new NLinearInterpolatorARGBFactory() );
+ interpolatedStack = Views.interpolate( catmaidStack, new NLinearInterpolatorARGBFactory() );
break;
default:
- interpolant = Views.interpolate( catmaidStack, new NearestNeighborInterpolatorFactory< ARGBType >() );
+ interpolatedStack = Views.interpolate( catmaidStack, new NearestNeighborInterpolatorFactory< ARGBType >() );
}
- final RandomAccessible< ARGBType > scaledInterpolant = RealViews.affine( interpolant, transform );
- final RandomAccessibleInterval< ARGBType > scaled =
+ final RandomAccessible< ARGBType > scaledInterpolatedStack = RealViews.affine( interpolatedStack, transform );
+ final RandomAccessibleInterval< ARGBType > croppedView =
Views.interval(
- scaledInterpolant,
+ scaledInterpolatedStack,
new FinalInterval(
( long )( scaleXY * width - offsetX ),
( long )( scaleXY * height - offsetY ),
( long )( scaleZ * depth - offsetZ ) ) );
-
- return new Tiler( scaled );
+ return new Tiler( croppedView );
}
-
-
-
-
- final static public void main( final String[] args ) throws Exception
+
+ public static void main( final String[] args ) throws Exception
{
final Param p = parseParameters();
-
+
System.out.println( "sourceInterval: " + Util.printInterval( p.sourceInterval ) );
-
+
final RealPoint min = new RealPoint( 3 );
p.sourceInterval.min( min );
-
+
final int scaleXYDiv = 1 << p.sourceScaleLevel;
final double scaleZDiv = scaleXYDiv * p.sourceResXY / p.sourceResZ;
- final FinalInterval cropDimensions = new FinalInterval(
+ final FinalInterval croppedDimensions = new FinalInterval(
p.sourceInterval.dimension( 0 ) / scaleXYDiv,
p.sourceInterval.dimension( 1 ) / scaleXYDiv,
( long )( p.sourceInterval.dimension( 2 ) / scaleZDiv ) );
-
+
fromCATMAID(
p.sourceUrlFormat,
p.sourceWidth,
@@ -379,8 +437,9 @@ final static public void main( final String[] args ) throws Exception
p.sourceResXY,
p.sourceResZ,
min,
- p.interpolation ).tile(
- cropDimensions,
+ p.interpolation,
+ p.tileCacheSize ).tile(
+ croppedDimensions,
p.orientation,
p.tileWidth,
p.tileHeight,
@@ -394,6 +453,8 @@ final static public void main( final String[] args ) throws Exception
p.tilePattern,
p.format,
p.quality,
- p.type );
+ p.type,
+ p.ignoreEmptyTiles,
+ p.bgValue);
}
}
diff --git a/src/main/java/org/catmaid/Tiler.java b/src/main/java/org/catmaid/Tiler.java
index e8b94f2..fadfac5 100644
--- a/src/main/java/org/catmaid/Tiler.java
+++ b/src/main/java/org/catmaid/Tiler.java
@@ -26,7 +26,6 @@
import net.imglib2.img.array.ArrayImg;
import net.imglib2.img.array.ArrayImgs;
import net.imglib2.img.basictypeaccess.array.IntArray;
-import net.imglib2.type.Type;
import net.imglib2.type.numeric.ARGBType;
import net.imglib2.util.Intervals;
import net.imglib2.view.Views;
@@ -38,7 +37,6 @@
*/
public class Tiler
{
-// final static protected Toolkit toolkit = Toolkit.getDefaultToolkit();
final protected RandomAccessibleInterval< ARGBType > source;
@@ -62,15 +60,23 @@ static public enum Orientation
* @param sourceTile
* @param targetTile
*/
- final static protected < T extends Type< T > > void copyTile(
- final RandomAccessibleInterval< T > sourceTile,
- final RandomAccessibleInterval< T > targetTile )
+ final static private boolean copyTile(
+ final RandomAccessibleInterval< ARGBType > sourceTile,
+ final RandomAccessibleInterval< ARGBType > targetTile,
+ final ARGBType bg )
{
- final Cursor< T > src = Views.flatIterable( sourceTile ).cursor();
- final Cursor< T > dst = Views.flatIterable( targetTile ).cursor();
+ final Cursor< ARGBType > src = Views.flatIterable( sourceTile ).cursor();
+ final Cursor< ARGBType > dst = Views.flatIterable( targetTile ).cursor();
- while ( src.hasNext() )
- dst.next().set( src.next() );
+ boolean hasInfo = false;
+ while ( src.hasNext() ) {
+ ARGBType spixel = src.next();
+ if ((spixel.get() & 0xFFFFFF) != bg.get()) {
+ hasInfo = true;
+ }
+ dst.next().set(spixel);
+ }
+ return hasInfo;
}
@@ -86,7 +92,7 @@ final static protected < T extends Type< T > > void copyTile(
* @param yx
* @param bg background value
*/
- final static protected void copyTile(
+ final static private boolean copyTile(
final RandomAccessibleInterval< ARGBType > sourceTile,
final RandomAccessibleInterval< ARGBType > targetTile,
final boolean yx,
@@ -103,7 +109,7 @@ final static protected void copyTile(
for ( final ARGBType p : Views.iterable( targetTile ) )
p.set( bg );
- raiTarget = Views.interval( targetTile, sourceTile );
+ raiTarget = Views.interval( targetTile, sourceTile );
}
final RandomAccessibleInterval< ARGBType > raiSource;
@@ -115,35 +121,9 @@ final static protected void copyTile(
else
raiSource = sourceTile;
- copyTile( raiSource, raiTarget );
+ return copyTile( raiSource, raiTarget, bg );
}
-
-
- /**
- * Replace the ctile coordinates in a pattern string.
- *
- * @param template
- * @param s scale-index (scale = 1/2s)
- * @param z z-index
- * @param r row
- * @param c column
- * @return
- */
- final static protected String tileName(
- final String template,
- final long s,
- final long z,
- final long r,
- final long c )
- {
- return template.
- replace( "", Long.toString( s ) ).
- replace( "", Long.toString( z ) ).
- replace( "", Long.toString( r ) ).
- replace( "", Long.toString( c ) );
- }
-
-
+
/**
* Generate a subset of a CATMAID tile stack of an {@link Interval} of the
* source {@link RandomAccessibleInterval}. That is you can choose the
@@ -166,6 +146,7 @@ final static protected String tileName(
* @param format
* @param quality
* @param type
+ * @param bgValue background pixel value
* @throws IOException
*/
public void tile(
@@ -183,7 +164,9 @@ public void tile(
final String tilePattern,
final String format,
final float quality,
- final int type ) throws IOException
+ final int type,
+ final boolean ignoreEmptyTiles,
+ final int bgValue ) throws IOException
{
/* orientation */
final RandomAccessibleInterval< ARGBType > view;
@@ -206,19 +189,16 @@ public void tile(
view = source;
viewInterval = sourceInterval;
}
-
-// final long maxC =
-// final long maxR = ( long ) Math.ceil( ( double ) viewInterval.dimension( 1 ) / ( double ) tileHeight ) - 1;
-// final long maxZ = viewInterval.dimension( 2 ) - 1;
-//
+
final long[] min = new long[ 3 ];
final long[] size = new long[ 3 ];
size[ 2 ] = 1;
-
+
final int[] tilePixels = new int[ tileWidth * tileHeight ];
final ArrayImg< ARGBType, IntArray > tile = ArrayImgs.argbs( tilePixels, tileWidth, tileHeight );
final BufferedImage img = new BufferedImage( tileWidth, tileHeight, BufferedImage.TYPE_INT_RGB );
-
+ final ARGBType bg = new ARGBType( ARGBType.rgba(bgValue, bgValue, bgValue, 0) );
+
for ( long z = minZ; z <= maxZ; ++z )
{
min[ 2 ] = z + viewInterval.min( 2 );
@@ -235,20 +215,18 @@ public void tile(
final RandomAccessibleInterval< ARGBType > sourceTile = Views.hyperSlice( Views.offsetInterval( view, min, size ), 2, 0 );
- copyTile( sourceTile, tile, orientation == Orientation.ZY, new ARGBType( 0 ) );
- img.getRaster().setDataElements( 0, 0, tileWidth, tileHeight, tilePixels );
- final BufferedImage imgCopy = Util.draw( img, type );
-
- final String tilePath =
- new StringBuffer( exportPath ).
- append( "/" ).
- append( tileName( tilePattern, 0, z, r, c ) ).
- append( "." ).
- append( format ).
- toString();
-
- Util.writeTile( imgCopy, tilePath, format, quality );
-// writePngTile( img, sectionPath + "/" + r + "_" + c + "_0.png" );
+ boolean tileIsNotEmpty = copyTile( sourceTile, tile, orientation == Orientation.ZY, bg );
+ if (tileIsNotEmpty || !ignoreEmptyTiles) {
+ img.getRaster().setDataElements(0, 0, tileWidth, tileHeight, tilePixels);
+ final BufferedImage imgCopy = Util.draw(img, type);
+ final String tilePath =
+ new StringBuffer(exportPath != null && exportPath.trim().length() > 0 ? exportPath : "")
+ .append(exportPath != null && exportPath.trim().length() > 0 ? "/" : "")
+ .append(String.format(tilePattern, 0, 1.0, min[0], min[1], z, tileWidth, tileHeight, r, c))
+ .toString();
+
+ Util.writeTile(imgCopy, tilePath, format, quality);
+ }
}
}
}
@@ -260,7 +238,7 @@ public void tile(
* {@link RandomAccessibleInterval}. That is you can choose the
* window to be exported.
*
- * @param sourceInterval the interval of the source to be exported
+ * @param sourceInterval the interval of the source to be exported
* @param orientation the export orientation
* @param tileWidth
* @param tileHeight
@@ -271,6 +249,7 @@ public void tile(
* @param format
* @param quality
* @param type
+ * @param bgValue background pixel value
* @throws IOException
*/
public void tile(
@@ -282,12 +261,14 @@ public void tile(
final String tilePattern,
final String format,
final float quality,
- final int type ) throws IOException
+ final int type,
+ final boolean ignoreEmptyTiles,
+ final int bgValue ) throws IOException
{
final long maxC;
final long maxR;
final long maxZ;
-
+
switch ( orientation )
{
case XZ:
@@ -306,10 +287,6 @@ public void tile(
maxZ = sourceInterval.dimension( 2 ) - 1;
}
-// System.out.println( "maxZ:" + maxZ );
-// System.out.println( "maxR:" + maxR );
-// System.out.println( "maxC:" + maxC );
-
tile(
sourceInterval,
orientation,
@@ -325,7 +302,9 @@ public void tile(
tilePattern,
format,
quality,
- type );
+ type,
+ ignoreEmptyTiles,
+ bgValue );
}
@@ -343,6 +322,7 @@ public void tile(
* @param format
* @param quality
* @param type
+ * @param bgValue background pixel value
* @throws IOException
*/
public void tile(
@@ -353,7 +333,9 @@ public void tile(
final String tilePattern,
final String format,
final float quality,
- final int type ) throws IOException
+ final int type,
+ final boolean ignoreEmptyTiles,
+ final int bgValue ) throws IOException
{
tile(
source,
@@ -364,7 +346,9 @@ public void tile(
tilePattern,
format,
quality,
- type );
+ type,
+ ignoreEmptyTiles,
+ bgValue );
}
@@ -389,6 +373,7 @@ public void tile(
* @param quality quality for jpg-compression if format is "jpg"
* @param type the type of export tiles, e.g.
* {@link BufferedImage#TYPE_BYTE_GRAY}
+ * @param bgValue background pixel value
* @throws IOException
*/
public void tile(
@@ -405,7 +390,9 @@ public void tile(
final String tilePattern,
final String format,
final float quality,
- final int type ) throws IOException
+ final int type,
+ final boolean ignoreEmptyTiles,
+ final int bgValue ) throws IOException
{
tile(
source,
@@ -422,6 +409,8 @@ public void tile(
tilePattern,
format,
quality,
- type );
+ type,
+ ignoreEmptyTiles,
+ bgValue );
}
}
diff --git a/src/main/java/org/catmaid/Util.java b/src/main/java/org/catmaid/Util.java
index d01d092..083e39e 100644
--- a/src/main/java/org/catmaid/Util.java
+++ b/src/main/java/org/catmaid/Util.java
@@ -18,23 +18,29 @@
import java.awt.Image;
import java.awt.image.BufferedImage;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
-import javax.imageio.stream.FileImageOutputStream;
+import javax.imageio.stream.ImageOutputStream;
/**
*
*
* @author Stephan Saalfeld
*/
-public class Util
-{
- final static public String tilePath(
+class Util {
+ final static String tilePath(
final String tileFormat,
final int scaleLevel,
final double scale,
@@ -44,30 +50,157 @@ final static public String tilePath(
final int tileWidth,
final int tileHeight,
final long row,
- final long column )
- {
+ final long column) {
return String.format( tileFormat, scaleLevel, scale, x, y, z, tileWidth, tileHeight, row, column );
}
-
- final static public BufferedImage draw(
+
+ final static BufferedImage draw(
final Image img,
- final int type )
- {
+ final int type) {
final BufferedImage imgCopy = new BufferedImage( img.getWidth( null ), img.getHeight( null ), type );
imgCopy.createGraphics().drawImage( img, 0, 0, null );
return imgCopy;
}
-
- final static public void writeTile(
+
+ final static BufferedImage readTile(
+ final String url,
+ final BufferedImage alternative) {
+ if ( url.startsWith("file://") ) {
+ return readTileFromFile(url.substring("file://".length()), alternative);
+ } else if ( url.startsWith("http://") || url.startsWith("https://") ) {
+ return readTileFromUrl(url, alternative);
+ } else {
+ return readTileFromFile(url, alternative);
+ }
+ }
+
+ final static BufferedImage readTileFromFile(
+ final String url,
+ final BufferedImage alternative) {
+ File f = new File( url );
+ if ( f.exists() ) {
+ try {
+ return ImageIO.read( new File( url ) );
+ } catch ( IOException e ) {
+ e.printStackTrace();
+ }
+ }
+ return alternative;
+ }
+
+ final static BufferedImage readTileFromUrl(
+ final String urlString,
+ final BufferedImage alternative) {
+ HttpURLConnection conn = null;
+ InputStream connInputStream = null;
+ try {
+ final URL url = new URL( urlString );
+ conn = (HttpURLConnection) url.openConnection();
+ conn.setDoOutput(false);
+ conn.setDoInput(true);
+ conn.setRequestMethod("GET");
+ int statusCode = conn.getResponseCode();
+ if (statusCode != HttpURLConnection.HTTP_OK) {
+ return alternative;
+ }
+ connInputStream = conn.getInputStream();
+ return ImageIO.read(connInputStream);
+ } catch ( IOException e ) {
+ e.printStackTrace();
+ } finally {
+ if (connInputStream != null) {
+ try {
+ connInputStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ if (conn != null) {
+ conn.disconnect();
+ }
+ }
+ return alternative;
+ }
+
+ final static void writeTile(
final BufferedImage img,
- final String path,
+ final String url,
+ final String format,
+ final float quality ) throws IOException
+ {
+ if ( url.startsWith("file://") ) {
+ writeTileToFile(img, url.substring("file://".length()), format, quality);
+ } else if ( url.startsWith("http://") || url.startsWith("https://") ) {
+ writeTileToUrl(img, url, format, quality);
+ } else {
+ writeTileToFile(img, url, format, quality);
+ }
+ }
+
+ final static private void writeTileToFile(
+ final BufferedImage img,
+ final String tileFile,
+ final String format,
+ final float quality ) throws IOException
+ {
+ new File( tileFile ).getParentFile().mkdirs();
+ final FileOutputStream os = new FileOutputStream( new File( tileFile ) );
+ try {
+ writeTile(img, os, format, quality);
+ } finally {
+ os.close();
+ }
+ }
+
+ final static private void writeTileToUrl(
+ final BufferedImage img,
+ final String httpUrl,
+ final String format,
+ final float quality ) throws IOException
+ {
+ URL url = new URL(httpUrl);
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setDoOutput(true);
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty("Content-Type", "application/octet-stream");
+ OutputStream os = conn.getOutputStream();
+ InputStream is = null;
+ try {
+ writeTile(img, os, format, quality);
+ int statusCode = conn.getResponseCode();
+ if (statusCode >= HttpURLConnection.HTTP_BAD_REQUEST) {
+ System.err.printf("Error response from %s: %d\n", httpUrl, statusCode);
+ }
+ is = conn.getInputStream();
+ BufferedReader br = new BufferedReader(new InputStreamReader((is)));
+ String serverOutput;
+ while ((serverOutput = br.readLine()) != null) {
+ System.out.println(serverOutput);
+ }
+ } catch (IOException e) {
+ System.err.printf("Error writing to %s %d\n", httpUrl, conn.getExpiration());
+ throw e;
+ } finally {
+ if (is != null) {
+ try {
+ is.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ conn.disconnect();
+ }
+ }
+
+ final static private void writeTile(
+ final BufferedImage img,
+ final OutputStream outputStream,
final String format,
final float quality ) throws IOException
{
- new File( path ).getParentFile().mkdirs();
final ImageWriter writer = ImageIO.getImageWritersByFormatName( format ).next();
- final FileImageOutputStream output = new FileImageOutputStream( new File( path ) );
- writer.setOutput( output );
+ ImageOutputStream ios = ImageIO.createImageOutputStream(outputStream);
+ writer.setOutput(ios);
if ( format.equalsIgnoreCase( "jpg" ) )
{
final ImageWriteParam param = writer.getDefaultWriteParam();
@@ -76,9 +209,12 @@ final static public void writeTile(
writer.write( null, new IIOImage( img.getRaster(), null, null ), param );
}
else
+ {
writer.write( img );
-
+ }
+ ios.flush();
+ outputStream.flush();
writer.dispose();
- output.close();
}
+
}