diff --git a/pom.xml b/pom.xml index 7e0c9722..8073524c 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 com.ebremer Halcyon - 0.5.1 + 0.6.0 jar Halcyon A whole slide image annotation, management, and visualization system @@ -69,8 +69,8 @@ UTF-8 - 17 - 17 + 20 + 20 17 4.8.0 9.14.0 @@ -165,7 +165,6 @@ src\main\resources\META-INF\halcyon.ico dist - diff --git a/src/main/java/com/ebremer/ethereal/SelectDataProvider.java b/src/main/java/com/ebremer/ethereal/SelectDataProvider.java index 3d56c8c3..3c26dc7d 100644 --- a/src/main/java/com/ebremer/ethereal/SelectDataProvider.java +++ b/src/main/java/com/ebremer/ethereal/SelectDataProvider.java @@ -55,15 +55,15 @@ private void updateCount() { StopWatch w = new StopWatch(); Query q = getQuery(); Dataset ds = dds.load(); - ds.begin(ReadWrite.READ); QueryExecution qe = QueryExecutionFactory.create(q,ds); - ResultSet rs = qe.execSelect().materialise(); - ds.end(); + ds.begin(ReadWrite.READ); + ResultSet rs = qe.execSelect(); size = 0; while (rs.hasNext()) { rs.next(); size++; } + ds.end(); w.getTime("updateCount() "+size); } diff --git a/src/main/java/com/ebremer/halcyon/FL/FL.java b/src/main/java/com/ebremer/halcyon/FL/FL.java index b7e667b4..6a43600e 100644 --- a/src/main/java/com/ebremer/halcyon/FL/FL.java +++ b/src/main/java/com/ebremer/halcyon/FL/FL.java @@ -17,6 +17,7 @@ import com.ebremer.ns.IIIF; import com.ebremer.halcyon.imagebox.IIIFUtils; import static com.ebremer.halcyon.imagebox.IIIFUtils.IIIFAdjust; +import com.ebremer.halcyon.utils.StopWatch; import jakarta.json.Json; import jakarta.json.JsonArray; import jakarta.json.JsonObject; @@ -28,16 +29,12 @@ import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; import java.util.Collections; import java.util.HashMap; +import java.util.concurrent.Executors; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.LongStream; -import javax.imageio.ImageIO; import loci.formats.gui.AWTImageTools; import org.apache.commons.collections4.iterators.IteratorChain; import org.apache.jena.graph.Graph; @@ -55,11 +52,9 @@ import org.apache.jena.rdf.model.ResourceFactory; import org.apache.jena.riot.system.JenaTitanium; import org.apache.jena.sparql.vocabulary.DOAP; -import org.apache.jena.sys.JenaSystem; import org.apache.jena.vocabulary.OA; import org.apache.jena.vocabulary.RDF; import org.apache.jena.vocabulary.SchemaDO; -import org.slf4j.LoggerFactory; /** * @@ -77,7 +72,6 @@ public class FL { private final float[] ratios; public FL(Model m) { - System.out.println("Creating an FL Reader"); this.m = m; this.hspace = new HashMap<>(); this.classes = new HashMap<>(); @@ -100,7 +94,6 @@ public FL(Model m) { } else { throw new Error("Cannot find CreateAction/ROCrate"); } - //System.out.println("FEATURE WIDTH/HEIGHT : "+width+", "+height); pss = new ParameterizedSparqlString( """ select ?class where { @@ -168,34 +161,40 @@ public int getHeight() { return height; } + public int getBest(float r) { + int best = ratios.length-1; + float rr = 0.8f*ratios[best]; + while ((r0)) { + best--; + rr = 0.8f*ratios[best]; + } + return best; + } + public BufferedImage FetchImage(int x, int y, int w, int h, int tx, int ty) { //System.out.println("FetchImage : "+x+" "+y+" "+w+" "+h+" "+tx+" "+ty); float iratio = ((float) w)/((float) tx); - int layer = numscales-1; + int layer; float rr = 1.0f; if (hspace.size()==1) { layer = hspace.keySet().iterator().next(); } else { - float a = 0.8f*ratios[layer]; - while ((iratio0)) { - layer--; - a = 0.8f*ratios[layer]; - } + layer = getBest(iratio); rr = ratios[layer]; } - int gx=(int) (x/rr); - int gy=(int) (y/rr); - int gw=(int) (w/rr); - int gh=(int) (h/rr); + int gx=(int) Math.round(x/rr); + int gy=(int) Math.round(y/rr); + int gw=(int) Math.round(w/rr); + int gh=(int) Math.round(h/rr); IteratorChain rs = Search(gx, gy, gw, gh, layer); BufferedImage bi = generateImage(gx,gy,gw,gh,layer,rs); - bi = AWTImageTools.scale(bi, (int) Math.round(w/iratio), (int) Math.round(h/iratio), false); - return bi; + BufferedImage bix = AWTImageTools.scale(bi, (int) Math.round(w/iratio), (int) Math.round(h/iratio), false); + return bix; } public IteratorChain Search(int x, int y, int w, int h, int scale) { - //System.out.println("Search ( "+x+", "+y+" by "+w+", "+h+" scale -> "+scale+" )"); hsPolygon p = hspace.get(scale).Box(x, y, w, h); + //System.out.println("Search ( "+x+", "+y+" by "+w+"x"+h+" scale -> "+scale+" ) ---> "+p.getRanges().size()); ParameterizedSparqlString pss = new ParameterizedSparqlString( """ select distinct ?polygon ?low ?high ?class ?certainty where { @@ -231,20 +230,14 @@ public IteratorChain Search(int x, int y, int w, int h, int scale pss.setIri("plow", HAL.low.toString()+"/"+scale); pss.setIri("phigh", HAL.high.toString()+"/"+scale); pss.setNsPrefix("oa", OA.NS); - pss.setNsPrefix("hal", "https://www.ebremer.com/halcyon/ns/"); + pss.setNsPrefix("hal", HAL.NS); IteratorChain ic = new IteratorChain<>(); p.getRanges().forEach(r->{ pss.setLiteral("rlow", r.low()); pss.setLiteral("rhigh", r.high()); - //System.out.println(pss.toString()); - QueryExecution qe = QueryExecutionFactory.create(pss.toString(), m); - ResultSet rs = qe.execSelect(); - //System.out.println("********************************************"); - //ResultSetFormatter.out(System.out,rs); - //System.out.println("********************************************"); + ResultSet rs = QueryExecutionFactory.create(pss.toString(), m).execSelect(); ic.addIterator(rs); }); - //System.out.println("Do we have items at scale : "+scale+" "+ic.hasNext()); return ic; } @@ -254,34 +247,33 @@ public BufferedImage getImage(int x, int y, int w, int h, int scale) { } public BufferedImage generateImage(int x, int y, int w, int h, int scale, IteratorChain rs) { - //System.out.println("generateImage "+x+", "+y+" "+w+", "+h+" "+scale); + // System.out.println("generateImage "+x+", "+y+" "+w+", "+h+" "+scale); + //StopWatch sw = new StopWatch(); HilbertSpace hs = hspace.get(scale); BufferedImage bi = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = bi.createGraphics(); g2.setColor(new Color(128,0,128,128)); g2.fillRect(0, 0, w, h); - rs.forEachRemaining(qs->{ - long low = qs.get("low").asLiteral().getLong(); - long high = qs.get("high").asLiteral().getLong(); - float pc = qs.get("certainty").asLiteral().getFloat(); - int classid = classes.get(qs.get("class").asResource().getURI()); - // System.out.println(low+" "+high+" "+pc); - int prob = (int) (pc*255f+0.5); - int color = (0xFF000000)+(classid<<16)+(prob<<8); - LongStream.rangeClosed(low, high).forEach(k->{ - long[] point = hs.hc.point(k); - int a = (int)(point[0] - x); - int b = (int)(point[1] - y); - //System.out.println("PLOT : "+a+", "+b); - if ((a>=0)&&(b>=0)&&(b{ + long low = qs.get("low").asLiteral().getLong(); + long high = qs.get("high").asLiteral().getLong(); + //System.out.println(low+"->"+high); + float pc = qs.get("certainty").asLiteral().getFloat(); + int classid = classes.get(qs.get("class").asResource().getURI()); + int prob = (int) (pc*255f+0.5); + int color = (0xFF000000)+(classid<<16)+(prob<<8); + LongStream.rangeClosed(low, high).forEach(k->{ + long[] point = hs.hc.point(k); + int a = (int)(point[0] - x); + int b = (int)(point[1] - y); + try { + bi.setRGB(a, b, color); + } catch (java.lang.ArrayIndexOutOfBoundsException ex) { + //System.out.println("Out of Bounds "+w+","+h+" "+b+","+a); + } }); + }); + //sw.getLapseTime("genImage"); return bi; } @@ -309,53 +301,11 @@ public String GetImageInfo(String xurl) { mm.add(s,IIIF.sizes,size); mm.addLiteral(tiles, IIIF.scaleFactors,((int)(width/hspace.get(k).width))); }); -/* - for (int j=numscales-1;j>=0;j--) { - Resource size = mm.createResource(); - mm.addLiteral(size,IIIF.width,hspace.get(j).width); - mm.addLiteral(size,IIIF.height,hspace.get(j).height); - mm.add(s,IIIF.sizes,size); - mm.addLiteral(tiles, IIIF.scaleFactors,((int)(width/hspace.get(j).width))); - } - */ mm.add(s, IIIF.preferredFormats, "png"); mm.add(s, RDF.type, HAL.HalcyonROCrate); IIIFUtils.addSupport(s, mm); Model whoa = ModelFactory.createDefaultModel(); - //whoa.add(manifest); whoa.add(mm); - /* - UpdateRequest request = UpdateFactory.create(); - ParameterizedSparqlString pss = new ParameterizedSparqlString( - """ - delete {?s ?p ?o} - insert {?yay ?p ?o} - where { - ?s ?p ?o - filter(strstarts(str(?s),?base)) - bind(iri(concat(?newbase,substr(str(?s),?len))) as ?yay) - } - """); - pss.setLiteral("base", reference+"/"); - pss.setLiteral("newbase", xurl); - pss.setLiteral("len", reference.length()+1); - request.add(pss.toString()); - UpdateAction.execute(request,whoa); - pss = new ParameterizedSparqlString(""" - delete {?s ?p ?o} - insert {?s ?p ?yay} - where { - ?s ?p ?o - filter(strstarts(str(?o),?base)) - bind(iri(concat(?newbase,substr(str(?o),?len))) as ?yay) - } - """); - pss.setLiteral("base", reference+"/"); - pss.setLiteral("newbase", xurl); - pss.setLiteral("len", reference.length()+1); - request.add(pss.toString()); - UpdateAction.execute(request,whoa); -*/ mm.add(whoa); Dataset ds = DatasetFactory.createGeneral(); ds.getDefaultModel().add(mm); @@ -458,7 +408,6 @@ public String GetImageInfo(String xurl) { out.writeObject(jo); String hold = new String(baos.toByteArray()); hold = IIIFAdjust(hold); - // System.out.println("GetImageInfo ---> "+hold); return hold; } catch (JsonLdError ex) { Logger.getLogger(FL.class.getName()).log(Level.SEVERE, null, ex); @@ -466,64 +415,6 @@ public String GetImageInfo(String xurl) { return "{}"; } - public static void test2(Model m) { - ParameterizedSparqlString pss = new ParameterizedSparqlString( - """ - select * where { - ?s so:name ?name - } limit 10 - """); - pss.setNsPrefix("so", SchemaDO.NS); - pss.setNsPrefix("oa", OA.NS); - pss.setNsPrefix("hal", HAL.NS); - // System.out.println(pss.toString()); - QueryExecution qe = QueryExecutionFactory.create(pss.toString(), m); - ResultSet rs = qe.execSelect(); - ResultSetFormatter.out(System.out,rs); - } - - public static void test(Model m) { - ParameterizedSparqlString pss = new ParameterizedSparqlString( - """ -PREFIX oa: - PREFIX hal: - PREFIX so: - #select distinct ?polygon ?low ?high ?class ?certainty where { - select * where { - { - select * where { - ?range hal:low ?low . - ?range hal:high ?high . - ?polygon ?range . - ?annotation oa:hasSelector ?polygon . - ?annotation oa:hasBody ?body . - ?body hal:assertedClass ?class . - ?body hal:hasCertainty ?certainty . - filter(?low>=2147483648) - filter(?low<=2148532223) - } - } union { - #select ?polygon ?low ?high ?class ?certainty where { - select * where { - ?range hal:low ?low . - ?range hal:high ?high . - ?polygon ?range . - ?annotation oa:hasSelector ?polygon . - ?annotation oa:hasBody ?body . - ?body hal:assertedClass ?class . - ?body hal:hasCertainty ?certainty . - filter(?high>=2147483648) - filter(?high<=2148532223) - } - } - } #limit 20 - """); - // System.out.println(pss.toString()); - QueryExecution qe = QueryExecutionFactory.create(pss.toString(), m); - ResultSet rs = qe.execSelect(); - ResultSetFormatter.out(System.out,rs); - } - public static void ScanAll(Model m) { ParameterizedSparqlString pss = new ParameterizedSparqlString( """ @@ -536,68 +427,4 @@ public static void ScanAll(Model m) { ResultSet rs = qe.execSelect(); ResultSetFormatter.out(System.out,rs); } - - public static void main(String[] args) throws IOException, URISyntaxException { - ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); - root.setLevel(ch.qos.logback.classic.Level.OFF); - //String base = "http://www.ebremer.com/YAY"; - String base = "http://localhost:8888/halcyon/?iiif="; - //URI uri = new URI("file:///D:/data2/halcyon/hm.zip"); - //URI uri = new URI("file:///D:/HalcyonStorage/nuclearsegmentation2019/coad/TCGA-AA-3872-01Z-00-DX1.eb3732ee-40e3-4ff0-a42b-d6a85cfbab6a.zip"); - URI uri = new URI("file:///D:/HalcyonStorage/nuclearsegmentation2019/coad/TCGA-CM-5348-01Z-00-DX1.2ad0b8f6-684a-41a7-b568-26e97675cce9.zip"); - JenaSystem.init(); - BeakGraph g = new BeakGraph(uri); - Model m = ModelFactory.createModelForGraph(g); - - //ScanAll(m); - //test(m); - - - FL fl = new FL(m); - //ByteArrayOutputStream baos = new ByteArrayOutputStream(); - //sw.Lap("Start Search"); - //ResultSet rs = fl.Search(32768, 32768, 512, 512, 0); - //sw.Lap("Search Complete..."); - // ResultSetFormatter.out(System.out, rs); - //long middle = System.nanoTime(); - //BufferedImage bi = fl.getImage(32768, 32768, 512, 512, 0); - //BufferedImage bi = fl.getImage(32768, 32768, 1024, 1024, 1); - //BufferedImage bi = fl.FetchImage(32768, 32768, 1024, 1024, 1024, 1024); - //BufferedImage bi = fl.FetchImage(32768, 32768, 1024, 1024, 1024, 1024); -//BufferedImage bi = fl.FetchImage(0, 0, 505, 372, 505, 505); - - - BufferedImage bi = fl.FetchImage(32768, 32768, 32768, 32768, 512, 512); - - - //BufferedImage bi = fl.FetchImage(52000, 33000, 32192, 32192, 8192, 8192); - - //BufferedImage bi = fl.FetchImage(52000, 33000, 32192, 32192, 32768, 32768); - // BufferedImage bi = fl.FetchImage(52000, 33000, 32192, 32192, 16384, 16384); - // BufferedImage bi = fl.FetchImage(52000, 33000, 32192, 32192, 8192, 8192); - // BufferedImage bi = fl.FetchImage(52000, 33000, 32192, 32192, 4096, 4096); - //BufferedImage bi = fl.FetchImage(52000, 33000, 32192, 32192, 2048, 2048); - // BufferedImage bi = fl.FetchImage(52000, 33000, 32192, 32192, 1024, 1024); - - - //BufferedImage bi = fl.FetchImage(0, 0, 32192, 32192, 32768, 32768); - // BufferedImage bi = fl.FetchImage(0, 0, 32192, 32192, 16384, 16384); - File out = new File("d:\\data2\\halcyon\\bam.png"); - ImageIO.write(bi, "png", out); - // double mid = (middle-begin)/1000000000d; - - // System.out.println(mid); - // System.out.println(fl.GetImageInfo("http://www.halcyon.io/crap.zip")); - } } - - - // List sr = new ArrayList(p.getRanges().size()); - // System.out.println("# of range in selection : "+p.getRanges().size()); - // p.getRanges().forEach(r->{ - // sr.add( - // List.of( - // ResourceFactory.createTypedLiteral(r.low()), ResourceFactory.createTypedLiteral(r.high()) - // ) - // ); - // }); diff --git a/src/main/java/com/ebremer/halcyon/FL/FLKeyedPool.java b/src/main/java/com/ebremer/halcyon/FL/FLKeyedPool.java index be41fb31..415e9880 100644 --- a/src/main/java/com/ebremer/halcyon/FL/FLKeyedPool.java +++ b/src/main/java/com/ebremer/halcyon/FL/FLKeyedPool.java @@ -13,18 +13,15 @@ public class FLKeyedPool extends GenericKeyedObjectPool { public FLKeyedPool(FLPoolFactory factory, FLKeyedPoolConfig config) { super((BaseKeyedPooledObjectFactory)factory, config); - //System.out.println("Building FL Pool X..."); } @Override public FL borrowObject(final URI key) throws Exception { - //System.out.println("borrowObject : "+key.toString()); return (FL) super.borrowObject(key); } @Override public void returnObject(final URI key, final FL reader) { - //System.out.println("returnObject : "+key); super.returnObject(key, reader); } } diff --git a/src/main/java/com/ebremer/halcyon/FL/FLKeyedPoolConfig.java b/src/main/java/com/ebremer/halcyon/FL/FLKeyedPoolConfig.java index 4a050039..6555e48e 100644 --- a/src/main/java/com/ebremer/halcyon/FL/FLKeyedPoolConfig.java +++ b/src/main/java/com/ebremer/halcyon/FL/FLKeyedPoolConfig.java @@ -5,13 +5,14 @@ /** * * @author erich - * @param + * @param */ -public class FLKeyedPoolConfig extends GenericKeyedObjectPoolConfig { +public class FLKeyedPoolConfig extends GenericKeyedObjectPoolConfig { private String base = "https://xdummy.com/"; - public void setBase(String base) { + public FLKeyedPoolConfig setBase(String base) { this.base = base; + return this; } public String getBase() { diff --git a/src/main/java/com/ebremer/halcyon/FL/FLPoolFactory.java b/src/main/java/com/ebremer/halcyon/FL/FLPoolFactory.java index 35681d36..b2bd14d6 100644 --- a/src/main/java/com/ebremer/halcyon/FL/FLPoolFactory.java +++ b/src/main/java/com/ebremer/halcyon/FL/FLPoolFactory.java @@ -6,7 +6,6 @@ import org.apache.commons.pool2.DestroyMode; import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.impl.DefaultPooledObject; -import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; /** @@ -14,18 +13,18 @@ * @author erich */ public class FLPoolFactory extends BaseKeyedPooledObjectFactory { - private final String base; + //private final String base; public FLPoolFactory(String base) { - this.base = base; + // this.base = base; } @Override public FL create(URI uri) throws Exception { - System.out.println("Create FL "+uri+" with base : "+base); + System.out.println("Creating FL Reader..."+uri.toString()); BeakGraph g = new BeakGraph(uri); - Model m = ModelFactory.createModelForGraph(g); - FL fl = new FL(m); + FL fl = new FL(ModelFactory.createModelForGraph(g)); + System.out.println("FL Reader Created: "+uri.toString()); return fl; } @@ -36,7 +35,7 @@ public PooledObject wrap(FL value) { @Override public void destroyObject(URI key, PooledObject p, DestroyMode mode) throws Exception { - System.out.println("Destroying FL : "+mode); + System.out.println("Destroying FL Reader"); FL fl = (FL) p.getObject(); fl.close(); super.destroyObject(key, p, mode); diff --git a/src/main/java/com/ebremer/halcyon/HalcyonSettings.java b/src/main/java/com/ebremer/halcyon/HalcyonSettings.java index 24ee1b07..bb56f0b5 100644 --- a/src/main/java/com/ebremer/halcyon/HalcyonSettings.java +++ b/src/main/java/com/ebremer/halcyon/HalcyonSettings.java @@ -61,8 +61,8 @@ public final class HalcyonSettings { public static final int DEFAULTSPARQLPORT = 8887; public static final String DEFAULTHOSTNAME = "http://localhost"; public static final String DEFAULTHOSTIP = "0.0.0.0"; - public static final String VERSION = "0.5.1"; - public static Resource HALCYONAGENT = ResourceFactory.createResource(HAL.NS+"/VERSION/"+VERSION); + public static final String VERSION = "0.6.0"; + public static Resource HALCYONAGENT = ResourceFactory.createResource(HAL.NS+"VERSION/"+VERSION); private HalcyonSettings() { File f = new File(MasterSettingsLocation); diff --git a/src/main/java/com/ebremer/halcyon/imagebox/FeatureServer.java b/src/main/java/com/ebremer/halcyon/imagebox/FeatureServer.java index 87af12cc..e3ea1360 100644 --- a/src/main/java/com/ebremer/halcyon/imagebox/FeatureServer.java +++ b/src/main/java/com/ebremer/halcyon/imagebox/FeatureServer.java @@ -6,14 +6,13 @@ import com.ebremer.halcyon.HalcyonSettings; import com.ebremer.halcyon.FL.FL; import com.ebremer.halcyon.imagebox.Enums.ImageFormat; +import static com.ebremer.halcyon.imagebox.Enums.ImageFormat.JPG; +import static com.ebremer.halcyon.imagebox.Enums.ImageFormat.PNG; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; -import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.net.URISyntaxException; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; @@ -31,122 +30,126 @@ */ public class FeatureServer extends HttpServlet { - HalcyonSettings settings = HalcyonSettings.getSettings(); + private final HalcyonSettings settings; private final FLKeyedPool frp; public FeatureServer() { + settings = HalcyonSettings.getSettings(); FLKeyedPoolConfig config = new FLKeyedPoolConfig<>(); config.setBase(settings.getProxyHostName()+"/halcyon/?iiif="); frp = FLPool.getPool(config); } + public void ReportError(HttpServletResponse response, String msg) { + response.setContentType("application/json"); + try (PrintWriter jwriter=response.getWriter()) { + jwriter.append("{'error': '"+msg+"'}"); + } catch (IOException ex1) { + // connection probably closed + } catch (IllegalStateException ex1) { + // connection probably closed + } + } + @Override - protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws IOException { - String iiif = request.getParameter("iiif"); - if (iiif!=null) { - IIIFProcessor i = null; - try { - i = new IIIFProcessor(iiif); - } catch (URISyntaxException ex) { - Logger.getLogger(FeatureServer.class.getName()).log(Level.SEVERE, null, ex); - } - FL fr = null; - File f = new File(i.uri); - String target = f.getAbsolutePath(); + protected void doGet( HttpServletRequest request, HttpServletResponse response ) { + String iiif = request.getParameter("iiif"); + try { + IIIFProcessor i = new IIIFProcessor(iiif); try { - fr = (FL) frp.borrowObject(i.uri); + FL fr = (FL) frp.borrowObject(i.uri); frp.returnObject(i.uri, fr); - } catch (Exception ex) { - System.out.println(ex.toString()); - System.out.println("ERROR Starting FEA Reader : "+target); - } - if (i.tilerequest) { - if (i.fullrequest) { - i.x = 0; - i.y = 0; - i.w = fr.getWidth(); - i.h = fr.getHeight(); - } else { - if ((i.x+i.w)>fr.getWidth()) { - i.w = fr.getWidth()-i.x; + if (i.tilerequest) { + if (i.fullrequest) { + i.x = 0; + i.y = 0; + i.w = fr.getWidth(); + i.h = fr.getHeight(); + } else { + if ((i.x+i.w)>fr.getWidth()) { + i.w = fr.getWidth()-i.x; + } + if ((i.y+i.h)>fr.getHeight()) { + i.h = fr.getHeight()-i.y; + } } - if ((i.y+i.h)>fr.getHeight()) { - i.h = fr.getHeight()-i.y; - } - } - if (i.imageformat == ImageFormat.JSON) { - /* - String json = fr.FetchPolygons(i.x, i.y, i.w, i.h, i.tx, i.tx); - frp.returnObject(xid, fr); - response.setContentType("application/json"); - PrintWriter jwriter=response.getWriter(); - jwriter.append(json); - jwriter.flush(); -*/ - } else { - BufferedImage bi = fr.FetchImage(i.x, i.y, i.w, i.h, i.tx, i.tx); - ImageWriter writer; - ImageOutputStream imageOut; - byte[] imageInByte; - try ( - ServletOutputStream sos = response.getOutputStream(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ) { + if (i.imageformat == ImageFormat.JSON) { + /* + String json = fr.FetchPolygons(i.x, i.y, i.w, i.h, i.tx, i.tx); + frp.returnObject(xid, fr); + response.setContentType("application/json"); + PrintWriter jwriter=response.getWriter(); + jwriter.append(json); + jwriter.flush(); + */ + } else { + BufferedImage bi = fr.FetchImage(i.x, i.y, i.w, i.h, i.tx, i.tx); + ImageWriter writer; + ImageOutputStream imageOut; + byte[] imageInByte; switch (i.imageformat) { case JPG: writer = ImageIO.getImageWritersByFormatName("jpg").next(); JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null); jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); jpegParams.setCompressionQuality(0.7f); - imageOut=ImageIO.createImageOutputStream(baos); - writer.setOutput(imageOut); - writer.write(null,new IIOImage(bi,null,null),jpegParams); - baos.flush(); - imageInByte = baos.toByteArray(); - response.setContentType("image/jpg"); - response.setContentLength(imageInByte.length); - response.setHeader("Access-Control-Allow-Origin", "*"); - sos.write(imageInByte); + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + imageOut=ImageIO.createImageOutputStream(baos); + writer.setOutput(imageOut); + writer.write(null,new IIOImage(bi,null,null),jpegParams); + imageInByte = baos.toByteArray(); + response.setContentType("image/jpg"); + response.setContentLength(imageInByte.length); + response.setHeader("Access-Control-Allow-Origin", "*"); + try (ServletOutputStream sos = response.getOutputStream()) { + sos.write(imageInByte); + } catch (IOException ex) { + ReportError(response, "error writing feature image"); + } + } catch (IOException ex) { + ReportError(response, "error with ByteArrayOutputStream"); + } break; case PNG: writer = ImageIO.getImageWritersByFormatName("png").next(); ImageWriteParam pjpegParams = writer.getDefaultWriteParam(); - imageOut=ImageIO.createImageOutputStream(baos); - writer.setOutput(imageOut); - writer.write(null,new IIOImage(bi,null,null),pjpegParams); - baos.flush(); - imageInByte = baos.toByteArray(); - response.setContentType("image/png"); - response.setContentLength(imageInByte.length); - response.setHeader("Access-Control-Allow-Origin", "*"); - sos.write(imageInByte); + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + imageOut=ImageIO.createImageOutputStream(baos); + writer.setOutput(imageOut); + writer.write(null,new IIOImage(bi,null,null),pjpegParams); + imageInByte = baos.toByteArray(); + response.setContentType("image/png"); + response.setContentLength(imageInByte.length); + response.setHeader("Access-Control-Allow-Origin", "*"); + try (ServletOutputStream sos = response.getOutputStream()) { + sos.write(imageInByte); + } catch (IOException ex) { + ReportError(response, "error writing feature image"); + } + } catch (IOException ex) { + ReportError(response, "error with ByteArrayOutputStream"); + } break; default: - System.out.println("ERROR! Unknown format!!"); + System.out.println("Unknown format"); } } + } else if (i.inforequest) { + response.setContentType("application/json"); + try (PrintWriter writer = response.getWriter()) { + String id = settings.getProxyHostName()+"/halcyon/?iiif="+request.getParameter("iiif").substring(0, request.getParameter("iiif").length()-"/info.json".length()); + String blah = fr.GetImageInfo(id); + writer.append(blah); + writer.flush(); + } catch (IllegalStateException ex) { + // connection probably closed + } } - } else if (i.inforequest) { - response.setContentType("application/json"); - try (PrintWriter writer = response.getWriter()) { - String id = settings.getProxyHostName()+"/halcyon/?iiif="+request.getParameter("iiif").substring(0, request.getParameter("iiif").length()-"/info.json".length()); - String blah = fr.GetImageInfo(id); - writer.append(blah); - writer.flush(); - } - } - } else { - System.out.println("IIIF FAILURE!!!"); - } - } - - public static String getFullURL(HttpServletRequest request) { - StringBuilder requestURL = new StringBuilder(request.getRequestURL().toString()); - String queryString = request.getQueryString(); - if (queryString == null) { - return requestURL.toString(); - } else { - return requestURL.append('?').append(queryString).toString(); + } catch (Exception ex) { + ReportError(response, "ERROR Starting FEA Reader"); + } + } catch (URISyntaxException ex) { + ReportError(response, "bad iiif request"); } } } diff --git a/src/main/java/com/ebremer/halcyon/imagebox/ImageReaderPool.java b/src/main/java/com/ebremer/halcyon/imagebox/ImageReaderPool.java index 6502ed0b..7cab500c 100644 --- a/src/main/java/com/ebremer/halcyon/imagebox/ImageReaderPool.java +++ b/src/main/java/com/ebremer/halcyon/imagebox/ImageReaderPool.java @@ -15,7 +15,7 @@ public ImageReaderPool() {} public static synchronized ImageReaderKeyedPool getPool() { if (pool == null) { GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig<>(); - config.setMaxTotalPerKey(1); + config.setMaxTotalPerKey(5); config.setMinIdlePerKey(0); config.setMaxWait(Duration.ofMillis(60000)); config.setBlockWhenExhausted(true); diff --git a/src/main/java/com/ebremer/halcyon/imagebox/ImageServer.java b/src/main/java/com/ebremer/halcyon/imagebox/ImageServer.java index 4da3bb01..89b4269a 100644 --- a/src/main/java/com/ebremer/halcyon/imagebox/ImageServer.java +++ b/src/main/java/com/ebremer/halcyon/imagebox/ImageServer.java @@ -11,8 +11,6 @@ import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; @@ -29,10 +27,10 @@ * @author erich */ public class ImageServer extends HttpServlet { - HalcyonSettings settings = HalcyonSettings.getSettings(); - private static final long serialVersionUID = 1L; - static final ImageReaderKeyedPool pool = ImageReaderPool.getPool(); - Path fpath = Paths.get(System.getProperty("user.dir")+"/"+settings.getwebfiles()); + + private final HalcyonSettings settings = HalcyonSettings.getSettings(); + private final ImageReaderKeyedPool pool = ImageReaderPool.getPool(); + private final Path fpath = Paths.get(System.getProperty("user.dir")+"/"+settings.getwebfiles()); @Override protected void doGet( HttpServletRequest request, HttpServletResponse response ) { @@ -42,7 +40,7 @@ protected void doGet( HttpServletRequest request, HttpServletResponse response ) try { i = new IIIFProcessor(iiif); } catch (URISyntaxException ex) { - Logger.getLogger(ImageServer.class.getName()).log(Level.SEVERE, null, ex); + ReportError(response, "BAD URL"); } ImageTiler nt = null; String target = null; @@ -52,14 +50,14 @@ protected void doGet( HttpServletRequest request, HttpServletResponse response ) try { nt = (ImageTiler) pool.borrowObject(target); } catch (Exception ex) { - Logger.getLogger(ImageServer.class.getName()).log(Level.SEVERE, null, ex); + ReportError(response, "Can't get ImageTiler"); } } else if (i.uri.getScheme().startsWith("http")) { target = i.uri.toString(); try { nt = (ImageTiler) pool.borrowObject(target); } catch (Exception ex) { - Logger.getLogger(ImageServer.class.getName()).log(Level.SEVERE, null, ex); + ReportError(response, "Can't get ImageTiler"); } } else if (i.uri.getScheme().startsWith("file")) { File image = FileSystems.getDefault().provider().getPath(i.uri).toAbsolutePath().toFile(); @@ -67,10 +65,10 @@ protected void doGet( HttpServletRequest request, HttpServletResponse response ) try { nt = (ImageTiler) pool.borrowObject(target); } catch (Exception ex) { - Logger.getLogger(ImageServer.class.getName()).log(Level.SEVERE, null, ex); + ReportError(response, "Can't get ImageTiler"); } } else { - System.out.println("I'm so confused as to what I am looking at...."); + ReportError(response, "I'm so confused as to what I am looking at...."); } if (nt.isBorked()) { response.setContentType("application/json"); @@ -80,7 +78,7 @@ protected void doGet( HttpServletRequest request, HttpServletResponse response ) writer.append(nt.GetImageInfo()); writer.flush(); } catch (IOException ex) { - Logger.getLogger(ImageServer.class.getName()).log(Level.SEVERE, null, ex); + ReportError(response, "ImageTiler is borked"); } } else if (i.tilerequest) { BufferedImage originalImage; @@ -98,42 +96,50 @@ protected void doGet( HttpServletRequest request, HttpServletResponse response ) } } originalImage = nt.FetchImage(i.x, i.y, i.w, i.h, i.tx, i.tx); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - try (ServletOutputStream sos = response.getOutputStream()) { - if (i.imageformat == ImageFormat.JPG) { - ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); - JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null); - jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); - jpegParams.setCompressionQuality(0.7f); + if (i.imageformat == ImageFormat.JPG) { + ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); + JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null); + jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + jpegParams.setCompressionQuality(0.7f); + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { ImageOutputStream imageOut = ImageIO.createImageOutputStream(baos); writer.setOutput(imageOut); writer.write(null,new IIOImage(originalImage,null,null),jpegParams); baos.flush(); byte[] imageInByte = baos.toByteArray(); - baos.close(); - response.setContentType("image/jpg"); - response.setContentLength(imageInByte.length); - response.setHeader("Access-Control-Allow-Origin", "*"); - sos.write(imageInByte); - } else if (i.imageformat == ImageFormat.PNG) { - ImageWriter writer = ImageIO.getImageWritersByFormatName("png").next(); - ImageWriteParam pjpegParams = writer.getDefaultWriteParam(); + try (ServletOutputStream sos = response.getOutputStream()) { + response.setContentType("image/jpg"); + response.setContentLength(imageInByte.length); + response.setHeader("Access-Control-Allow-Origin", "*"); + sos.write(imageInByte); + } catch (IOException ex) { + ReportError(response, "error writing image"); + } + } catch (IOException ex) { + ReportError(response, "error creating ByteArrayOutputStream"); + } + } else if (i.imageformat == ImageFormat.PNG) { + ImageWriter writer = ImageIO.getImageWritersByFormatName("png").next(); + ImageWriteParam pjpegParams = writer.getDefaultWriteParam(); + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { ImageOutputStream imageOut=ImageIO.createImageOutputStream(baos); writer.setOutput(imageOut); writer.write(null,new IIOImage(originalImage,null,null),pjpegParams); baos.flush(); byte[] imageInByte = baos.toByteArray(); - baos.close(); - response.setContentType("image/png"); - response.setContentLength(imageInByte.length); - response.setHeader("Access-Control-Allow-Origin", "*"); - sos.write(imageInByte); + try (ServletOutputStream sos = response.getOutputStream()) { + response.setContentType("image/png"); + response.setContentLength(imageInByte.length); + response.setHeader("Access-Control-Allow-Origin", "*"); + sos.write(imageInByte); + } catch (IOException ex) { + ReportError(response, "error writing image"); + } + } catch (IOException ex) { + ReportError(response, "error creating ByteArrayOutputStream"); } - } catch (IOException ex) { - Logger.getLogger(ImageServer.class.getName()).log(Level.SEVERE, null, ex); } } else if (i.inforequest) { - //System.out.println("IMAGE INFORMATION REQUEST : "+request.getQueryString()); nt.setURL(request.getRequestURL().toString()+"?"+request.getQueryString()); nt.setURL(settings.getProxyHostName()+request.getRequestURI()+"?"+request.getQueryString()); response.setContentType("application/json"); @@ -142,25 +148,25 @@ protected void doGet( HttpServletRequest request, HttpServletResponse response ) writer.append(nt.GetImageInfo()); writer.flush(); } catch (IOException ex) { - Logger.getLogger(ImageServer.class.getName()).log(Level.SEVERE, null, ex); + ReportError(response, "issue writing info.json file"); } } else { System.out.println("unknown IIIF request"); } pool.returnObject(target, nt); } else { - + ReportError(response, "NO IIIF Parameter"); } } - public static String getFullURL(HttpServletRequest request) { - StringBuilder requestURL = new StringBuilder(request.getRequestURL().toString()); - String queryString = request.getQueryString(); - - if (queryString == null) { - return requestURL.toString(); - } else { - return requestURL.append('?').append(queryString).toString(); + public void ReportError(HttpServletResponse response, String msg) { + response.setContentType("application/json"); + try (PrintWriter jwriter=response.getWriter()) { + jwriter.append("{'error': '"+msg+"'}"); + } catch (IOException ex1) { + // connection probably closed + } catch (IllegalStateException ex1) { + // connection probably closed } } } diff --git a/src/main/java/com/ebremer/halcyon/server/Main.java b/src/main/java/com/ebremer/halcyon/server/Main.java index 0a176708..05c04d2b 100644 --- a/src/main/java/com/ebremer/halcyon/server/Main.java +++ b/src/main/java/com/ebremer/halcyon/server/Main.java @@ -70,11 +70,11 @@ public ServletRegistrationBean proxyServletRegistrationBean() { public UndertowServletWebServerFactory embeddedServletContainerFactory() { System.out.println("Configuring Undertow Web Engine..."); UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory(); - //int cores = Runtime.getRuntime().availableProcessors(); - //int ioThreads = cores*2; - //int taskThreads = 16*cores; - //System.out.println("ioThreads : "+ioThreads+"\ntaskThreads : "+taskThreads); - //factory.setIoThreads(ioThreads); + int cores = Runtime.getRuntime().availableProcessors(); + int ioThreads = cores; + int taskThreads = 16*cores; + System.out.println("ioThreads : "+ioThreads+"\ntaskThreads : "+taskThreads); + factory.setIoThreads(ioThreads); factory.setPort(settings.GetHTTPPort()); if (settings.isHTTPSenabled()) { factory.addBuilderCustomizers(builder -> { @@ -84,7 +84,7 @@ public UndertowServletWebServerFactory embeddedServletContainerFactory() { System.out.println("HTTPS PORT : "+settings.GetHTTPSPort()); builder .addHttpsListener(settings.GetHTTPSPort(), settings.GetHostIP(), ssl) - .setServerOption(UndertowOptions.ENABLE_HTTP2, false) + .setServerOption(UndertowOptions.ENABLE_HTTP2, true) .setServerOption(UndertowOptions.MAX_PARAMETERS, 100000) .setServerOption(UndertowOptions.MAX_CONCURRENT_REQUESTS_PER_CONNECTION, 100); } catch (Exception ex) { @@ -98,8 +98,7 @@ public UndertowServletWebServerFactory embeddedServletContainerFactory() { } @Bean - ServletRegistrationBean iboxServletRegistration () { - System.out.println("iboxServletRegistration order: "+Ordered.LOWEST_PRECEDENCE); + ServletRegistrationBean ImageServerRegistration () { ServletRegistrationBean srb = new ServletRegistrationBean(); srb.setOrder(Ordered.HIGHEST_PRECEDENCE+2); srb.setServlet(new ImageServer()); @@ -107,15 +106,18 @@ ServletRegistrationBean iboxServletRegistration () { return srb; } + @Bean + ServletRegistrationBean FeatureServerRegistration () { + ServletRegistrationBean srb = new ServletRegistrationBean(); + srb.setOrder(Ordered.HIGHEST_PRECEDENCE+3); + srb.setServlet(new FeatureServer()); + srb.setUrlMappings(Arrays.asList("/halcyon/*")); + return srb; + } + @Bean public FilterRegistrationBean KeycloakOIDCFilterFilterRegistration(){ - //filter.setSessionIdMapper(SessionsManager.getSessionsManager().getSessionIdMapper()); - //filter.setSessionIdMapper(getSessionIdMapper()); HALKeycloakOIDCFilter filter = new HALKeycloakOIDCFilter(); - //KeycloakOIDCFilterConfig config = new KeycloakOIDCFilterConfig("keycloak"); - //config.setInitParameter(KeycloakOIDCFilter.CONFIG_FILE_PARAM, "keycloak.json"); - //config.setInitParameter(KeycloakOIDCFilter.SKIP_PATTERN_PARAM, "(^/halcyon.*|^/viewer.*|^/rdf.*|^/hawkeye/.*|/;jsessionid=.*|/gui/images/halcyon.png|^/wicket/resource/.*|^/multi-viewer.*|^/iiif.*|^/|^/about|^/ListImages.*|^/wicket/resource/com.*\\.css||^/auth/.*|^/favicon.ico)"); - // filter.setConfig(config); FilterRegistrationBean registration = new FilterRegistrationBean<>(); registration.setName("keycloak"); registration.setFilter(filter); @@ -143,15 +145,6 @@ public FilterRegistrationBean wicketFilterRegistration(){ //registration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.FORWARD); return registration; } - - @Bean - ServletRegistrationBean HalcyonServletRegistration () { - ServletRegistrationBean srb = new ServletRegistrationBean(); - srb.setServlet(new FeatureServer()); - srb.setOrder(Ordered.HIGHEST_PRECEDENCE+3); - srb.setUrlMappings(Arrays.asList("/halcyon/*")); - return srb; - } @Configuration public class HalcyonResourceConfiguration implements WebMvcConfigurer { @@ -225,15 +218,3 @@ public static void main(String[] args) throws NoSuchAlgorithmException { System.out.println("===================== Welcome to Halcyon!"); } } - - - /* - @Bean - public FilterRegistrationBean headerAddingFilter() { - FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); - registrationBean.setFilter(new JwtInterceptor()); - registrationBean.addUrlPatterns("/*"); - registrationBean.setOrder(1); - return registrationBean; - } - */ \ No newline at end of file diff --git a/src/main/java/com/ebremer/halcyon/utils/StopWatch.java b/src/main/java/com/ebremer/halcyon/utils/StopWatch.java index 02ebde35..e6b775b1 100644 --- a/src/main/java/com/ebremer/halcyon/utils/StopWatch.java +++ b/src/main/java/com/ebremer/halcyon/utils/StopWatch.java @@ -44,4 +44,11 @@ public String getTime(String message) { System.out.println(stat); return stat; } + + public String getLapseTime(String message) { + String stat = "Elapsed: "+getElapsedTimeSecs()+" - "+message; + System.out.println(stat); + this.startTime = System.nanoTime(); + return stat; + } } diff --git a/src/main/java/com/ebremer/halcyon/wicket/ListImages.java b/src/main/java/com/ebremer/halcyon/wicket/ListImages.java index 8ddce67b..e17f3533 100644 --- a/src/main/java/com/ebremer/halcyon/wicket/ListImages.java +++ b/src/main/java/com/ebremer/halcyon/wicket/ListImages.java @@ -14,7 +14,6 @@ import com.ebremer.halcyon.gui.HalcyonSession; import com.ebremer.halcyon.pools.AccessCache; import com.ebremer.halcyon.pools.AccessCachePool; -import com.ebremer.halcyon.utils.StopWatch; import com.ebremer.multiviewer.MultiViewer; import com.ebremer.ns.EXIF; import java.util.HashSet; @@ -94,7 +93,7 @@ public void populateItem(Item> cellItem, String compone SelectDataProvider rdfsdf = new SelectDataProvider(ds,pss.toString()); pss.setIri("collection", "urn:halcyon:nocollections"); rdfsdf.SetSPARQL(pss.toString()); - AjaxFallbackDefaultDataTable table = new AjaxFallbackDefaultDataTable<>("table", columns, rdfsdf, 30); + AjaxFallbackDefaultDataTable table = new AjaxFallbackDefaultDataTable<>("table", columns, rdfsdf, 25); add(table); RDFDetachableModel rdg = new RDFDetachableModel(Patterns.getALLCollectionRDF()); LDModel ldm = new LDModel(rdg); @@ -103,7 +102,6 @@ public void populateItem(Item> cellItem, String compone new LoadableDetachableModel>() { @Override protected List load() { - //System.out.println("Load Images..."); org.apache.jena.rdf.model.Model ccc = ModelFactory.createDefaultModel(); try { HalcyonPrincipal p = HalcyonSession.get().getHalcyonPrincipal();