Skip to content

Commit

Permalink
Merge branch 'ebremer:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
ebremer authored Mar 6, 2024
2 parents fe20589 + 1a816bc commit 5420fb1
Show file tree
Hide file tree
Showing 12 changed files with 300 additions and 48 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/target/
error.*
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Hatch 3.2.0
# Hatch

This tool converts the largest image in a VSI, SVS, or TIF image into a new TIFF image with a freshly created image pyramid with each scaling 1/2 dimensions each scale.

Expand Down
11 changes: 10 additions & 1 deletion dependency-reduced-pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>edu.stonybrook.bmi</groupId>
<artifactId>hatch</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
<build>
<resources>
<resource>
Expand Down Expand Up @@ -128,6 +128,15 @@
<url>https://artifacts.openmicroscopy.org/artifactory/maven/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>apache-jena-libs</artifactId>
<version>5.0.0-rc1</version>
<type>pom</type>
<scope>compile</scope>
</dependency>
</dependencies>
<properties>
<maven.compiler.target>21</maven.compiler.target>
<twelvemonkeys.version>3.10.1</twelvemonkeys.version>
Expand Down
Empty file added error.log
Empty file.
6 changes: 3 additions & 3 deletions nbactions-hatchjar.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<properties>
<exec.vmArgs></exec.vmArgs>
<exec.args>${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}</exec.args>
<exec.appArgs>-src \vsi\vsi -dest \vsi\warp</exec.appArgs>
<exec.appArgs>-v -src D:\HalcyonStorage\tcga\brca -dest D:\HalcyonStorage\tcga\brca\tif</exec.appArgs>
<exec.mainClass>edu.stonybrook.bmi.hatch.Hatch</exec.mainClass>
<exec.executable>java</exec.executable>
</properties>
Expand All @@ -29,7 +29,7 @@
<properties>
<exec.vmArgs>-agentlib:jdwp=transport=dt_socket,server=n,address=${jpda.address}</exec.vmArgs>
<exec.args>${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}</exec.args>
<exec.appArgs>-src \vsi\vsi -dest \vsi\warp</exec.appArgs>
<exec.appArgs>-v -src D:\HalcyonStorage\tcga\brca -dest D:\HalcyonStorage\tcga\brca\tif</exec.appArgs>
<exec.mainClass>edu.stonybrook.bmi.hatch.Hatch</exec.mainClass>
<exec.executable>java</exec.executable>
<jpda.listen>true</jpda.listen>
Expand All @@ -49,7 +49,7 @@
<exec.args>${exec.vmArgs} -classpath %classpath ${exec.mainClass} ${exec.appArgs}</exec.args>
<exec.mainClass>edu.stonybrook.bmi.hatch.Hatch</exec.mainClass>
<exec.executable>java</exec.executable>
<exec.appArgs>-src \vsi\vsi -dest \vsi\warp</exec.appArgs>
<exec.appArgs>-v -src D:\HalcyonStorage\tcga\brca -dest D:\HalcyonStorage\tcga\brca\tif</exec.appArgs>
</properties>
</action>
</actions>
8 changes: 7 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>edu.stonybrook.bmi</groupId>
<artifactId>hatch</artifactId>
<version>3.2.0</version>
<version>3.3.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down Expand Up @@ -35,6 +35,12 @@
<artifactId>imageio-tiff</artifactId>
<version>${twelvemonkeys.version}</version>
</dependency>
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>apache-jena-libs</artifactId>
<version>5.0.0-rc1</version>
<type>pom</type>
</dependency>
</dependencies>
<build>
<resources>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/edu/stonybrook/bmi/hatch/Hatch.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* @author erich
*/
public class Hatch {
public static String software = "hatch 3.2.0 by Wing-n-Beak";
public static String software = "hatch 3.3.0 by Wing-n-Beak";
private static final String[] ext = new String[] {".vsi", ".svs", ".tif"};
private static final String errorlog = "error.log";
private static Logger LOGGER;
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/edu/stonybrook/bmi/hatch/HatchWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
public class HatchWriter implements AutoCloseable {
private final RandomAccessOutputStream ros;
private final HatchSaver writer;
//private XMP xmp = null;

public HatchWriter(String file) throws IOException {
ros = new RandomAccessOutputStream(file);
Expand All @@ -27,6 +28,10 @@ public HatchWriter(String file) throws IOException {
public void nextImage() throws IOException {
ros.seek(ros.length());
}

//public void setXMP(XMP xmp) {
// this.xmp = xmp;
//}

@Override
public void close() {
Expand All @@ -39,6 +44,9 @@ public void close() {
}

public void writeIFDStrips(IFD ifd, byte[] raw, boolean last, int x, int y) throws FormatException, IOException {
// if (xmp!=null) {
// ifd.putIFDValue(700, xmp.getXMPString());
//}
byte[][] tilestrip = new byte[1][];
tilestrip[0] = raw;
writer.writeIFDStrips(ifd, tilestrip, 3, last, x, y);
Expand Down
18 changes: 0 additions & 18 deletions src/main/java/edu/stonybrook/bmi/hatch/Test2.java

This file was deleted.

88 changes: 65 additions & 23 deletions src/main/java/edu/stonybrook/bmi/hatch/X2TIF.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand All @@ -22,6 +23,7 @@
import loci.formats.gui.AWTImageTools;
import loci.formats.meta.IMetadata;
import loci.formats.meta.MetadataRetrieve;
import loci.formats.ome.OMEPyramidStore;
import loci.formats.services.OMEXMLService;
import loci.formats.tiff.IFD;
import loci.formats.tiff.PhotoInterp;
Expand Down Expand Up @@ -58,6 +60,7 @@ public class X2TIF implements AutoCloseable {
private IMetadata meta;
private byte compression;
private static Logger LOGGER;
private XMP xmp = null;

public X2TIF(HatchParameters params, String src, String dest, Integer series) {
LOGGER = Logger.getLogger(X2TIF.class.getName());
Expand Down Expand Up @@ -94,13 +97,13 @@ public X2TIF(HatchParameters params, String src, String dest, Integer series) {
maximage = series;
}
if ((series!=null)&&((series<0)||(series>reader.getSeriesCount()))) {
LOGGER.log(Level.INFO,"Series doesn't exist : "+src+" --> "+series);
LOGGER.log(Level.INFO, "Series doesn''t exist : {0} --> {1}", new Object[]{src, series});
System.exit(0);
}
try {
writer = new HatchWriter(dest);
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> "+params.src+" "+params.dest+" "+ex.toString());
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> {0} {1} {2}", new Object[]{params.src, params.dest, ex.toString()});
}
reader.setSeries(maximage);
tileSizeX = reader.getOptimalTileWidth();
Expand All @@ -112,9 +115,9 @@ public X2TIF(HatchParameters params, String src, String dest, Integer series) {
ppy = retrieve.getPixelsPhysicalSizeY(maximage);
SetPPS();
if (params.verbose) {
LOGGER.log(Level.INFO,"Image Size : "+width+"x"+height);
LOGGER.log(Level.INFO,"Tile size : "+tileSizeX+"x"+tileSizeY);
LOGGER.log(Level.INFO,"Compression : "+reader.metadata.get("Compression"));
LOGGER.log(Level.INFO, "Image Size : {0}x{1}", new Object[]{width, height});
LOGGER.log(Level.INFO, "Tile size : {0}x{1}", new Object[]{tileSizeX, tileSizeY});
LOGGER.log(Level.INFO, "Compression : {0}", reader.metadata.get("Compression"));
}
//String xml = service.getOMEXML(omexml);
//Systsm.out.println(xml);
Expand All @@ -129,7 +132,7 @@ public X2TIF(HatchParameters params, String src, String dest, Integer series) {
throw new Error("Hatch can only convert images that have JPEG compression.");
}
} catch (Error e){
LOGGER.log(Level.SEVERE, e.getLocalizedMessage()+" : "+src+" "+dest);
LOGGER.log(Level.SEVERE, "{0} : {1} {2}", new Object[]{e.getLocalizedMessage(), src, dest});
System.exit(0);
}
int size = Math.max(width, height);
Expand All @@ -138,7 +141,7 @@ public X2TIF(HatchParameters params, String src, String dest, Integer series) {
depth = ss-tiless+2;
TileSize = reader.getOptimalTileHeight() * reader.getOptimalTileWidth() * 24;
if (params.verbose) {
LOGGER.log(Level.INFO,"# of scales to be generated : "+depth);
LOGGER.log(Level.INFO, "# of scales to be generated : {0}", depth);
}
meta = service.createOMEXMLMetadata();
meta.setImageID("Image:0", 0);
Expand All @@ -157,15 +160,41 @@ public X2TIF(HatchParameters params, String src, String dest, Integer series) {
meta.setPixelsSizeC(new PositiveInteger(3), 0);
meta.setPixelsSizeT(new PositiveInteger(1), 0);
} catch (DependencyException ex) {
LOGGER.log(Level.SEVERE, "DependencyException : "+src+" "+dest);
LOGGER.log(Level.SEVERE, "DependencyException : {0} {1}", new Object[]{src, dest});
} catch (ServiceException ex) {
LOGGER.log(Level.SEVERE, "ServiceException : "+src+" "+dest);
LOGGER.log(Level.SEVERE, "ServiceException : {0} {1}", new Object[]{src, dest});
} catch (FormatException ex) {
LOGGER.log(Level.SEVERE, "FormatException : "+src+" "+dest);
LOGGER.log(Level.SEVERE, "FormatException : {0} {1}", new Object[]{src, dest});
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "IOException : "+src+" "+dest);
LOGGER.log(Level.SEVERE, "IOException : {0} {1}", new Object[]{src, dest});
}

xmp = new XMP();
xmp.setMagnification(FindMagnification());
xmp.setSizePerPixelXinMM((1d/((px.doubleValue()/10d)/1000d))/1000d);
xmp.setSizePerPixelYinMM((1d/((py.doubleValue()/10d)/1000d))/1000d);
//writer.setXMP(xmp);
}

private Double FindMagnification() {
var mx = (OMEPyramidStore) reader.getMetadataStore();
try {
String objectiveID = mx.getObjectiveSettingsID(0);
int instrument = -1;
int objective = -1;
int numberOfInstruments = mx.getInstrumentCount();
for (int ii = 0; ii < numberOfInstruments; ii++) {
int numObjectives = mx.getObjectiveCount(ii);
for (int oi = 0; 0 < numObjectives; oi++) {
if (objectiveID.equals(mx.getObjectiveID(ii, oi))) {
instrument = ii;
objective = oi;
break;
}
}
}
return (instrument < 0) ? null : mx.getObjectiveNominalMagnification(instrument, objective);
} catch (NullPointerException ex) {}
return null;
}

private int MaxImage(FormatReader reader) {
Expand Down Expand Up @@ -215,9 +244,9 @@ public void Dump2File3(byte[] buffer, int a, int b) {
fos.flush();
}
} catch (FileNotFoundException ex) {
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> "+params.src+" "+params.dest+" "+ex.toString());
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> {0} {1} {2}", new Object[]{params.src, params.dest, ex.toString()});
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> "+params.src+" "+params.dest+" "+ex.toString());
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> {0} {1} {2}", new Object[]{params.src, params.dest, ex.toString()});
}
}

Expand All @@ -239,14 +268,14 @@ public void DumpBI2File3(BufferedImage bi, int a, int b) {
try {
jpgWriter.write(null, outputImage, param);
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> "+params.src+" "+params.dest+" "+ex.toString());
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> {0} {1} {2}", new Object[]{params.src, params.dest, ex.toString()});
}
jpgWriter.dispose();
Files.write(f.toPath(), baos.toByteArray());
} catch (FileNotFoundException ex) {
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> "+params.src+" "+params.dest+" "+ex.toString());
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> {0} {1} {2}", new Object[]{params.src, params.dest, ex.toString()});
} catch (IOException ex) {
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> "+params.src+" "+params.dest+" "+ex.toString());
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> {0} {1} {2}", new Object[]{params.src, params.dest, ex.toString()});
}
}

Expand All @@ -257,7 +286,16 @@ public static void Display(byte[] buffer, int from, int to) {
}
System.out.println("");
}


public short[] byte2short(byte[] byteArray) {
short[] shortArray = new short[byteArray.length+1];
for (int i = 0; i < shortArray.length-1; i++) {
shortArray[i] = (short) byteArray[i];
}
shortArray[shortArray.length-1] = 0x00;
return shortArray;
}

public void readWriteTiles() throws FormatException, IOException {
if (params.verbose) {
LOGGER.log(Level.INFO,"transferring image data...");
Expand All @@ -280,6 +318,9 @@ public void readWriteTiles() throws FormatException, IOException {
ifd.put(IFD.IMAGE_LENGTH, (long) height);
ifd.put(IFD.TILE_OFFSETS, new long[numtiles]);
ifd.put(IFD.TILE_BYTE_COUNTS, new long[numtiles]);
if (xmp!=null) {
ifd.putIFDValue(700, byte2short(xmp.getXMPString().getBytes(StandardCharsets.UTF_8)));
}
String comp = (String) reader.metadata.get("Compression");
if (comp==null) {
comp = "UNKNOWN";
Expand Down Expand Up @@ -362,6 +403,7 @@ public void readWriteTiles() throws FormatException, IOException {
time.Cumulative();
LOGGER.log(Level.INFO,"Generate image pyramid...");
}
ifd.remove(700);
ifd.remove(IFD.Y_CB_CR_SUB_SAMPLING);
ifd.remove(IFD.IMAGE_DESCRIPTION);
ifd.remove(IFD.SOFTWARE);
Expand All @@ -370,7 +412,7 @@ public void readWriteTiles() throws FormatException, IOException {
ifd.put(IFD.COMPRESSION, 7);
for (int s=1;s<depth;s++) {
if (params.verbose) {
LOGGER.log(Level.INFO,"Level : "+s+" of "+depth);
LOGGER.log(Level.INFO, "Level : {0} of {1}", new Object[]{s, depth});
}
if (params.verbose) {
LOGGER.log(Level.INFO,"Lump...");
Expand All @@ -381,12 +423,12 @@ public void readWriteTiles() throws FormatException, IOException {
}
pyramid.Shrink();
if (params.verbose) {
LOGGER.log(Level.INFO,pyramid.gettilesX()+" X "+pyramid.gettilesY());
LOGGER.log(Level.INFO,"Resolution S="+s+" "+pyramid.getWidth()+"x"+pyramid.getHeight());
LOGGER.log(Level.INFO, "{0} X {1}", new Object[]{pyramid.gettilesX(), pyramid.gettilesY()});
LOGGER.log(Level.INFO, "Resolution S={0} {1}x{2}", new Object[]{s, pyramid.getWidth(), pyramid.getHeight()});
}
writer.nextImage();
if (params.verbose) {
LOGGER.log(Level.INFO,"Writing level "+s+"...");
LOGGER.log(Level.INFO, "Writing level {0}...", s);
}
numtiles = pyramid.gettilesX()*pyramid.gettilesY();
ifd.put(IFD.NEW_SUBFILE_TYPE, 1L);
Expand All @@ -410,7 +452,7 @@ private BufferedImage byte2bi(byte[] buf) {
bb = AWTImageTools.makeImage(buf, reader.isInterleaved(), meta, 0);
return bb;
} catch (FormatException ex) {
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> "+params.src+" "+params.dest+" "+ex.toString());
LOGGER.log(Level.SEVERE, "FILE PROCESSOR ERROR --> {0} {1} {2}", new Object[]{params.src, params.dest, ex.toString()});
}
return bb;
}
Expand Down
Loading

0 comments on commit 5420fb1

Please sign in to comment.