Skip to content

Commit

Permalink
Merge pull request #3505 from melissalinkert/new-ndpi
Browse files Browse the repository at this point in the history
NDPI: support JPEG-XR and files larger than 4 GB
  • Loading branch information
dgault authored Mar 11, 2020
2 parents 1f48d3c + 730721a commit 7f5a068
Show file tree
Hide file tree
Showing 12 changed files with 512 additions and 210 deletions.
5 changes: 5 additions & 0 deletions components/formats-bsd/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@
<artifactId>metadata-extractor</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>ome</groupId>
<artifactId>jxrlib-all</artifactId>
<version>${jxrlib.version}</version>
</dependency>

<!-- xerces is no longer a dependency of metadata-extractor, but it may be required by other BF components -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
/*
* #%L
* OME Bio-Formats package for reading and converting biological file formats.
* BSD implementations of Bio-Formats readers and writers
* %%
* Copyright (C) 2016 - 2017 Open Microscopy Environment:
* - Board of Regents of the University of Wisconsin-Madison
* - Glencoe Software, Inc.
* - University of Dundee
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 2 of the
* License, or (at your option) any later version.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-2.0.html>.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/

Expand Down Expand Up @@ -81,17 +88,13 @@ public byte[] decompress(byte[] buf, CodecOptions options)
{
initialize();

byte[] uncompressed = service.decompress(buf);

if (options.interleaved) {
return uncompressed;
}

int bpp = options.bitsPerSample / 8;
int pixels = options.width * options.height;

byte[] uncompressed = service.decompress(buf);
int channels = uncompressed.length / (pixels * bpp);

if (channels == 1) {
if (channels == 1 || options.interleaved) {
return uncompressed;
}

Expand All @@ -101,8 +104,9 @@ public byte[] decompress(byte[] buf, CodecOptions options)
for (int c=0; c<channels; c++) {
for (int b=0; b<bpp; b++) {
int bb = options.littleEndian ? b : bpp - b - 1;
deinterleaved[bpp * (c * pixels + p) + bb] =
uncompressed[bpp * (p * channels + c) + b];
int src = bpp * (p * channels + c) + b;
int dest = bpp * (c * pixels + p) + bb;
deinterleaved[dest] = uncompressed[src];
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* #%L
* BSD implementations of Bio-Formats readers and writers
* %%
* Copyright (C) 2016 - 2017 Open Microscopy Environment:
* - Board of Regents of the University of Wisconsin-Madison
* - Glencoe Software, Inc.
* - University of Dundee
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/

package loci.formats.services;

import loci.common.services.Service;
import loci.formats.FormatException;

/**
* Interface defining methods for working with JPEG-XR data
*/
public interface JPEGXRService extends Service {

/**
* Decompress the given JPEG-XR compressed byte array and return as a byte array.
* Opening and closing of decoders and streams is handled internally.
*
* @param compressed the complete JPEG-XR compressed data
* @return raw decompressed bytes
* @throws FormatException if an error occurs during decompression
*/
byte[] decompress(byte[] compressed) throws FormatException;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
* #%L
* BSD implementations of Bio-Formats readers and writers
* %%
* Copyright (C) 2016 - 2017 Open Microscopy Environment:
* - Board of Regents of the University of Wisconsin-Madison
* - Glencoe Software, Inc.
* - University of Dundee
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/

package loci.formats.services;

import java.io.IOException;

import loci.common.RandomAccessInputStream;
import loci.common.services.AbstractService;
import loci.formats.FormatException;
import loci.formats.tiff.IFD;
import loci.formats.tiff.TiffParser;

import ome.jxrlib.Decode;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Interface defining methods for working with JPEG-XR data
*/
public class JPEGXRServiceImpl extends AbstractService implements JPEGXRService {

// see table A.4 in ITU-T T.832
private static final int PIXEL_FORMAT_TAG = 0xbc01;

// see table A.6 in ITU-T T.832
private static final short BGR_24 = 0x0c;
private static final short BGR_32 = 0x0e;
private static final short BGRA_32 = 0x0f;
private static final short PBGRA_32 = 0x10;

private static final Logger LOGGER =
LoggerFactory.getLogger(JPEGXRServiceImpl.class);

public JPEGXRServiceImpl() {
checkClassDependency(ome.jxrlib.Decode.class);
}

/**
* @see JPEGXRServiceImpl#decompress(byte[])
*/
public byte[] decompress(byte[] compressed) throws FormatException {
LOGGER.trace("begin tile decode; compressed size = {}", compressed.length);
try {
byte[] raw = Decode.decodeFirstFrame(compressed, 0, compressed.length);
short[] format = getPixelFormat(compressed);

if (isBGR(format)) {
int bpp = getBGRComponents(format);
// only happens with 8 bits per channel,
// 3 (BGR) or 4 (BGRA) channel data
for (int p=0; p<raw.length; p+=bpp) {
byte tmp = raw[p];
raw[p] = raw[p + 2];
raw[p + 2] = tmp;
}
}
return raw;
}
// really only want to catch ome.jxrlib.FormatError, but that doesn't compile
catch (Exception e) {
throw new FormatException(e);
}
}

private short[] getPixelFormat(byte[] stream) throws FormatException, IOException {
try (RandomAccessInputStream s = new RandomAccessInputStream(stream)) {
s.order(true);
s.seek(4);
long ifdPointer = s.readInt();
TiffParser p = new TiffParser(s);
IFD ifd = p.getIFD(ifdPointer);
return ifd.getIFDShortArray(PIXEL_FORMAT_TAG);
}
}

private boolean isBGR(short[] format) {
short lastByte = format[format.length - 1];
return lastByte == BGR_24 || lastByte == BGR_32 ||
lastByte == BGRA_32 || lastByte == PBGRA_32;
}

private int getBGRComponents(short[] format) {
short lastByte = format[format.length - 1];
return lastByte == BGR_24 || lastByte == BGR_32 ? 3 : 4;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import loci.formats.codec.JPEG2000Codec;
import loci.formats.codec.JPEG2000CodecOptions;
import loci.formats.codec.JPEGCodec;
import loci.formats.codec.JPEGXRCodec;
import loci.formats.codec.LZWCodec;
import loci.formats.codec.LuraWaveCodec;
import loci.formats.codec.NikonCodec;
Expand Down Expand Up @@ -193,7 +194,8 @@ public CodecOptions getCompressionCodecOptions(IFD ifd, CodecOptions opt)

},
NIKON(34713, new NikonCodec(), "Nikon"),
LURAWAVE(65535, new LuraWaveCodec(), "LuraWave");
LURAWAVE(65535, new LuraWaveCodec(), "LuraWave"),
JPEGXR(22610, new JPEGXRCodec(), "JPEG-XR");

// -- Constants --

Expand Down
8 changes: 6 additions & 2 deletions components/formats-bsd/src/loci/formats/tiff/TiffParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ public Object getIFDValue(TiffIFDEntry entry) throws IOException {
}

if (offset != in.getFilePointer()) {
if (fakeBigTiff && (offset < 0 || offset > in.getFilePointer())) {
if (fakeBigTiff && offset < 0) {
offset &= 0xffffffffL;
offset += 0x100000000L;
}
Expand Down Expand Up @@ -1173,7 +1173,11 @@ public static void unpackBytes(byte[] samples, int startIndex, byte[] bytes,

TiffCompression compression = ifd.getCompression();
PhotoInterp photoInterp = ifd.getPhotometricInterpretation();
if (compression == TiffCompression.JPEG) photoInterp = PhotoInterp.RGB;
if (compression == TiffCompression.JPEG ||
compression == TiffCompression.JPEGXR)
{
photoInterp = PhotoInterp.RGB;
}

int[] bitsPerSample = ifd.getBitsPerSample();
int nChannels = bitsPerSample.length;
Expand Down
5 changes: 0 additions & 5 deletions components/formats-gpl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,6 @@
<artifactId>ome-poi</artifactId>
<version>${ome-poi.version}</version>
</dependency>
<dependency>
<groupId>ome</groupId>
<artifactId>jxrlib-all</artifactId>
<version>${jxrlib.version}</version>
</dependency>
<dependency>
<groupId>edu.ucar</groupId>
<artifactId>cdm</artifactId>
Expand Down
Loading

0 comments on commit 7f5a068

Please sign in to comment.