001/*
002 * Copyright 2010-2015 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019package icy.util;
020
021import icy.image.IcyBufferedImage;
022import icy.sequence.MetaDataUtil;
023import icy.sequence.Sequence;
024import icy.system.IcyExceptionHandler;
025import icy.type.DataType;
026import icy.type.TypeUtil;
027
028import java.awt.Color;
029
030import org.w3c.dom.Document;
031
032import loci.common.services.DependencyException;
033import loci.common.services.ServiceException;
034import loci.common.services.ServiceFactory;
035import loci.formats.MetadataTools;
036import loci.formats.ome.OMEXMLMetadataImpl;
037import loci.formats.services.OMEXMLService;
038import loci.formats.services.OMEXMLServiceImpl;
039import ome.units.UNITS;
040import ome.units.quantity.Length;
041import ome.units.quantity.Time;
042import ome.xml.meta.MetadataRetrieve;
043import ome.xml.meta.OMEXMLMetadata;
044import ome.xml.model.OME;
045import ome.xml.model.StructuredAnnotations;
046import ome.xml.model.XMLAnnotation;
047import ome.xml.model.primitives.NonNegativeInteger;
048import ome.xml.model.primitives.PositiveFloat;
049import ome.xml.model.primitives.PositiveInteger;
050
051/**
052 * @author Stephane
053 */
054public class OMEUtil
055{
056    private static ServiceFactory factory;
057    private static OMEXMLService OMEService;
058
059    static
060    {
061        try
062        {
063            factory = new ServiceFactory();
064            OMEService = factory.getInstance(OMEXMLService.class);
065        }
066        catch (DependencyException e)
067        {
068            System.err.println("Error create OME Service:" + e.getMessage());
069            System.err.println("Using default service implementation...");
070
071            factory = null;
072            OMEService = new OMEXMLServiceImpl();
073        }
074    }
075
076    /**
077     * Safe integer evaluation from PositiveInteger object.<br>
078     * Return defaultValue if specified object is null.
079     */
080    public static int getValue(PositiveInteger obj, int defaultValue)
081    {
082        if (obj == null)
083            return defaultValue;
084
085        return TypeUtil.getInt(obj.getValue(), defaultValue);
086    }
087
088    /**
089     * Safe integer evaluation from NonNegativeInteger object.<br>
090     * Return defaultValue if specified object is null.
091     */
092    public static int getValue(NonNegativeInteger obj, int defaultValue)
093    {
094        if (obj == null)
095            return defaultValue;
096
097        return TypeUtil.getInt(obj.getValue(), defaultValue);
098    }
099
100    /**
101     * Safe float evaluation from PositiveFloat object.<br>
102     * Return <code>defaultValue</code> if <code>obj</code> is null or equal to infinite with <code>allowInfinite</code>
103     * set to false.
104     */
105    public static double getValue(PositiveFloat obj, double defaultValue, boolean allowInfinite)
106    {
107        if (obj == null)
108            return defaultValue;
109
110        return TypeUtil.getDouble(obj.getValue(), defaultValue, allowInfinite);
111    }
112
113    /**
114     * Safe float evaluation from PositiveFloat object.<br>
115     * Return defaultValue if specified object is null.
116     */
117    public static double getValue(PositiveFloat obj, double defaultValue)
118    {
119        return getValue(obj, defaultValue, true);
120    }
121
122    /**
123     * Convert specified Length to double value in µm (for backward compatibility).<br>
124     * Return defaultValue if specified object is <code>null</code>.
125     */
126    public static double getValue(Length obj, double defaultValue)
127    {
128        if (obj == null)
129            return defaultValue;
130
131        final Number value = obj.value(UNITS.MICROMETER);
132        if (value == null)
133            return defaultValue;
134
135        return value.doubleValue();
136    }
137
138    /**
139     * Convert specified Time to double value in second (for backward compatibility).<br>
140     * Return defaultValue if specified object is <code>null</code>.
141     */
142    public static double getValue(Time obj, double defaultValue)
143    {
144        if (obj == null)
145            return defaultValue;
146
147        final Number value = obj.value(UNITS.SECOND);
148        if (value == null)
149            return defaultValue;
150
151        return value.doubleValue();
152    }
153
154    /**
155     * Return a PositiveFloat object representing the specified value
156     */
157    public static PositiveFloat getPositiveFloat(double value)
158    {
159        return new PositiveFloat(Double.valueOf(value));
160    }
161
162    /**
163     * Return a PositiveInteger object representing the specified value
164     */
165    public static PositiveInteger getPositiveInteger(int value)
166    {
167        return new PositiveInteger(Integer.valueOf(value));
168    }
169
170    /**
171     * Return a NonNegativeInteger object representing the specified value
172     */
173    public static NonNegativeInteger getNonNegativeInteger(int value)
174    {
175        return new NonNegativeInteger(Integer.valueOf(value));
176    }
177
178    /**
179     * Return a Length object representing the specified value (in µm)
180     */
181    public static Length getLength(double value)
182    {
183        return new Length(Double.valueOf(value), UNITS.MICROMETER);
184    }
185
186    /**
187     * Return a Time object representing the specified value (in second)
188     */
189    public static Time getTime(double value)
190    {
191        return new Time(Double.valueOf(value), UNITS.SECOND);
192    }
193
194    /**
195     * Return a java Color object from a OME Color object
196     */
197    public static Color getJavaColor(ome.xml.model.primitives.Color value)
198    {
199        if (value == null)
200            return null;
201
202        return new Color(value.getRed(), value.getGreen(), value.getBlue(), value.getAlpha());
203    }
204
205    /**
206     * Return a OME Color object from a java Color object
207     */
208    public static ome.xml.model.primitives.Color getOMEColor(Color value)
209    {
210        return new ome.xml.model.primitives.Color(value.getRed(), value.getGreen(), value.getBlue(), value.getAlpha());
211    }
212
213    /**
214     * Create a new empty OME Metadata object.
215     */
216    public synchronized static OMEXMLMetadata createOMEXMLMetadata()
217    {
218        try
219        {
220            return OMEService.createOMEXMLMetadata();
221        }
222        catch (Exception e)
223        {
224            IcyExceptionHandler.showErrorMessage(e, true);
225            return null;
226        }
227    }
228
229    /**
230     * @deprecated Use {@link #createOMEXMLMetadata()} instead
231     */
232    @Deprecated
233    public static OMEXMLMetadataImpl createOMEMetadata()
234    {
235        return (OMEXMLMetadataImpl) createOMEXMLMetadata();
236    }
237
238    /**
239     * Create a new OME Metadata object from the specified Metadata object.<br>
240     */
241    public static OMEXMLMetadata createOMEXMLMetadata(MetadataRetrieve metadata)
242    {
243        final OMEXMLMetadata result = createOMEXMLMetadata();
244
245        // TODO: remove that when annotations loading will be fixed in Bio-Formats
246        if (metadata instanceof OMEXMLMetadata)
247        {
248            final OME root = (OME) ((OMEXMLMetadata) metadata).getRoot();
249            final StructuredAnnotations annotations = root.getStructuredAnnotations();
250
251            // clean up annotation
252            if (annotations != null)
253            {
254                for (int i = annotations.sizeOfXMLAnnotationList() - 1; i >= 0; i--)
255                {
256                    final XMLAnnotation annotation = annotations.getXMLAnnotation(i);
257
258                    if (StringUtil.isEmpty(annotation.getValue()))
259                        annotations.removeXMLAnnotation(annotation);
260                }
261            }
262        }
263
264        synchronized (OMEService)
265        {
266            // need to cast to get rid of this old loci package stuff
267            OMEService.convertMetadata((loci.formats.meta.MetadataRetrieve) metadata,
268                    (loci.formats.meta.MetadataStore) result);
269        }
270
271        return result;
272    }
273
274    /**
275     * @deprecated Use {@link #createOMEXMLMetadata(MetadataRetrieve)} instead
276     */
277    @Deprecated
278    public synchronized static OMEXMLMetadataImpl createOMEMetadata(loci.formats.meta.MetadataRetrieve metadata)
279    {
280        return (OMEXMLMetadataImpl) createOMEXMLMetadata(metadata);
281    }
282
283    /**
284     * Create a new single serie OME Metadata object from the specified Metadata object.
285     * 
286     * @param serie
287     *        Index of the serie we want to keep.
288     */
289    public static OMEXMLMetadata createOMEXMLMetadata(MetadataRetrieve metadata, int serie)
290    {
291        final OMEXMLMetadata result = OMEUtil.createOMEXMLMetadata(metadata);
292
293        MetaDataUtil.keepSingleSerie(result, serie);
294
295        // set the default id with correct serie number (for XML metadata)
296        result.setImageID(MetadataTools.createLSID("Image", serie), 0);
297
298        return result;
299    }
300
301    /**
302     * @deprecated Use {@link #createOMEXMLMetadata(MetadataRetrieve,int)} instead
303     */
304    @Deprecated
305    public static OMEXMLMetadataImpl createOMEMetadata(loci.formats.meta.MetadataRetrieve metadata, int serie)
306    {
307        return (OMEXMLMetadataImpl) createOMEXMLMetadata(metadata, serie);
308    }
309
310    /**
311     * Convert the specified Metadata object to OME Metadata.<br>
312     * If the specified Metadata is already OME no conversion is done.
313     */
314    public static OMEXMLMetadata getOMEXMLMetadata(MetadataRetrieve metadata)
315    {
316        if (metadata instanceof OMEXMLMetadata)
317            return (OMEXMLMetadata) metadata;
318
319        return createOMEXMLMetadata(metadata);
320    }
321
322    /**
323     * @deprecated Use {@link #getOMEXMLMetadata(MetadataRetrieve)} instead
324     */
325    @Deprecated
326    public static OMEXMLMetadataImpl getOMEMetadata(loci.formats.meta.MetadataRetrieve metadata)
327    {
328        return (OMEXMLMetadataImpl) getOMEXMLMetadata(metadata);
329    }
330
331    /**
332     * Return a XML document from the specified Metadata object
333     */
334    public static Document getXMLDocument(OMEXMLMetadata metadata)
335    {
336        try
337        {
338            return XMLUtil.createDocument(metadata.dumpXML());
339        }
340        catch (Exception e)
341        {
342            IcyExceptionHandler.showErrorMessage(e, true);
343        }
344
345        // return empty document
346        return XMLUtil.createDocument(false);
347    }
348
349    /**
350     * @deprecated Use {@link #getXMLDocument(OMEXMLMetadata)} instead
351     */
352    @Deprecated
353    public static Document getXMLDocument(loci.formats.meta.MetadataRetrieve metadata)
354    {
355        return getXMLDocument(getOMEXMLMetadata(metadata));
356    }
357
358    /**
359     * @deprecated Uses {@link MetaDataUtil#setMetaData(OMEXMLMetadata, int, int, int, int, int, DataType, boolean)}
360     *             instead.
361     */
362    @Deprecated
363    public static OMEXMLMetadataImpl generateMetaData(OMEXMLMetadataImpl metadata, int sizeX, int sizeY, int sizeC,
364            int sizeZ, int sizeT, DataType dataType, boolean separateChannel)
365    {
366        final OMEXMLMetadata result;
367
368        if (metadata == null)
369            result = MetaDataUtil.createMetadata("Sample");
370        else
371            result = metadata;
372
373        MetaDataUtil.setMetaData(result, sizeX, sizeY, sizeC, sizeZ, sizeT, dataType, separateChannel);
374
375        return (OMEXMLMetadataImpl) result;
376    }
377
378    /**
379     * @deprecated Uses {@link MetaDataUtil#generateMetaData(int, int, int, int, int, DataType, boolean)} instead.
380     */
381    @Deprecated
382    public static OMEXMLMetadata generateMetaData(int sizeX, int sizeY, int sizeC, int sizeZ, int sizeT,
383            DataType dataType, boolean separateChannel) throws ServiceException
384    {
385        return MetaDataUtil.generateMetaData(sizeX, sizeY, sizeC, sizeZ, sizeT, dataType, separateChannel);
386    }
387
388    /**
389     * @deprecated Use {@link MetaDataUtil#generateMetaData(int, int, int, DataType, boolean)} instead.
390     */
391    @Deprecated
392    public static OMEXMLMetadata generateMetaData(int sizeX, int sizeY, int sizeC, DataType dataType,
393            boolean separateChannel) throws ServiceException
394    {
395        return MetaDataUtil.generateMetaData(sizeX, sizeY, sizeC, dataType, separateChannel);
396    }
397
398    /**
399     * @deprecated Use {@link MetaDataUtil#generateMetaData(IcyBufferedImage, boolean)} instead.
400     */
401    @Deprecated
402    public static OMEXMLMetadata generateMetaData(IcyBufferedImage image, boolean separateChannel)
403            throws ServiceException
404    {
405        return MetaDataUtil.generateMetaData(image, separateChannel);
406    }
407
408    /**
409     * @deprecated Use {@link MetaDataUtil#generateMetaData(Sequence, boolean)} instead.
410     */
411    @Deprecated
412    public static OMEXMLMetadata generateMetaData(Sequence sequence, boolean useZ, boolean useT,
413            boolean separateChannel)
414    {
415        return MetaDataUtil.generateMetaData(sequence, separateChannel);
416    }
417
418    /**
419     * @deprecated Use {@link MetaDataUtil#generateMetaData(Sequence, boolean)} instead.
420     */
421    @Deprecated
422    public static OMEXMLMetadata generateMetaData(Sequence sequence, int sizeZ, int sizeT, boolean separateChannel)
423    {
424        return MetaDataUtil.generateMetaData(sequence, separateChannel);
425    }
426
427    /**
428     * @deprecated Use {@link MetaDataUtil#generateMetaData(Sequence, boolean)} instead.
429     */
430    @Deprecated
431    public static OMEXMLMetadata generateMetaData(Sequence sequence, boolean separateChannel)
432    {
433        return MetaDataUtil.generateMetaData(sequence, separateChannel);
434    }
435
436    /**
437     * Report and upload the specified filename to LOCI team.
438     */
439    public static boolean reportLociError(String fileName, String errorMessage)
440    {
441        // TODO: implement this when done in LOCI
442        // final IssueReporter reporter = new IssueReporter();
443        // return reporter.reportBug(fileName, errorMessage);
444
445        return false;
446    }
447
448}