diff --git a/components/blitz/resources/omero/api/ThumbnailStore.ice b/components/blitz/resources/omero/api/ThumbnailStore.ice
index 9933f641836..47ba7d0262e 100644
--- a/components/blitz/resources/omero/api/ThumbnailStore.ice
+++ b/components/blitz/resources/omero/api/ThumbnailStore.ice
@@ -90,7 +90,8 @@ module omero {
* in the on-disk cache it will be returned directly,
* otherwise it will be created as in
* {@link #getThumbnailDirect}, placed in the on-disk
- * cache and returned.
+ * cache and returned. If the thumbnail is missing, a clock will
+ * be returned to signify that the thumbnail is yet to be generated.
*
* @param sizeX the X-axis width of the thumbnail.
* null
specifies the default size
@@ -112,6 +113,35 @@ module omero {
*/
idempotent Ice::ByteSeq getThumbnail(omero::RInt sizeX, omero::RInt sizeY) throws ServerError;
+ /**
+ * Retrieves a thumbnail for a pixels set using a given set of
+ * rendering settings (RenderingDef). If the thumbnail exists
+ * in the on-disk cache it will be returned directly,
+ * otherwise it will be created as in
+ * {@link #getThumbnailDirect}, placed in the on-disk
+ * cache and returned. If the thumbnail is still to be generated, an empty array will
+ * be returned.
+ *
+ * @param sizeX the X-axis width of the thumbnail.
+ * null
specifies the default size
+ * of 48.
+ * @param sizeY the Y-axis width of the thumbnail.
+ * null
specifies the default size
+ * of 48.
+ * @throws ApiUsageException
+ * if:
+ *
sizeX
> pixels.sizeXsizeX
is negativesizeY
> pixels.sizeYsizeY
is negativenull
specifies the default size
+ * of 48.
+ * @param sizeY the Y-axis width of the thumbnail.
+ * null
specifies the default size
+ * of 48.
+ * @throws ApiUsageException
+ * if:
+ * sizeX
> pixels.sizeXsizeX
is negativesizeY
> pixels.sizeYsizeY
is negativenull
.
* @param userID The id of the user the thumbnail is for.
* Must be positive.
- * @param validImage Pass true
if the image is a real image,
+ * @param validImage Pass true
if the image is a real image,
* false
otherwise.
*/
- public ThumbnailData(long imageID, BufferedImage thumbnail, long userID,
- boolean validImage)
+ public ThumbnailData(long imageID, Image thumbnail, long userID,
+ boolean validImage)
{
- if (imageID <= 0)
+ if (imageID <= 0)
throw new IllegalArgumentException("Non-positive image id: "+
imageID+".");
this.imageID = imageID;
- this.thumbnail = thumbnail;
+ this.thumbnail = toBufferedImage(thumbnail);
this.userID = userID;
this.validImage = validImage;
requirePyramid = null;
}
-
+
/**
* Creates a new instance.
- *
+ *
* @param imageID The id of the image to which the thumbnail belong.
* Must be positive.
* @param thumbnail The thumbnail pixels. Mustn't be null
.
- * @param validImage Pass true
if the image is a real image,
+ * @param validImage Pass true
if the image is a real image,
* false
otherwise.
*/
- public ThumbnailData(long imageID, BufferedImage thumbnail,
+ public ThumbnailData(long imageID, Image thumbnail,
boolean validImage)
{
this(imageID, thumbnail, -1, validImage);
}
-
+
/**
* Creates a new instance.
- *
+ *
* @param refOjbect The object of reference. Mustn't be null
.
* @param thumbnail The thumbnail pixels. Mustn't be null
.
- * @param validImage Passed true
if it is a valid image,
+ * @param validImage Passed true
if it is a valid image,
* false
otherwise.
*/
- public ThumbnailData(omero.gateway.model.DataObject refOjbect, BufferedImage thumbnail,
+ public ThumbnailData(omero.gateway.model.DataObject refOjbect, Image thumbnail,
boolean validImage)
{
if (refOjbect == null)
@@ -126,13 +128,13 @@ public ThumbnailData(omero.gateway.model.DataObject refOjbect, BufferedImage thu
throw new IllegalArgumentException("Type not valid.");
this.refObject = refOjbect;
this.validImage = validImage;
- this.thumbnail = thumbnail;
+ this.thumbnail = toBufferedImage(thumbnail);
requirePyramid = null;
}
-
+
/**
* Creates a new instance.
- *
+ *
* @param refOjbect The object of reference. Mustn't be null
.
* @param requirePyramid Pass true
if a pyramid is required,
* false
otherwise.
@@ -142,10 +144,10 @@ public ThumbnailData(omero.gateway.model.DataObject refOjbect, Boolean requirePy
this(refOjbect, null, false);
this.requirePyramid = requirePyramid;
}
-
+
/**
* Creates a new instance.
- *
+ *
* @param refOjbect The object of reference. Mustn't be null
.
* @param thumbnail The thumbnail pixels. Mustn't be null
.
*/
@@ -153,43 +155,43 @@ public ThumbnailData(omero.gateway.model.DataObject refOjbect, BufferedImage thu
{
this(refOjbect, thumbnail, true);
}
-
+
/**
* Sets the time the flag indicating if the image requires a pyramid to be
* built.
- *
+ *
* @param requirePyramid The value to set.
*/
public void setBackOffForPyramid(Boolean requirePyramid)
{
this.requirePyramid = requirePyramid;
}
-
+
/**
* Sets the exception thrown when trying to create a thumbnail.
- *
+ *
* @param error The exception to set.
*/
public void setError(Exception error) { this.error = error; }
-
+
/**
* Returns the exception.
- *
+ *
* @return See above.
*/
public Exception getError() { return error; }
-
- /**
+
+ /**
* Sets the image.
- *
+ *
* @param image The image to set.
*/
public void setImage(ImageData image) { this.image = image; }
-
+
/**
* Clones this object.
* This is a deep-copy, the thumbnail pixels are cloned too.
- *
+ *
* @see org.openmicroscopy.shoola.env.data.model.DataObject#makeNew()
*/
public DataObject makeNew()
@@ -197,7 +199,7 @@ public DataObject makeNew()
BufferedImage pixClone = null;
if (thumbnail != null) {
pixClone = new BufferedImage( thumbnail.getWidth(),
- thumbnail.getHeight(),
+ thumbnail.getHeight(),
thumbnail.getType());
Graphics2D g2D = pixClone.createGraphics();
g2D.drawImage(thumbnail, null, 0, 0);
@@ -216,58 +218,71 @@ public DataObject makeNew()
}
/**
- * Returns true
if the image is a real image,
+ * Returns true
if the image is a real image,
* false
otherwise.
- *
+ *
* @return See above.
*/
public boolean isValidImage() { return validImage; }
-
+
/**
* Returns the id of the user.
- *
+ *
* @return See above.
*/
public long getUserID() { return userID; }
-
+
/**
* Returns the id of the image to which the thumbnail belong.
- *
+ *
* @return See above.
*/
public long getImageID() { return imageID; }
-
+
/**
* Returns the thumbnail pixels.
- *
+ *
* @return See above.
*/
public BufferedImage getThumbnail() { return thumbnail; }
-
+
/**
* Returns the image.
- *
+ *
* @return See above.
*/
public ImageData getImage() { return image; }
-
+
/**
* Returns the object of reference.
- *
+ *
* @return See above.
*/
public omero.gateway.model.DataObject getRefObject() { return refObject; }
-
+
/**
* Returns true
if a pyramid is required, false
* otherwise.
- *
+ *
* @return See above.
*/
public Boolean requirePyramid()
- {
+ {
if (requirePyramid != null) return requirePyramid.booleanValue();
return null;
}
+ /**
+ * Converts a given Image into a BufferedImage
+ *
+ * @param img The Image to be converted
+ * @return The converted BufferedImage
+ */
+ public static BufferedImage toBufferedImage(Image img) {
+ if (img instanceof BufferedImage) {
+ return (BufferedImage) img;
+ }
+ return Factory.createImage(img);
+ }
+
}
diff --git a/components/insight/SRC/org/openmicroscopy/shoola/env/data/views/DataManagerViewImpl.java b/components/insight/SRC/org/openmicroscopy/shoola/env/data/views/DataManagerViewImpl.java
index b0b332f6f45..901d1dfddae 100644
--- a/components/insight/SRC/org/openmicroscopy/shoola/env/data/views/DataManagerViewImpl.java
+++ b/components/insight/SRC/org/openmicroscopy/shoola/env/data/views/DataManagerViewImpl.java
@@ -141,8 +141,7 @@ public CallHandle countContainerItems(SecurityContext ctx, Set rootIDs,
public CallHandle loadThumbnail(SecurityContext ctx, ImageData image,
int maxWidth, int maxHeight, long userID, AgentEventListener observer)
{
- BatchCallTree cmd = new ThumbnailLoader(ctx, image, maxWidth, maxHeight,
- userID);
+ BatchCallTree cmd = new ThumbnailLoader(ctx, image, maxWidth, maxHeight, userID);
return cmd.exec(observer);
}
diff --git a/components/insight/SRC/org/openmicroscopy/shoola/env/data/views/HierarchyBrowsingViewImpl.java b/components/insight/SRC/org/openmicroscopy/shoola/env/data/views/HierarchyBrowsingViewImpl.java
index 9b232bf4919..93394ddc637 100644
--- a/components/insight/SRC/org/openmicroscopy/shoola/env/data/views/HierarchyBrowsingViewImpl.java
+++ b/components/insight/SRC/org/openmicroscopy/shoola/env/data/views/HierarchyBrowsingViewImpl.java
@@ -65,18 +65,18 @@ public CallHandle loadHierarchy(SecurityContext ctx, Class rootNodeType,
/**
* Implemented as specified by the view interface.
- * @see HierarchyBrowsingView#loadThumbnails(Collection, int, int, long,
- * AgentEventListener)
+ * @see HierarchyBrowsingView#loadThumbnails(SecurityContext, Collection, int, int, long, int, AgentEventListener)
*/
public CallHandle loadThumbnails(SecurityContext ctx,
CollectionAs thumbnails are retrieved from OMERO, they're posted back to the + *
As thumbnails are retrieved from OMERO, they're posted back to the
* caller through DSCallFeedbackEvent
s. Each thumbnail will be
* posted in a single event; the caller can then invoke the
* getPartialResult
method to retrieve a ThumbnailData
@@ -62,395 +59,305 @@
* original image and so that their area doesn't exceed maxWidth*
* maxHeight
, which is specified to the constructor.
[index]
.
- *
- * @param pxd The image the thumbnail for.
- * @param userID The id of the user the thumbnail is for.
- * @param store The thumbnail store to use.
- * @param imageID The id of the image associated to the pixels set.
+ * Collection of user IDs.
*/
- private void loadThumbail(PixelsData pxd, long userID,
- ThumbnailStorePrx store, boolean last, long imageID)
- {
- BufferedImage thumbPix = null;
- boolean valid = true;
- int sizeX = maxWidth, sizeY = maxHeight;
- try {
- if (asImage) {
- sizeX = pxd.getSizeX();
- sizeY = pxd.getSizeY();
- } else {
- Dimension d = Factory.computeThumbnailSize(sizeX, sizeY,
- pxd.getSizeX(), pxd.getSizeY());
- sizeX = d.width;
- sizeY = d.height;
- }
-
- if (!store.setPixelsId(pxd.getId())) {
- store.resetDefaults();
- store.setPixelsId(pxd.getId());
- }
- if (userID >= 0) {
- long rndDefId = service.getRenderingDef(ctx,
- pxd.getId(), userID);
- // the user might not have own rendering settings
- // for this image
- if (rndDefId >= 0)
- store.setRenderingDefId(rndDefId);
- }
- thumbPix = WriterImage.bytesToImage(
- store.getThumbnail(omero.rtypes.rint(sizeX),
- omero.rtypes.rint(sizeY)));
- } catch (Throwable e) {
- thumbPix = null;
- LogMessage msg = new LogMessage();
- msg.print("Cannot retrieve thumbnail");
- msg.print(e);
- context.getLogger().error(this, msg);
- } finally {
- if (last) {
- context.getDataService().closeService(ctx, store);
- }
- }
- if (thumbPix == null) {
- valid = false;
- thumbPix = Factory.createDefaultImageThumbnail(sizeX, sizeY);
- }
- currentThumbnail = new ThumbnailData(imageID, thumbPix, userID, valid);
- }
+ private Collection[index]
.
+ *
+ * @param pxd The image the thumbnail for.
+ * @param userId The id of the user the thumbnail is for.
+ * @param store The thumbnail store to use.
*/
- public ThumbnailLoader(SecurityContext ctx, long pixelsID, int maxWidth,
- int maxHeight, long userID)
- {
- if (maxWidth <= 0)
- throw new IllegalArgumentException(
- "Non-positive id: "+pixelsID+".");
- if (maxWidth <= 0)
- throw new IllegalArgumentException(
- "Non-positive width: "+maxWidth+".");
- if (maxHeight <= 0)
- throw new IllegalArgumentException(
- "Non-positive height: "+maxHeight+".");
- this.ctx = ctx;
- pixelsCall = true;
- this.maxWidth = maxWidth;
- this.maxHeight = maxHeight;
- this.pixelsID = pixelsID;
- userIDs = new HashSet+ * Use this instead of String.compareTo() for a non-lexicographical + * comparison that works for version strings. e.g. "1.10".compareTo("1.6"). + *
+ * Note: It does not work if "1.10" is supposed to be equal to "1.10.0".
+ *
+ * @param str1 a string of ordinal numbers separated by decimal points.
+ * @param str2 a string of ordinal numbers separated by decimal points.
+ * @return The result is a negative integer if str1 is _numerically_ less than str2.
+ * The result is a positive integer if str1 is _numerically_ greater than str2.
+ * The result is zero if the strings are _numerically_ equal.
+ */
+ public static int compare(String str1, String str2) {
+ String[] vals1 = str1.split("\\.");
+ String[] vals2 = str2.split("\\.");
+ int i = 0;
+ // set index to first non-equal ordinal or length of shortest version string
+ while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) {
+ i++;
+ }
+ // compare first non-equal ordinal number
+ if (i < vals1.length && i < vals2.length) {
+ int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i]));
+ return Integer.signum(diff);
+ }
+ // the strings are equal or one string is a substring of the other
+ // e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4"
+ return Integer.signum(vals1.length - vals2.length);
+ }
+
+}
diff --git a/components/server/src/ome/services/ThumbnailBean.java b/components/server/src/ome/services/ThumbnailBean.java
index 3cd73336431..8007fc05f90 100644
--- a/components/server/src/ome/services/ThumbnailBean.java
+++ b/components/server/src/ome/services/ThumbnailBean.java
@@ -481,9 +481,8 @@ public void setSettingsService(IRenderingSettings settingsService) {
* @throws IOException
* if there is a problem writing to disk.
*/
- private void compressThumbnailToDisk(Thumbnail thumb, BufferedImage image)
- throws IOException {
-
+ private void compressThumbnailToDisk(Thumbnail thumb, BufferedImage image, boolean inProgress)
+ throws IOException {
if (diskSpaceChecking) {
iRepositoryInfo.sanityCheckRepository();
}
@@ -491,7 +490,7 @@ private void compressThumbnailToDisk(Thumbnail thumb, BufferedImage image)
FileOutputStream stream = ioService.getThumbnailOutputStream(thumb);
try {
if (inProgress) {
- compressInProgressImageToStream(thumb, stream);
+ compressInProgressImageToStream(thumb, stream, inProgressImageResource);
} else {
compressionService.compressToStream(image, stream);
}
@@ -502,45 +501,48 @@ private void compressThumbnailToDisk(Thumbnail thumb, BufferedImage image)
/**
* Compresses the in progress image to a stream.
- * @param thumb The thumbnail metadata.
+ *
+ * @param thumb Thumbnail meta data
* @param outputStream Stream to compress the data to.
+ * @param inProgressImageResource The image file (located in resources) to write to disk
+ * @throws IOException
*/
- private void compressInProgressImageToStream(
- Thumbnail thumb, OutputStream outputStream) {
- int x = thumb.getSizeX();
- int y = thumb.getSizeY();
- StopWatch s1 = new Slf4JStopWatch("omero.transcodeSVG");
- try
- {
- SVGRasterizer rasterizer = new SVGRasterizer(
- inProgressImageResource.getInputStream());
- // Batik will automatically maintain the aspect ratio of the
- // resulting image if we only specify the width or height.
- if (x > y)
- {
- rasterizer.setImageWidth(x);
- }
- else
- {
- rasterizer.setImageHeight(y);
- }
- rasterizer.setQuality(compressionService.getCompressionLevel());
- rasterizer.createJPEG(outputStream);
- s1.stop();
- }
- catch (IOException e1)
- {
- String s = "Error loading in-progress image from Spring resource.";
- log.error(s, e1);
- throw new ResourceError(s);
- }
- catch (TranscoderException e2)
- {
- String s = "Error transcoding in progress SVG.";
- log.error(s, e2);
- throw new ResourceError(s);
- }
- }
+ private void compressInProgressImageToStream(Thumbnail thumb, OutputStream outputStream,
+ Resource inProgressImageResource) {
+ int x = thumb.getSizeX();
+ int y = thumb.getSizeY();
+ StopWatch s1 = new Slf4JStopWatch("omero.transcodeSVG");
+ try
+ {
+ SVGRasterizer rasterizer = new SVGRasterizer(
+ inProgressImageResource.getInputStream());
+ // Batik will automatically maintain the aspect ratio of the
+ // resulting image if we only specify the width or height.
+ if (x > y)
+ {
+ rasterizer.setImageWidth(x);
+ }
+ else
+ {
+ rasterizer.setImageHeight(y);
+ }
+ rasterizer.setQuality(compressionService.getCompressionLevel());
+ rasterizer.createJPEG(outputStream);
+ s1.stop();
+ }
+ catch (IOException e1)
+ {
+ String s = "Error loading in-progress image from Spring resource.";
+ log.error(s, e1);
+ throw new ResourceError(s);
+ }
+ catch (TranscoderException e2)
+ {
+ String s = "Error transcoding in progress SVG.";
+ log.error(s, e2);
+ throw new ResourceError(s);
+ }
+ }
/**
* Checks that sizeX and sizeY are not out of range for the active pixels
@@ -819,10 +821,26 @@ public void createThumbnail(Integer sizeX, Integer sizeY)
}
}
- /** Actually does the work specified by {@link #createThumbnail(Integer, Integer)}. */
+ /**
+ * Calls {@code _createThumbnail(Thumbnail thumbMetaData)} with the local
+ * variable {@code thumbnailMetadata} as the input parameter.
+ *
+ * @return thumbnail object
+ */
private Thumbnail _createThumbnail() {
+ // For old times sake
+ return _createThumbnail(thumbnailMetadata);
+ }
+
+ /**
+ * Actually does the work specified by {@link #createThumbnail(Integer, Integer)}.
+ *
+ * @param thumbMetaData Thumbnail meta data object
+ * @return
+ */
+ private Thumbnail _createThumbnail(Thumbnail thumbMetaData) {
StopWatch s1 = new Slf4JStopWatch("omero._createThumbnail");
- if (thumbnailMetadata == null) {
+ if (thumbMetaData == null) {
throw new ValidationException("Missing thumbnail metadata.");
} else if (ctx.dirtyMetadata(pixels.getId())) {
// Increment the version of the thumbnail so that its
@@ -831,7 +849,7 @@ private Thumbnail _createThumbnail() {
// implemented using IUpdate.touch() or similar once that
// functionality exists.
//Check first if the thumbnail is the one of the settings owner
- Long ownerId = thumbnailMetadata.getDetails().getOwner().getId();
+ Long ownerId = thumbMetaData.getDetails().getOwner().getId();
Long rndOwnerId = settings.getDetails().getOwner().getId();
final Long rndGroupId = settings.getDetails().getGroup().getId();
final Map