<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../../jacoco-resources/report.gif" type="image/gif"/><title>EditableImage.java</title><link rel="stylesheet" href="../../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../../index.html" class="el_report">Mistral Examples CustomOperation</a> > <a href="../index.html" class="el_bundle">image-core</a> > <a href="index.source.html" class="el_package">it.tidalwave.image</a> > <span class="el_source">EditableImage.java</span></div><h1>EditableImage.java</h1><pre class="source lang-java linenums">/*
* *********************************************************************************************************************
*
* Mistral: open source imaging engine
* http://tidalwave.it/projects/mistral
*
* Copyright (C) 2003 - 2023 by Tidalwave s.a.s. (http://tidalwave.it)
*
* *********************************************************************************************************************
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* *********************************************************************************************************************
*
* git clone https://bitbucket.org/tidalwave/mistral-src
* git clone https://github.com/tidalwave-it/mistral-src
*
* *********************************************************************************************************************
*/
package it.tidalwave.image;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.io.IOException;
import java.io.Serializable;
import javax.imageio.ImageIO;
import javax.imageio.metadata.IIOMetadata;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import it.tidalwave.util.Key;
import it.tidalwave.util.TypeSafeMap;
import it.tidalwave.image.metadata.Directory;
import it.tidalwave.image.metadata.EXIF;
import it.tidalwave.image.metadata.IPTC;
import it.tidalwave.image.metadata.MakerNote;
import it.tidalwave.image.metadata.TIFF;
import it.tidalwave.image.metadata.XMP;
import it.tidalwave.image.op.AbstractCreateOp;
import it.tidalwave.image.op.AccessorOp;
import it.tidalwave.image.op.ImplementationFactoryRegistry;
import it.tidalwave.image.op.Operation;
import it.tidalwave.image.op.OperationImplementation;
import it.tidalwave.image.op.ReadOp;
import it.tidalwave.image.op.ScaleOp;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
/***********************************************************************************************************************
*
* An opaque class which encapsulates all the image manipulation logics, and allows the implementation of these logics
* to be transparently changed (e.g. by using or not JAI, etc...)
*
* @author Fabrizio Giudici
*
**********************************************************************************************************************/
<span class="fc" id="L77">@ToString(of = {"imageModelHolder", "attributeMapByName"}) @Slf4j</span>
public final class EditableImage implements Cloneable, Serializable // Externalizable
{
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
<span class="fc" id="L84"> @RequiredArgsConstructor</span>
public static enum DataType
{
<span class="fc" id="L87"> BYTE(DataBuffer.TYPE_BYTE),</span>
<span class="fc" id="L88"> UNSIGNED_SHORT(DataBuffer.TYPE_USHORT),</span>
<span class="fc" id="L89"> SHORT(DataBuffer.TYPE_SHORT),</span>
<span class="fc" id="L90"> INT(DataBuffer.TYPE_INT),</span>
<span class="fc" id="L91"> FLOAT(DataBuffer.TYPE_FLOAT),</span>
<span class="fc" id="L92"> DOUBLE(DataBuffer.TYPE_DOUBLE),</span>
<span class="fc" id="L93"> UNDEFINED(DataBuffer.TYPE_UNDEFINED);</span>
<span class="nc" id="L95"> @Getter</span>
private final int value;
/***************************************************************************************************************
*
* Returns the size in bits of this data type.
*
**************************************************************************************************************/
@Nonnegative
public int getSize()
{
<span class="fc" id="L106"> return DataBuffer.getDataTypeSize(value);</span>
}
/***************************************************************************************************************
*
*
**************************************************************************************************************/
@Nonnull
public static DataType valueOf (final int value)
{
<span class="pc bpc" id="L116" title="1 of 2 branches missed."> for (final var dataType : DataType.values())</span>
{
<span class="fc bfc" id="L118" title="All 2 branches covered."> if (dataType.value == value)</span>
{
<span class="fc" id="L120"> return dataType;</span>
}
}
<span class="nc" id="L124"> return EditableImage.DataType.UNDEFINED;</span>
}
}
<span class="pc bpc" id="L128" title="1 of 2 branches missed."> @RequiredArgsConstructor</span>
public static class Accessor // FIXME: protected
{
@Nonnull
private final EditableImage image;
public void setIIOMetadata (@Nonnull final IIOMetadata iioMetadata)
{
<span class="fc" id="L136"> image.iioMetadata = iioMetadata;</span>
<span class="fc" id="L137"> }</span>
@Nonnull
public Map<Class<? extends Directory>, List<Directory>> getMetadataMapByClass ()
{
<span class="fc" id="L142"> return image.metadataMapByClass;</span>
}
public void setLatestOperationDuration (@Nonnull final Duration latestOperationDuration)
{
<span class="fc" id="L147"> image.latestOperationDuration = latestOperationDuration;</span>
<span class="fc" id="L148"> }</span>
}
<span class="pc" id="L151"> private final AccessorOp accessor = new AccessorOp(this);</span>
private static final long serialVersionUID = -4524534539832240717L;
<span class="fc" id="L154"> private static final String CLASS = EditableImage.class.getName();</span>
<span class="fc" id="L156"> public static final Key<String> PROP_FORMAT = Key.of(CLASS + ".format", String.class);</span>
<span class="fc" id="L158"> public static final Key<String> PROP_MIME_TYPE = Key.of(CLASS + ".mimeType", String.class);</span>
/** The current image model. */
private ImageModelHolder imageModelHolder;
/** The metadata as it comes from Image I/O. */
private transient IIOMetadata iioMetadata; // TODO make it serializable
<span class="pc" id="L166"> private final Map<Class<? extends Directory>, List<Directory>> metadataMapByClass = new HashMap<>();</span>
/** The attributes. */
<span class="pc" id="L169"> @Nonnull</span>
<span class="pc" id="L170"> private TypeSafeMap attributeMapByName = TypeSafeMap.newInstance();</span>
private Duration latestOperationDuration;
@Nonnegative
private int latestSerializationSize;
/*******************************************************************************************************************
*
* For serialization only. Do not use.
*
******************************************************************************************************************/
public EditableImage()
<span class="nc" id="L183"> {</span>
// By default put empty objects for which isAvailable() returns false
<span class="nc" id="L185"> metadataMapByClass.put(TIFF.class, List.of(new TIFF()));</span>
<span class="nc" id="L186"> metadataMapByClass.put(EXIF.class, List.of(new EXIF()));</span>
<span class="nc" id="L187"> metadataMapByClass.put(IPTC.class, List.of(new IPTC()));</span>
<span class="nc" id="L188"> metadataMapByClass.put(XMP.class, List.of(new XMP()));</span>
<span class="nc" id="L189"> metadataMapByClass.put(MakerNote.class, List.of(new MakerNote()));</span>
<span class="nc" id="L190"> }</span>
/*******************************************************************************************************************
*
* For inner implementation only. Do not use.
*
******************************************************************************************************************/
public EditableImage (final ImageModel imageModel) // FIXME: try to make it protected
<span class="fc" id="L198"> {</span>
// null imageModel is accepted for instances carrying only metadata
<span class="fc" id="L200"> imageModelHolder = ImageModelHolder.wrap(imageModel);</span>
<span class="fc" id="L201"> }</span>
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void setNickName (final @Nonnull String nickName)
{
<span class="nc bnc" id="L209" title="All 2 branches missed."> if (imageModelHolder != null)</span>
{
<span class="nc" id="L211"> imageModelHolder.setNickName(nickName);</span>
}
<span class="nc" id="L213"> }</span>
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
@Nonnull
public Optional<String> getNickName()
{
<span class="nc bnc" id="L222" title="All 2 branches missed."> return (imageModelHolder != null) ? Optional.ofNullable(imageModelHolder.getNickName()) : Optional.empty();</span>
}
/*******************************************************************************************************************
*
* Creates a new EditableImage as specified by the parameter
*
* @param createOp the way the image should be created
* @return the image
*
******************************************************************************************************************/
@Nonnull
public static EditableImage create (@Nonnull final AbstractCreateOp createOp)
{
<span class="fc" id="L236"> final var editableImage = new EditableImage(null);</span>
<span class="fc" id="L237"> final var image = editableImage.internalExecute(createOp);</span>
<span class="fc" id="L238"> final var imageModel = ImplementationFactoryRegistry.getDefault().createImageModel(image);</span>
<span class="fc" id="L239"> editableImage.imageModelHolder = ImageModelHolder.wrap(imageModel);</span>
<span class="fc" id="L241"> return editableImage;</span>
}
/*******************************************************************************************************************
*
* Reads a new EditableImage as specified by the parameter
*
* @param readOp the way the image should be read
* @return the image
*
******************************************************************************************************************/
// FIXME: merge with create(AbstractCreateOp), introduce ReadJ2DOp
@Nonnull
public static EditableImage create (@Nonnull final ReadOp readOp)
throws IOException
{
<span class="fc" id="L257"> return readOp.execute();</span>
}
/*******************************************************************************************************************
*
* Returns true if the image has a raster (EditableImages can be loaded with
* metadata only).
*
* @return true if the image has a raster
*
******************************************************************************************************************/
public boolean hasRaster()
{
<span class="nc bnc" id="L270" title="All 2 branches missed."> return imageModelHolder.get() != null;</span>
}
/*******************************************************************************************************************
*
* DO NOT USE THIS. This method is only used by the module implementation.
*
******************************************************************************************************************/
public ImageModel getImageModel()
{
<span class="nc" id="L280"> return imageModelHolder.get();</span>
}
private static boolean availableExtensionsLogged;
/*******************************************************************************************************************
*
* Returns all the file extensions of file formats that can be read into an
* EditableImage. The <code>ImageIO</code> registry is called to retrieve the
* requested information.
*
* @return an array of all file extensions
*
******************************************************************************************************************/
@Nonnull
public static Collection<String> getAvailableExtensions()
{
final boolean logExtensions;
<span class="nc" id="L299"> synchronized (EditableImage.class)</span>
{
<span class="nc bnc" id="L301" title="All 2 branches missed."> logExtensions = !availableExtensionsLogged;</span>
<span class="nc" id="L302"> availableExtensionsLogged = true;</span>
<span class="nc" id="L303"> }</span>
<span class="nc bnc" id="L305" title="All 2 branches missed."> if (logExtensions)</span>
{
<span class="nc" id="L307"> log.info("getAvailableExtensions()");</span>
}
<span class="nc" id="L310"> final Set<String> suffixList = new TreeSet<>();</span>
<span class="nc bnc" id="L312" title="All 2 branches missed."> for (final var formatName : ImageIO.getReaderFormatNames())</span>
{
<span class="nc bnc" id="L314" title="All 2 branches missed."> for (final var i = ImageIO.getImageReadersByFormatName(formatName); i.hasNext(); )</span>
{
<span class="nc" id="L316"> final var imageReader = i.next();</span>
<span class="nc" id="L317"> final var originatingProvider = imageReader.getOriginatingProvider();</span>
<span class="nc" id="L318"> final var suffixes = originatingProvider.getFileSuffixes();</span>
<span class="nc" id="L319"> final var suffixesAsList = Arrays.asList(suffixes);</span>
<span class="nc" id="L320"> suffixList.addAll(suffixesAsList);</span>
<span class="nc bnc" id="L322" title="All 2 branches missed."> if (logExtensions)</span>
{
<span class="nc" id="L324"> log.info(">>>> reader - format name: {} provider: {} supports {}",</span>
<span class="nc" id="L325"> formatName, originatingProvider.getPluginClassName(), suffixesAsList);</span>
}
<span class="nc" id="L327"> }</span>
}
<span class="nc bnc" id="L330" title="All 2 branches missed."> if (logExtensions)</span>
{
<span class="nc" id="L332"> log.info(">>>> returning {}", suffixList);</span>
}
<span class="nc" id="L335"> return suffixList;</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public <T extends Directory> Optional<T> getMetadata (final @Nonnull Class<T> metadataClass)
{
<span class="fc" id="L344"> return getMetadata(metadataClass, 0);</span>
}
/*******************************************************************************************************************
*
* Retrieve a metadata directory.
*
* @param metadataClass the type of the directory
* @param index the index (in case of multiple items)
* @return the metadata directory
*
******************************************************************************************************************/
public <T extends Directory> Optional<T> getMetadata (final @Nonnull Class<T> metadataClass, final @Nonnegative int index)
{
<span class="fc" id="L358"> final var list = (List<T>)metadataMapByClass.get(metadataClass);</span>
<span class="pc bpc" id="L359" title="1 of 2 branches missed."> return Optional.ofNullable(list).flatMap(l -> l.isEmpty() ? Optional.empty() : Optional.of(l.get(index)));</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
@Nonnegative
public int getMetadataCount (final @Nonnull Class<?> metadataClass)
{
<span class="fc" id="L369"> return Optional.ofNullable(metadataMapByClass.get(metadataClass)).map(List::size).orElse(0);</span>
}
/*******************************************************************************************************************
*
* Returns the width of this image.
*
* @return the width
*
******************************************************************************************************************/
@Nonnegative
public int getWidth()
{
<span class="fc" id="L382"> return imageModelHolder.get().getWidth();</span>
}
/*******************************************************************************************************************
*
* Returns the height of this image.
*
* @return the height
*
******************************************************************************************************************/
@Nonnegative
public int getHeight()
{
<span class="fc" id="L395"> return imageModelHolder.get().getHeight();</span>
}
/*******************************************************************************************************************
*
* Returns the dataType used by this image.
*
* @return the data type
*
******************************************************************************************************************/
@Nonnull
public DataType getDataType()
{
<span class="fc" id="L408"> return imageModelHolder.get().getDataType();</span>
}
/*******************************************************************************************************************
*
* Returns the number of bands this EditableImage is composed of.
*
* @return the band count
*
******************************************************************************************************************/
@Nonnegative
public int getBandCount()
{
<span class="fc" id="L421"> return imageModelHolder.get().getBandCount();</span>
}
/*******************************************************************************************************************
*
* Returns the number of sample bits for each band this EditableImage is
* composed of.
*
* @return the number of bits
*
******************************************************************************************************************/
@Nonnegative
public int getBitsPerBand()
{
<span class="fc" id="L435"> return getDataType().getSize();</span>
}
/*******************************************************************************************************************
*
* Returns the number of sample bits for each pixel this EditableImage is
* composed of.
*
* @return the number of bits
*
******************************************************************************************************************/
@Nonnegative
public int getBitsPerPixel()
{
<span class="fc" id="L449"> return getBandCount() * getBitsPerBand();</span>
}
/*******************************************************************************************************************
*
* Executes an operation. The original image is lost and replaced by results.
*
* @param operation the operation to perform
* @return the operation (as a convenience in case it carries results)
*
******************************************************************************************************************/
@Nonnull
public <T extends Operation> T executeInPlace (@Nonnull final T operation)
{
<span class="fc" id="L463"> final var time = Instant.now();</span>
<span class="fc" id="L464"> final var image = internalExecute(operation);</span>
<span class="fc" id="L465"> imageModelHolder.get().setImage(image);</span>
<span class="fc" id="L466"> latestOperationDuration = Duration.between(time, Instant.now());</span>
<span class="fc" id="L468"> return operation;</span>
}
/*******************************************************************************************************************
*
* Executes an operation. The original image is untouched as the results are placed in a brand-new instance of
* EditableImage.
*
* @param operation the operation to perform
* @return the result
*
******************************************************************************************************************/
@Nonnull
public EditableImage execute (@Nonnull final Operation operation)
{
try
{
<span class="fc" id="L485"> final var time = Instant.now();</span>
<span class="fc" id="L486"> final var image = internalExecute(operation);</span>
<span class="fc" id="L487"> final var modelClass = imageModelHolder.get().getClass();</span>
<span class="fc" id="L488"> final var constructor = modelClass.getConstructor(Object.class);</span>
<span class="fc" id="L489"> final var newModel = constructor.newInstance(image);</span>
<span class="fc" id="L490"> final var result = new EditableImage(newModel);</span>
<span class="fc" id="L491"> result.attributeMapByName = attributeMapByName; // immutable</span>
<span class="fc" id="L492"> result.latestOperationDuration = Duration.between(time, Instant.now());;</span>
<span class="fc" id="L494"> return result;</span>
}
<span class="fc" id="L496"> catch (Exception e)</span>
{
<span class="fc" id="L498"> throw new RuntimeException(e);</span>
}
}
/*******************************************************************************************************************
*
* Returns the elapsed time of the latest operation performed. Note that for
* execute2() this value is available on the result. When an image is
* deserialized, this method returns the serialization time (this relies upon
* the fact that the clocks on all network nodes are synchronized).
*
* @return the latest operation elapsed time
*
******************************************************************************************************************/
@Nonnull
public Duration getLatestOperationDuration()
{
<span class="nc" id="L515"> return latestOperationDuration;</span>
}
/*******************************************************************************************************************
*
* Creates a similar image, that is a blank image with the same characteristics
* of this image (width, height, data type, color model).
* @deprecated will be merged with create(AbstractCreateOp)
*
* @return a new, similar image
*
******************************************************************************************************************/
@Nonnull
public EditableImage createSimilarImage()
{
<span class="nc" id="L530"> final var imageCopy = imageModelHolder.get().createCopy(false);</span>
<span class="nc" id="L531"> imageCopy.attributeMapByName = attributeMapByName; // immutable</span>
<span class="nc" id="L532"> return imageCopy;</span>
}
/*******************************************************************************************************************
*
* Clones this image.
*
******************************************************************************************************************/
@Nonnull
public EditableImage cloneImage()
{
<span class="nc" id="L543"> final var imageCopy = imageModelHolder.get().createCopy(true);</span>
<span class="nc" id="L544"> imageCopy.attributeMapByName = attributeMapByName; // immutable</span>
<span class="nc" id="L545"> return imageCopy;</span>
}
/*******************************************************************************************************************
*
* Creates a resized image. - FIXME should be removed
* @deprecated
*
******************************************************************************************************************/
@Nonnull
public EditableImage createResizedImage (final @Nonnegative int width, final @Nonnegative int height)
{
<span class="nc" id="L557"> return createResizedImage(width, height, Quality.FASTEST);</span>
}
/*******************************************************************************************************************
*
* Creates a resized image. - FIXME move to a factory method for ScaleOp.
* @deprecated
*
******************************************************************************************************************/
@Nonnull
public EditableImage createResizedImage (final @Nonnegative int width,
final @Nonnegative int height,
final @Nonnull Quality quality)
{
<span class="nc" id="L571"> final var hScale = (double)width / (double)getWidth();</span>
<span class="nc" id="L572"> final var vScale = (double)height / (double)getHeight();</span>
<span class="nc" id="L573"> final var scaleOp = new ScaleOp(hScale, vScale, quality);</span>
<span class="nc" id="L574"> executeInPlace(scaleOp);</span>
<span class="nc" id="L576"> return this;</span>
}
/*******************************************************************************************************************
*
* Sets an attribute of this image. Attributes are user-specific name-value pairs.
*
* @param key the attribute name
* @param value the attribute value
*
******************************************************************************************************************/
public <T> void setAttribute (final @Nonnull Key<T> key, final @Nonnull T value)
{
<span class="fc" id="L589"> attributeMapByName = attributeMapByName.with(key, value);</span>
<span class="fc" id="L590"> }</span>
/*******************************************************************************************************************
*
* Returns an attribute of this image.
*
* @param key the attribute name
* @return the attribute value
*
******************************************************************************************************************/
@Nonnull
public <T> Optional<T> getAttribute (final @Nonnull Key<T> key)
{
<span class="fc" id="L603"> return attributeMapByName.getOptional(key);</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
public void setAttributes (final @Nonnull Map<Key<?>, Object> attributes)
{
<span class="nc" id="L612"> attributeMapByName = TypeSafeMap.ofCloned(attributes);</span>
<span class="nc" id="L613"> }</span>
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
@Nonnull
public TypeSafeMap getAttributes()
{
<span class="nc" id="L622"> return attributeMapByName; // immutable</span>
}
/*******************************************************************************************************************
*
* Removes an attribute from this image.
*
* @param name the attribute name
* @return the attribute value
*
******************************************************************************************************************/
@Nonnull
public <T> T removeAttribute (final @Nonnull String name)
{
<span class="nc" id="L636"> throw new UnsupportedOperationException(); // FIXME: need to add TypeSafeMap.without()</span>
}
/*******************************************************************************************************************
*
* Removes all the resources bound to this image.
*
******************************************************************************************************************/
public void dispose()
{
<span class="nc" id="L646"> imageModelHolder.get().dispose();</span>
<span class="nc" id="L647"> imageModelHolder = null;</span>
<span class="nc" id="L648"> attributeMapByName = TypeSafeMap.newInstance();</span>
<span class="nc" id="L649"> }</span>
/*******************************************************************************************************************
*
* Returns an estimate of the memory allocated by this image.
*
* @return the memory allocated for this image
*
******************************************************************************************************************/
@Nonnegative
public long getMemorySize()
{
<span class="nc" id="L661"> final var imageModel = imageModelHolder.get();</span>
<span class="nc bnc" id="L662" title="All 2 branches missed."> return (imageModel != null) ? imageModel.getMemorySize() : 0;</span>
}
/*******************************************************************************************************************
*
* Returns the ColorModel of this image.
*
* @return the color model
*
******************************************************************************************************************/
@Nonnegative
public ColorModel getColorModel() // FIXME: to be removed
to be removed
{
<span class="nc" id="L675"> return imageModelHolder.get().getColorModel();</span>
}
/*******************************************************************************************************************
*
* Returns the ICC_Profile of this image (null will be returned if the ColorModel is not ICC-based). <i>Note that
* this is the profile of the image as it is optimized for the display, which is almost surely sRGB; and <b>it's
* probably different than the original image profile</b></i>.
*
* @return the color profile
*
******************************************************************************************************************/
@Nonnegative
public ICC_Profile getICCProfile() // FIXME: to be removed
{
<span class="nc" id="L690"> final var colorModel = getColorModel();</span>
<span class="nc bnc" id="L692" title="All 2 branches missed."> if (colorModel != null)</span>
{
<span class="nc" id="L694"> final var colorSpace = colorModel.getColorSpace();</span>
<span class="nc bnc" id="L696" title="All 2 branches missed."> if (colorSpace instanceof ICC_ColorSpace)</span>
{
<span class="nc" id="L698"> final var iccColorSpace = (ICC_ColorSpace)colorSpace;</span>
<span class="nc" id="L699"> return iccColorSpace.getProfile();</span>
}
}
<span class="nc" id="L703"> return null;</span>
}
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
/*
private final static int COMPRESSED = 1;
public void writeExternal (ObjectOutput out)
throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// GZIPOutputStream gos = new GZIPOutputStream(baos);
DataOutputStream dos = new DataOutputStream(baos);
dos.writeUTF(imageModel.getClass().getName());
imageModel.writeExternal(dos);
dos.flush();
dos.close();
byte[] buffer = baos.toByteArray();
out.writeLong(System.currentTimeMillis());
out.writeInt(0);
out.writeInt(buffer.length);
out.write(buffer);
out.flush();
}*/
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
/*
public void readExternal (ObjectInput in)
throws IOException, ClassNotFoundException
{
long serializationTimeStamp = in.readLong();
latestOperationTime = System.currentTimeMillis() - serializationTimeStamp;
int mode = in.readInt();
int bufferSize = in.readInt();
byte[] buffer = new byte[bufferSize];
in.readFully(buffer);
InputStream is = new ByteArrayInputStream(buffer);
if (mode == COMPRESSED)
{
is = new GZIPInputStream(is);
}
DataInputStream dis = new DataInputStream(is);
String className = dis.readUTF();
Class clazz = Class.forName(className);
try
{
imageModel = (ImageModel)clazz.newInstance();
}
catch (InstantiationException e)
{
throw new RuntimeException(e);
}
catch (IllegalAccessException e)
{
throw new RuntimeException(e);
}
imageModel.readExternal(dis);
dis.close();
latestSerializationSize = bufferSize;
}*/
/*******************************************************************************************************************
*
*
******************************************************************************************************************/
@Nonnull
public long getLatestSerializationSize()
{
<span class="nc" id="L783"> return latestSerializationSize;</span>
}
/*******************************************************************************************************************
*
* DO NOT USE. This is only for implementation and testing purposes.
*
******************************************************************************************************************/
@Nonnull
public <T> T getInnerProperty (final @Nonnull Class<T> propertyClass)
{
<span class="fc bfc" id="L794" title="All 2 branches covered."> if (AccessorOp.class.equals(propertyClass))</span>
{
<span class="fc" id="L796"> return propertyClass.cast(accessor);</span>
}
<span class="pc bpc" id="L799" title="1 of 2 branches missed."> if (IIOMetadata.class.equals(propertyClass))</span>
{
<span class="nc" id="L801"> return propertyClass.cast(iioMetadata);</span>
}
<span class="fc" id="L804"> return imageModelHolder.get().getInnerProperty(propertyClass);</span>
}
/*******************************************************************************************************************
*
* Executes an operation and return the raw result (the object to be wrapped by the ImageModel).
*
* @param operation the operation to perform
* @return the result (the object wrapped by the ImageModel)
*
******************************************************************************************************************/
@Nonnull
private Object internalExecute (final @Nonnull Operation operation)
throws UnsupportedOperationException
{
<span class="fc" id="L819"> final var implementationFactoryRegistry = ImplementationFactoryRegistry.getDefault();</span>
<span class="fc" id="L820"> final var imageModel = imageModelHolder.get();</span>
<span class="fc bfc" id="L821" title="All 2 branches covered."> var image = (imageModel != null) ? imageModel.getImage() : null;</span>
<span class="fc" id="L822"> OperationImplementation implementation = null;</span>
<span class="pc bpc" id="L824" title="1 of 4 branches missed."> if ((image == null) && !(operation instanceof AbstractCreateOp))</span>
{
<span class="nc" id="L826"> throw new RuntimeException("null image with an Op different that AbstractCreateOp");</span>
}
try
{
<span class="fc" id="L831"> implementation = implementationFactoryRegistry.findImplementation(operation, imageModelHolder.get(), false);</span>
}
<span class="fc" id="L833"> catch (UnsupportedOperationException e)</span>
{
<span class="fc" id="L835"> log.warn("No default implementation of {} for model: {}", operation, image);</span>
<span class="nc" id="L836"> implementation = implementationFactoryRegistry.findImplementation(operation, imageModelHolder.get(), true);</span>
<span class="nc" id="L837"> log.info("Found alternate implementation: {}", implementation);</span>
<span class="nc bnc" id="L839" title="All 2 branches missed."> if (!(operation instanceof AbstractCreateOp))</span>
{
<span class="nc bnc" id="L841" title="All 2 branches missed."> if (implementation.getFactory().canConvertFrom(image.getClass()))</span>
{
<span class="nc" id="L843"> log.info(">>>> CONVERT FROM using {}", implementation.getFactory());</span>
<span class="nc" id="L844"> imageModelHolder = ImageModelHolder.wrap(implementation.getFactory().convertFrom(image));</span>
<span class="nc" id="L845"> image = imageModelHolder.get().getImage();</span>
}
<span class="nc bnc" id="L848" title="All 2 branches missed."> else if (imageModelHolder.get().getFactory().canConvertTo(implementation.getFactory().getModelClass()))</span>
{
<span class="nc" id="L850"> log.info(">>>> CONVERT TO {}", implementation.getFactory().getModelClass());</span>
<span class="nc" id="L851"> image = imageModelHolder.get().getFactory().convertTo(implementation.getFactory().getModelClass());</span>
}
else
{
<span class="nc" id="L856"> throw new RuntimeException("Shouldn't get here");</span>
}
<span class="nc" id="L859"> log.info(">>>> NEW IMAGE {} NEW IMAGE MODEL {}", image, imageModelHolder);</span>
}
<span class="fc" id="L861"> }</span>
try
{
<span class="fc" id="L865"> return implementation.execute(this, image);</span>
}
<span class="fc" id="L867"> catch (RuntimeException e)</span>
{
<span class="fc" id="L869"> log.error("Operation failed, offending image: {}", image);</span>
<span class="fc" id="L870"> throw e;</span>
}
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.7.202105040129</span></div></body></html>