Compare commits
10 commits
ca2df9023f
...
a58f1e6c83
Author | SHA1 | Date | |
---|---|---|---|
a58f1e6c83 | |||
afbe6eee2f | |||
229951349b | |||
27fd1956a1 | |||
55ae303d70 | |||
e42bdecb99 | |||
047fee7798 | |||
b906e7533b | |||
6e82a0fbbd | |||
840cdc36f8 |
320 changed files with 69167 additions and 431 deletions
|
@ -7,7 +7,7 @@ plugins {
|
|||
|
||||
wrapper {
|
||||
gradleVersion = libs.versions.gradle.get()
|
||||
distributionType = Wrapper.DistributionType.ALL
|
||||
distributionType = Wrapper.DistributionType.BIN
|
||||
}
|
||||
|
||||
ext {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
group = org.xbib.graphics
|
||||
name = graphics
|
||||
version = 5.3.3
|
||||
|
||||
org.gradle.warning.mode = ALL
|
||||
version = 5.5.1
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
maven {
|
||||
//url 'https://www.dcm4che.org/maven2/'
|
||||
url 'https://maven.scijava.org/content/repositories/public/'
|
||||
}
|
||||
maven {
|
||||
url 'https://raw.githubusercontent.com/nroduit/mvn-repo/master/'
|
||||
}
|
||||
}
|
||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
20
gradlew.bat
vendored
20
gradlew.bat
vendored
|
@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
|
|||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
|
|
|
@ -2,23 +2,20 @@ package org.xbib.graphics.ghostscript;
|
|||
|
||||
import com.sun.jna.Pointer;
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.xbib.graphics.ghostscript.internal.ErrorCodes;
|
||||
import org.xbib.graphics.ghostscript.internal.GhostscriptLibrary;
|
||||
import org.xbib.graphics.ghostscript.internal.GhostscriptLibraryLoader;
|
||||
import org.xbib.graphics.ghostscript.internal.LoggingOutputStream;
|
||||
import org.xbib.graphics.ghostscript.internal.NullOutputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -33,21 +30,12 @@ public class Ghostscript implements AutoCloseable {
|
|||
|
||||
private final GhostscriptLibrary libraryInstance;
|
||||
|
||||
private InputStream stdIn;
|
||||
|
||||
private OutputStream stdOut;
|
||||
|
||||
private OutputStream stdErr;
|
||||
|
||||
private final AtomicBoolean closed;
|
||||
|
||||
public Ghostscript() throws IOException {
|
||||
prepareTmp();
|
||||
GhostscriptLibraryLoader libraryLoader = new GhostscriptLibraryLoader();
|
||||
this.libraryInstance = libraryLoader.getGhostscriptLibrary();
|
||||
Objects.requireNonNull(this.libraryInstance);
|
||||
this.stdOut = new LoggingOutputStream(logger);
|
||||
this.stdErr = new LoggingOutputStream(logger);
|
||||
this.libraryInstance = Objects.requireNonNull(libraryLoader.getGhostscriptLibrary(), "library instance must not be null");
|
||||
this.closed = new AtomicBoolean(false);
|
||||
}
|
||||
|
||||
|
@ -68,63 +56,8 @@ public class Ghostscript implements AutoCloseable {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the error output stream of the Ghostscript interpreter (may be null
|
||||
* if not set).
|
||||
*
|
||||
* @return The OutputStream or null
|
||||
*/
|
||||
public OutputStream getStdErr() {
|
||||
return stdErr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the error output stream of the Ghostscript interpreter.
|
||||
*
|
||||
* @param outputStream OutputStream object
|
||||
*/
|
||||
public void setStdErr(OutputStream outputStream) {
|
||||
stdErr = outputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the standard output stream of the Ghostscript interpreter.
|
||||
*
|
||||
* @return The OutputStream or null
|
||||
*/
|
||||
public OutputStream getStdOut() {
|
||||
return stdOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the standard output stream of the Ghostscript interpreter.
|
||||
*
|
||||
* @param outputStream OutputStream object
|
||||
*/
|
||||
public void setStdOut(OutputStream outputStream) {
|
||||
stdOut = outputStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the standard input stream of the Ghostscript interpreter.
|
||||
*
|
||||
* @return The InputStream or null
|
||||
*/
|
||||
public InputStream getStdIn() {
|
||||
return stdIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the standard input stream of the Ghostscript interpreter.
|
||||
*
|
||||
* @param inputStream InputStream object
|
||||
*/
|
||||
public void setStdIn(InputStream inputStream) {
|
||||
stdIn = inputStream;
|
||||
}
|
||||
|
||||
public synchronized void run(String[] args) throws IOException {
|
||||
run(args, null, null);
|
||||
public synchronized int run(List<String> args) throws IOException {
|
||||
return run(args, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,78 +66,56 @@ public class Ghostscript implements AutoCloseable {
|
|||
* @param args Interpreter parameters. Use the same as Ghostscript command line arguments.
|
||||
* @param runString run a string for the Ghostscript interpreter.
|
||||
* @param fileName run a postscript file for the Ghostscript interpreter.
|
||||
* @return the ghostscript return code;
|
||||
* @throws IOException if initialize fails
|
||||
*/
|
||||
public synchronized void run(String[] args,
|
||||
public synchronized int run(List<String> args,
|
||||
String runString,
|
||||
String fileName) throws IOException {
|
||||
Objects.requireNonNull(args);
|
||||
List<String> fullArgList = new LinkedList<>();
|
||||
if (!args.contains("ps2pdf")) {
|
||||
fullArgList.add("gs"); // gs or ps2pdf must be always present in the arg list
|
||||
}
|
||||
fullArgList.addAll(args);
|
||||
GhostscriptLibrary.gs_main_instance.ByReference nativeInstanceByRef = null;
|
||||
int ret = 0;
|
||||
boolean quit = false;
|
||||
try {
|
||||
nativeInstanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
|
||||
int result = libraryInstance.gsapi_new_instance(nativeInstanceByRef.getPointer(), null);
|
||||
if (result != 0) {
|
||||
ret = libraryInstance.gsapi_new_instance(nativeInstanceByRef.getPointer(), null);
|
||||
if (ret != 0) {
|
||||
nativeInstanceByRef = null;
|
||||
throw new IOException("can not call Ghostscript gsapi_new_instance, error code " + result);
|
||||
}
|
||||
logger.log(Level.INFO, "ghostscript instance " + nativeInstanceByRef + " created");
|
||||
GhostscriptLibrary.stdin_fn stdinCallback = null;
|
||||
if (getStdIn() != null) {
|
||||
stdinCallback = (caller_handle, buf, len) -> {
|
||||
String encoding = System.getProperty(ENCODING_PARAMETER, "UTF-8");
|
||||
try {
|
||||
byte[] buffer = new byte[1024];
|
||||
int read = getStdIn().read(buffer);
|
||||
if (read != -1) {
|
||||
buf.setString(0, new String(buffer, 0, read, encoding));
|
||||
return read;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, e.getMessage(), e);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
GhostscriptLibrary.stdout_fn stdoutCallback;
|
||||
if (getStdOut() == null) {
|
||||
setStdOut(new NullOutputStream());
|
||||
}
|
||||
stdoutCallback = (caller_handle, str, len) -> {
|
||||
try {
|
||||
getStdOut().write(str.getBytes(), 0, len);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, ex.getMessage(), ex);
|
||||
throw new IOException("can not call Ghostscript gsapi_new_instance, error code = " + ret);
|
||||
}
|
||||
logger.log(Level.FINE, "ghostscript instance " + nativeInstanceByRef + " created");
|
||||
Pointer pointer = nativeInstanceByRef.getValue();
|
||||
// always 0, we never use stdin
|
||||
GhostscriptLibrary.stdin_fn stdinCallback = (caller_handle, buf, len) -> 0;
|
||||
GhostscriptLibrary.stdout_fn stdoutCallback = (caller_handle, str, len) -> {
|
||||
logger.log(Level.FINE, str.substring(0, len));
|
||||
return len;
|
||||
};
|
||||
GhostscriptLibrary.stderr_fn stderrCallback;
|
||||
if (getStdErr() == null) {
|
||||
setStdErr(new NullOutputStream());
|
||||
}
|
||||
stderrCallback = (caller_handle, str, len) -> {
|
||||
try {
|
||||
getStdErr().write(str.getBytes(), 0, len);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, ex.getMessage(), ex);
|
||||
}
|
||||
GhostscriptLibrary.stderr_fn stderrCallback = (caller_handle, str, len) -> {
|
||||
logger.log(Level.FINE, str.substring(0, len));
|
||||
return len;
|
||||
};
|
||||
logger.log(Level.FINE, "setting gsapi_set_stdio");
|
||||
result = libraryInstance.gsapi_set_stdio(nativeInstanceByRef.getValue(), stdinCallback,
|
||||
stdoutCallback, stderrCallback);
|
||||
if (result != 0) {
|
||||
throw new IOException("can not set stdio on Ghostscript interpreter, error code " + result);
|
||||
ret = libraryInstance.gsapi_set_stdio(pointer, stdinCallback, stdoutCallback, stderrCallback);
|
||||
if (ret != 0) {
|
||||
throw new IOException("can not set stdio on Ghostscript interpreter, error code " + ret);
|
||||
}
|
||||
logger.log(Level.FINE, "gsapi_init_with_args = " + (args != null ? Arrays.asList(args) : "null"));
|
||||
result = libraryInstance.gsapi_init_with_args(nativeInstanceByRef.getValue(),
|
||||
args != null ? args.length : 0, args);
|
||||
logger.log(Level.FINE, "gsapi_init_with_args result = " + result);
|
||||
if (result == ErrorCodes.gs_error_Quit) {
|
||||
result = 0;
|
||||
logger.log(Level.FINE, "gsapi_init_with_args = " + fullArgList);
|
||||
ret = libraryInstance.gsapi_init_with_args(pointer, fullArgList.size(), fullArgList.toArray(new String[0]));
|
||||
logger.log(Level.FINE, "gsapi_init_with_args return code = " + ret);
|
||||
if (ret == ErrorCodes.gs_error_Quit) {
|
||||
quit = true;
|
||||
ret = 0;
|
||||
}
|
||||
if (result == 0) {
|
||||
if (ret == 0) {
|
||||
if (runString != null) {
|
||||
IntByReference exitCode = new IntByReference();
|
||||
libraryInstance.gsapi_run_string_begin(nativeInstanceByRef.getValue(), 0, exitCode);
|
||||
ret = libraryInstance.gsapi_run_string_begin(pointer, 0, exitCode);
|
||||
if (exitCode.getValue() != 0) {
|
||||
throw new IOException("can not run command on Ghostscript interpreter. gsapi_run_string_begin failed with error code "
|
||||
+ exitCode.getValue());
|
||||
|
@ -212,14 +123,13 @@ public class Ghostscript implements AutoCloseable {
|
|||
String[] slices = runString.split("\n");
|
||||
for (String slice1 : slices) {
|
||||
String slice = slice1 + "\n";
|
||||
libraryInstance.gsapi_run_string_continue(nativeInstanceByRef.getValue(), slice, slice.length(),
|
||||
0, exitCode);
|
||||
libraryInstance.gsapi_run_string_continue(pointer, slice, slice.length(), 0, exitCode);
|
||||
if (exitCode.getValue() != 0) {
|
||||
throw new IOException("can not run command on Ghostscript interpreter. gsapi_run_string_continue failed with error code "
|
||||
+ exitCode.getValue());
|
||||
}
|
||||
}
|
||||
libraryInstance.gsapi_run_string_end(nativeInstanceByRef.getValue(), 0, exitCode);
|
||||
ret = libraryInstance.gsapi_run_string_end(pointer, 0, exitCode);
|
||||
if (exitCode.getValue() != 0) {
|
||||
throw new IOException("can not run command on Ghostscript interpreter. gsapi_run_string_end failed with error code "
|
||||
+ exitCode.getValue());
|
||||
|
@ -228,53 +138,45 @@ public class Ghostscript implements AutoCloseable {
|
|||
}
|
||||
if (fileName != null) {
|
||||
IntByReference exitCode = new IntByReference();
|
||||
libraryInstance.gsapi_run_file(nativeInstanceByRef.getValue(), fileName, 0, exitCode);
|
||||
ret = libraryInstance.gsapi_run_file(pointer, fileName, 0, exitCode);
|
||||
if (exitCode.getValue() != 0) {
|
||||
throw new IOException("can not run file on Ghostscript interpreter, error code " + exitCode.getValue());
|
||||
throw new IOException("can not run file on Ghostscript interpreter, error code = " + exitCode.getValue());
|
||||
}
|
||||
logger.log(Level.FINE, "file completed: " + fileName);
|
||||
}
|
||||
return;
|
||||
return ret;
|
||||
}
|
||||
if (result < 0) {
|
||||
throw new IOException("can not initialize Ghostscript interpreter, error code " + result);
|
||||
if (ret < 0) {
|
||||
throw new IOException("can not initialize Ghostscript interpreter, error code = " + ret);
|
||||
}
|
||||
} finally {
|
||||
if (nativeInstanceByRef != null) {
|
||||
Pointer pointer = nativeInstanceByRef.getValue();
|
||||
if (pointer != null) {
|
||||
int result = libraryInstance.gsapi_exit(pointer);
|
||||
if (result != 0) {
|
||||
logger.log(Level.SEVERE, "can not call Ghostscript gsapi_exit, error code " + result);
|
||||
if (!quit && ret >= 0) {
|
||||
logger.log(Level.FINE, "exiting ghostscript instance " + libraryInstance);
|
||||
ret = libraryInstance.gsapi_exit(pointer);
|
||||
if (ret != 0) {
|
||||
logger.log(Level.SEVERE, "can not call Ghostscript gsapi_exit, error code " + ret);
|
||||
}
|
||||
logger.log(Level.FINE, "deleting ghostscript instance " + pointer);
|
||||
libraryInstance.gsapi_delete_instance(pointer);
|
||||
}
|
||||
} else {
|
||||
logger.log(Level.WARNING, "no pointer to exit");
|
||||
}
|
||||
libraryInstance.gsapi_delete_instance(nativeInstanceByRef.getValue());
|
||||
logger.log(Level.INFO, "ghostscript instance " + nativeInstanceByRef + " deleted");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void close() throws IOException {
|
||||
if (closed.compareAndSet(false, true)) {
|
||||
if (stdIn != null) {
|
||||
stdIn.close();
|
||||
stdIn = null;
|
||||
}
|
||||
if (stdOut != null) {
|
||||
stdOut.close();
|
||||
stdOut = null;
|
||||
}
|
||||
if (stdErr != null) {
|
||||
stdErr.close();
|
||||
stdErr = null;
|
||||
}
|
||||
if (libraryInstance != null) {
|
||||
libraryInstance.dispose();
|
||||
System.gc();
|
||||
logger.log(Level.INFO, "ghostscript library instance disposed and gc'ed()");
|
||||
logger.log(Level.FINE, "ghostscript library instance disposed and gc'ed()");
|
||||
} else {
|
||||
logger.log(Level.WARNING, "ghostscript library instance is null");
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package org.xbib.graphics.ghostscript;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import org.xbib.graphics.ghostscript.internal.LoggingOutputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -14,6 +13,7 @@ import java.nio.file.SimpleFileVisitor;
|
|||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -75,9 +75,16 @@ public class PDFConverter {
|
|||
*/
|
||||
private final PaperSize paperSize;
|
||||
|
||||
private final List<String> customGsArgs;
|
||||
|
||||
public PDFConverter() {
|
||||
this(OPTION_AUTOROTATEPAGES_OFF, OPTION_PROCESSCOLORMODEL_RGB,
|
||||
OPTION_PDFSETTINGS_PRINTER, "1.4", false, PaperSize.A4);
|
||||
OPTION_PDFSETTINGS_PRINTER, "1.4", false, PaperSize.A4, List.of());
|
||||
}
|
||||
|
||||
public PDFConverter(List<String> customGsArgs) {
|
||||
this(OPTION_AUTOROTATEPAGES_OFF, OPTION_PROCESSCOLORMODEL_RGB,
|
||||
OPTION_PDFSETTINGS_PRINTER, "1.4", false, PaperSize.A4, customGsArgs);
|
||||
}
|
||||
|
||||
public PDFConverter(int autoRotatePages,
|
||||
|
@ -85,41 +92,45 @@ public class PDFConverter {
|
|||
int pdfsettings,
|
||||
String compatibilityLevel,
|
||||
boolean pdfx,
|
||||
PaperSize paperSize) {
|
||||
PaperSize paperSize,
|
||||
List<String> customGsArgs) {
|
||||
this.autoRotatePages = autoRotatePages;
|
||||
this.processColorModel = processColorModel;
|
||||
this.pdfsettings = pdfsettings;
|
||||
this.compatibilityLevel = compatibilityLevel;
|
||||
this.pdfx = pdfx;
|
||||
this.paperSize = paperSize;
|
||||
this.customGsArgs = customGsArgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run method called to perform the actual process of the converter.
|
||||
*
|
||||
* @param inputStream the input document
|
||||
* @param outputStream output stream
|
||||
* @param inputStream the input stream
|
||||
* @param outputStream the output stream
|
||||
* @return the Ghostscript return code
|
||||
* @throws IOException if conversion fails
|
||||
*/
|
||||
public synchronized void convert(InputStream inputStream, OutputStream outputStream)
|
||||
throws IOException {
|
||||
if (outputStream == null) {
|
||||
return;
|
||||
}
|
||||
public synchronized int convert(InputStream inputStream,
|
||||
OutputStream outputStream) throws IOException {
|
||||
Objects.requireNonNull(inputStream, "inputStream must not be null");
|
||||
Objects.requireNonNull(outputStream, "outputStream must not be null");
|
||||
int ret;
|
||||
Path tmpPath = createTmpPath();
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
Path input = Files.createTempFile(tmpPath, "pdf", "pdf");
|
||||
try (OutputStream sourceOutputStream = Files.newOutputStream(input)) {
|
||||
inputStream.transferTo(sourceOutputStream);
|
||||
}
|
||||
Path output = Files.createTempFile(tmpPath, "pdf", "pdf");
|
||||
List<String> gsArgs = new LinkedList<>();
|
||||
gsArgs.add("-ps2pdf");
|
||||
List<String> gsArgs = new LinkedList<>(customGsArgs);
|
||||
gsArgs.add("-dNOSAFER");
|
||||
gsArgs.add("-dNOPAUSE");
|
||||
gsArgs.add("-dBATCH");
|
||||
gsArgs.add("-dSAFER");
|
||||
switch (autoRotatePages) {
|
||||
case OPTION_AUTOROTATEPAGES_NONE -> gsArgs.add("-dAutoRotatePages=/None");
|
||||
case OPTION_AUTOROTATEPAGES_ALL -> gsArgs.add("-dAutoRotatePages=/All");
|
||||
case OPTION_AUTOROTATEPAGES_PAGEBYPAGE -> gsArgs.add("-dAutoRotatePages=/PageByPage");
|
||||
default -> {
|
||||
}
|
||||
default -> gsArgs.add("-dAutoRotatePages=/None");
|
||||
}
|
||||
switch (processColorModel) {
|
||||
case OPTION_PROCESSCOLORMODEL_CMYK -> gsArgs.add("-dProcessColorModel=/DeviceCMYK");
|
||||
|
@ -134,21 +145,21 @@ public class PDFConverter {
|
|||
default -> gsArgs.add("-dPDFSETTINGS=/default");
|
||||
}
|
||||
gsArgs.add("-dCompatibilityLevel=" + compatibilityLevel);
|
||||
if (pdfx) {
|
||||
gsArgs.add("-dPDFX=" + pdfx);
|
||||
}
|
||||
gsArgs.add("-dDEVICEWIDTHPOINTS=" + paperSize.getWidth());
|
||||
gsArgs.add("-dDEVICEHEIGHTPOINTS=" + paperSize.getHeight());
|
||||
gsArgs.add("-sDEVICE=pdfwrite");
|
||||
gsArgs.add("-sOutputFile=" + output.toAbsolutePath().toString());
|
||||
gsArgs.add("-sOutputFile=" + output.toAbsolutePath());
|
||||
gsArgs.add("-f");
|
||||
gsArgs.add("-");
|
||||
gs.setStdIn(inputStream);
|
||||
gs.setStdOut(new LoggingOutputStream(logger));
|
||||
gs.setStdErr(new LoggingOutputStream(logger));
|
||||
gs.run(gsArgs.toArray(new String[0]));
|
||||
gsArgs.add(input.toString());
|
||||
ret = gs.run(gsArgs);
|
||||
Files.copy(output.toAbsolutePath(), outputStream);
|
||||
} finally {
|
||||
deleteTmpPath(tmpPath);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void deleteTmpPath(Path path) throws IOException {
|
||||
|
|
|
@ -15,7 +15,6 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream;
|
|||
import org.apache.pdfbox.pdmodel.common.PDRectangle;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
|
||||
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
|
||||
import org.xbib.graphics.ghostscript.internal.LoggingOutputStream;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.BufferedOutputStream;
|
||||
|
@ -72,8 +71,9 @@ public class PDFRasterizer {
|
|||
this.subject = subject;
|
||||
}
|
||||
|
||||
public synchronized void convert(Path source, Path target) throws IOException {
|
||||
logger.info("convert source=" + source + " target=" + target);
|
||||
public synchronized void convert(Path source,
|
||||
Path target) throws IOException {
|
||||
logger.log(Level.FINE, "convert source=" + source + " target=" + target);
|
||||
if (!Files.exists(source)) {
|
||||
throw new FileNotFoundException(source.toString());
|
||||
}
|
||||
|
@ -86,18 +86,19 @@ public class PDFRasterizer {
|
|||
Path tmpPath = createTmpPath();
|
||||
try {
|
||||
Path path = Files.createTempDirectory(tmpPath, "pdf-rasterize");
|
||||
pdfToImage(source, path, "pdf", null);
|
||||
pdfToImage(source, path, "pdf");
|
||||
Path tmpTarget = path.resolve(target.getFileName());
|
||||
mergeImagesToPDF(path, tmpTarget);
|
||||
scalePDF(tmpTarget, target);
|
||||
logger.info("convert source=" + source + " done");
|
||||
logger.log(Level.FINE, "convert source=" + source + " done");
|
||||
} finally {
|
||||
deleteTmpPath(tmpPath);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void screenConvert(Path source, Path target) throws IOException {
|
||||
logger.info("screen convert source=" + source.toAbsolutePath() + " target=" + target);
|
||||
public synchronized void screenConvert(Path source,
|
||||
Path target) throws IOException {
|
||||
logger.log(Level.FINE, "screen convert source=" + source.toAbsolutePath() + " target=" + target);
|
||||
if (!Files.exists(source.toAbsolutePath())) {
|
||||
throw new FileNotFoundException(source.toString());
|
||||
}
|
||||
|
@ -115,14 +116,15 @@ public class PDFRasterizer {
|
|||
mergeImagesToPDF(path, tmpTarget);
|
||||
//toPDFA(tmpTarget, target);
|
||||
scalePDF(tmpTarget, target);
|
||||
logger.info("screen convert source=" + source.toAbsolutePath() + " done");
|
||||
logger.log(Level.FINE, "screen convert source=" + source.toAbsolutePath() + " done");
|
||||
} finally {
|
||||
deleteTmpPath(tmpPath);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void pdfToGrayScreenImage(Path source, Path target) throws IOException {
|
||||
logger.info("pdfToGrayScreenImage source=" + source + " target=" + target);
|
||||
public synchronized void pdfToGrayScreenImage(Path source,
|
||||
Path target) throws IOException {
|
||||
logger.log(Level.FINE, "pdfToGrayScreenImage source=" + source + " target=" + target);
|
||||
if (!Files.exists(source.toAbsolutePath())) {
|
||||
throw new FileNotFoundException("not found: " + source);
|
||||
}
|
||||
|
@ -144,21 +146,25 @@ public class PDFRasterizer {
|
|||
gsArgs.add("-sOutputFile=" + target.resolve("screen-gray-pdf-%05d.png"));
|
||||
gsArgs.add("-f");
|
||||
gsArgs.add(source.toString());
|
||||
logger.info("pdfToImage args=" + gsArgs);
|
||||
logger.log(Level.FINE, "pdfToImage args=" + gsArgs);
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
gs.setStdIn(null);
|
||||
gs.setStdOut(new LoggingOutputStream(logger));
|
||||
gs.setStdErr(new LoggingOutputStream(logger));
|
||||
gs.run(gsArgs.toArray(new String[0]));
|
||||
logger.info("pdfToImage done");
|
||||
gs.run(gsArgs);
|
||||
logger.log(Level.FINE, "pdfToImage done");
|
||||
}
|
||||
}
|
||||
|
||||
public void pdfToImage(Path sourceFile,
|
||||
Path targetDir,
|
||||
String prefix) throws IOException {
|
||||
pdfToImage(sourceFile, targetDir, prefix, null, null);
|
||||
}
|
||||
|
||||
public synchronized void pdfToImage(Path sourceFile,
|
||||
Path targetDir,
|
||||
String prefix,
|
||||
String pageRange) throws IOException {
|
||||
logger.info("pdfToImage source=" + sourceFile + " target=" + targetDir + " started");
|
||||
String firstPage,
|
||||
String lastPage) throws IOException {
|
||||
logger.log(Level.FINE, "pdfToImage source=" + sourceFile + " target=" + targetDir + " started");
|
||||
List<String> gsArgs = new LinkedList<>();
|
||||
gsArgs.add("-dNOPAUSE");
|
||||
gsArgs.add("-dBATCH");
|
||||
|
@ -167,9 +173,11 @@ public class PDFRasterizer {
|
|||
gsArgs.add("-dINTERPOLATE");
|
||||
// how do we know we have a crop box or not?
|
||||
gsArgs.add("-dUseCropBox");
|
||||
// page range, if not null
|
||||
if (pageRange != null) {
|
||||
gsArgs.add("-sPageList=" + pageRange);
|
||||
if (firstPage != null) {
|
||||
gsArgs.add("-sFirstPage=" + firstPage);
|
||||
}
|
||||
if (lastPage != null) {
|
||||
gsArgs.add("-sLastPage=" + lastPage);
|
||||
}
|
||||
gsArgs.add("-sDEVICE=png16m");
|
||||
gsArgs.add("-r300");
|
||||
|
@ -181,23 +189,21 @@ public class PDFRasterizer {
|
|||
gsArgs.add("100000000 setvmthreshold");
|
||||
gsArgs.add("-f");
|
||||
gsArgs.add(sourceFile.toString());
|
||||
logger.info("pdfToImage args=" + gsArgs);
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
// reset stdin
|
||||
gs.setStdIn(null);
|
||||
gs.setStdOut(new LoggingOutputStream(logger));
|
||||
gs.setStdErr(new LoggingOutputStream(logger));
|
||||
gs.run(gsArgs.toArray(new String[0]));
|
||||
logger.info("pdfToImage done");
|
||||
gs.run(gsArgs);
|
||||
logger.log(Level.FINE, "pdfToImage done");
|
||||
}
|
||||
}
|
||||
|
||||
public int mergeImagesToPDF(Path sourceDir, Path targetFile) throws IOException {
|
||||
public int mergeImagesToPDF(Path sourceDir,
|
||||
Path targetFile) throws IOException {
|
||||
return mergeImagesToPDF(sourceDir, targetFile, "**/*");
|
||||
}
|
||||
|
||||
public synchronized int mergeImagesToPDF(Path sourceDir, Path targetFile, String globPattern) throws IOException {
|
||||
logger.info("mergeImagesToPDF: source=" + sourceDir + " target=" + targetFile + " glob =" + globPattern);
|
||||
public synchronized int mergeImagesToPDF(Path sourceDir,
|
||||
Path targetFile,
|
||||
String globPattern) throws IOException {
|
||||
logger.log(Level.FINE, "mergeImagesToPDF: source=" + sourceDir + " target=" + targetFile + " glob =" + globPattern);
|
||||
AtomicInteger pagecount = new AtomicInteger();
|
||||
PathMatcher pathMatcher = sourceDir.getFileSystem().getPathMatcher("glob:" + globPattern);
|
||||
List<PDDocument> coverPageDocs = new ArrayList<>();
|
||||
|
@ -222,7 +228,7 @@ public class PDFRasterizer {
|
|||
}
|
||||
for (Path path : entries) {
|
||||
if (path.getFileName().toString().toLowerCase(Locale.ROOT).endsWith(".pdf")) {
|
||||
logger.info("found pdf " + path);
|
||||
logger.log(Level.FINE, "found pdf " + path);
|
||||
try (InputStream inputStream = Files.newInputStream(path)) {
|
||||
PDDocument doc = Loader.loadPDF(inputStream.readAllBytes());
|
||||
for (int i = 0; i < doc.getNumberOfPages(); i++) {
|
||||
|
@ -266,7 +272,7 @@ public class PDFRasterizer {
|
|||
}
|
||||
}
|
||||
pdDocument.save(outputStream);
|
||||
logger.info("mergeImagesToPDF: done, " + pagecount.get() + " pages");
|
||||
logger.log(Level.FINE, "pagesToPDF: done, " + pagecount.get() + " pages");
|
||||
} finally {
|
||||
for (PDDocument pd : coverPageDocs) {
|
||||
pd.close();
|
||||
|
@ -277,7 +283,7 @@ public class PDFRasterizer {
|
|||
|
||||
public synchronized void scalePDF(Path sourceFile,
|
||||
Path targetFile) throws IOException {
|
||||
logger.info("scalePDF: source = " + sourceFile + " target = " + targetFile + " starting");
|
||||
logger.log(Level.FINE, "scalePDF: source = " + sourceFile + " target = " + targetFile + " starting");
|
||||
List<String> gsArgs = new LinkedList<>();
|
||||
gsArgs.add("-dNOPAUSE");
|
||||
gsArgs.add("-dBATCH");
|
||||
|
@ -292,10 +298,27 @@ public class PDFRasterizer {
|
|||
gsArgs.add("-sOutputFile=" + targetFile.toString());
|
||||
gsArgs.add(sourceFile.toString());
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
gs.setStdIn(null);
|
||||
logger.info(gsArgs.toString());
|
||||
gs.run(gsArgs.toArray(new String[0]));
|
||||
logger.info("scalePDF: source = " + sourceFile + " target = " + targetFile + " done");
|
||||
gs.run(gsArgs);
|
||||
logger.log(Level.FINE, "scalePDF: source = " + sourceFile + " target = " + targetFile + " done");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void downgradePDF(Path sourceFile,
|
||||
Path targetFile) throws IOException {
|
||||
logger.log(Level.FINE, "downgradePDF: source = " + sourceFile + " target = " + targetFile + " starting");
|
||||
List<String> gsArgs = new LinkedList<>();
|
||||
gsArgs.add("-dNOPAUSE");
|
||||
gsArgs.add("-dBATCH");
|
||||
gsArgs.add("-dQUIET");
|
||||
gsArgs.add("-dPDFSETTINGS=/printer");
|
||||
gsArgs.add("-dFIXEDMEDIA");
|
||||
gsArgs.add("-dCompatibilityLevel=1.4");
|
||||
gsArgs.add("-sDEVICE=pdfwrite");
|
||||
gsArgs.add("-sOutputFile=" + targetFile.toString());
|
||||
gsArgs.add(sourceFile.toString());
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
gs.run(gsArgs);
|
||||
logger.log(Level.FINE, "downgradePDF: source = " + sourceFile + " target = " + targetFile + " done");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,14 +356,16 @@ public class PDFRasterizer {
|
|||
gsArgs.add("-sOutputFile=" + target.toString());
|
||||
gsArgs.add(pdfapsPath.toAbsolutePath().toString());
|
||||
gsArgs.add(source.toString());
|
||||
gs.setStdIn(null);
|
||||
gs.run(gsArgs.toArray(new String[0]));
|
||||
gs.run(gsArgs);
|
||||
} finally {
|
||||
deleteTmpPath(tmpPath);
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyAndReplace(Path source, Path target, String from, String to) throws IOException {
|
||||
private static void copyAndReplace(Path source,
|
||||
Path target,
|
||||
String from,
|
||||
String to) throws IOException {
|
||||
try (BufferedReader br = Files.newBufferedReader(source); BufferedWriter bw = Files.newBufferedWriter(target)) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
package org.xbib.graphics.ghostscript;
|
||||
|
||||
public class PageRaster {
|
||||
|
||||
private int width;
|
||||
|
||||
private int height;
|
||||
|
||||
private int raster;
|
||||
|
||||
private int format;
|
||||
|
||||
private byte[] data;
|
||||
|
||||
public PageRaster() {
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public int getRaster() {
|
||||
return raster;
|
||||
}
|
||||
|
||||
public void setRaster(int raster) {
|
||||
this.raster = raster;
|
||||
}
|
||||
|
||||
public int getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(int format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
|
@ -21,23 +21,20 @@ public class GhostscriptLibraryLoader {
|
|||
};
|
||||
|
||||
private static final String[] MAC_LIBNAMES = {
|
||||
"libgs.9.54.dylib",
|
||||
"libgs.9.54",
|
||||
"gs.9.54",
|
||||
"libgs.9.25.dylib",
|
||||
"libgs.9.25",
|
||||
"gs.9.25",
|
||||
"libgs.dylib",
|
||||
"gs.9.26",
|
||||
"gs",
|
||||
};
|
||||
|
||||
private GhostscriptLibrary ghostscriptLibrary;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public GhostscriptLibraryLoader() {
|
||||
Map<String, Object> options = Map.of(Library.OPTION_CALLING_CONVENTION, Function.C_CONVENTION,
|
||||
Library.OPTION_INVOCATION_MAPPER, (InvocationMapper) (lib, m) -> {
|
||||
if (m.getName().equals("dispose")) {
|
||||
return (proxy, method, args) -> {
|
||||
// we use the deprecated dispose() call here by intention
|
||||
lib.dispose();
|
||||
return null;
|
||||
};
|
||||
|
@ -51,7 +48,7 @@ public class GhostscriptLibraryLoader {
|
|||
for (String libname : libnames) {
|
||||
try {
|
||||
this.ghostscriptLibrary = Native.load(libname, GhostscriptLibrary.class, options);
|
||||
} catch (Error e) {
|
||||
} catch (Exception | Error e) {
|
||||
logger.log(Level.WARNING, "library " + libname + " not found", e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
package org.xbib.graphics.ghostscript.internal;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class LoggingOutputStream extends ByteArrayOutputStream {
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
public LoggingOutputStream(Logger logger) {
|
||||
super();
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
super.flush();
|
||||
String s = new String(buf, 0, count);
|
||||
if (s.length() > 0) {
|
||||
logger.log(Level.FINE, s);
|
||||
}
|
||||
reset();
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package org.xbib.graphics.ghostscript.internal;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class NullOutputStream extends OutputStream {
|
||||
|
||||
@Override
|
||||
public void write(int b) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) {
|
||||
}
|
||||
}
|
|
@ -1,23 +1,24 @@
|
|||
package org.xbib.graphics.ghostscript.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.ghostscript.Ghostscript;
|
||||
import org.xbib.graphics.ghostscript.GhostscriptRevision;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
public class GhostscriptTest {
|
||||
public class BasicGhostscriptTest {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(GhostscriptTest.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(BasicGhostscriptTest.class.getName());
|
||||
|
||||
private static final String dir = "src/test/resources/org/xbib/graphics/ghostscript/test/";
|
||||
|
||||
|
@ -39,7 +40,7 @@ public class GhostscriptTest {
|
|||
@Test
|
||||
public void testExit() {
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
String[] args = {"-dNODISPLAY", "-dQUIET"};
|
||||
List<String> args = List.of("-dNODISPLAY", "-dQUIET");
|
||||
gs.run(args);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
|
@ -50,7 +51,7 @@ public class GhostscriptTest {
|
|||
@Test
|
||||
public void testRunString() {
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
String[] args = {"-dNODISPLAY", "-dQUIET"};
|
||||
List<String> args = List.of("-dNODISPLAY", "-dQUIET");
|
||||
gs.run(args, "devicenames ==", null);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
|
@ -63,7 +64,7 @@ public class GhostscriptTest {
|
|||
@Test
|
||||
public void testRunFile() {
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
String[] args = {"-dNODISPLAY", "-dQUIET", "-dNOPAUSE", "-dBATCH", "-dSAFER"};
|
||||
List<String> args = List.of("-dNODISPLAY", "-dQUIET", "-dNOPAUSE", "-dBATCH", "-dSAFER");
|
||||
gs.run(args, null, dir + "input.ps");
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
|
@ -73,45 +74,38 @@ public class GhostscriptTest {
|
|||
}
|
||||
}
|
||||
|
||||
// This test throws core dump.
|
||||
// [libgs.so.9.25+0x32dc11] clump_splay_walk_fwd+0x31
|
||||
// [libgs.so.9.56+0x32bcf4] clump_splay_walk_fwd+0x34
|
||||
@Disabled("core dump")
|
||||
@Test
|
||||
public void testStdIn() {
|
||||
try (Ghostscript gs = new Ghostscript();
|
||||
InputStream is = new FileInputStream(dir + "input.ps")) {
|
||||
gs.setStdIn(is);
|
||||
String[] args = {"-dNODISPLAY", "-dQUIET", "-dNOPAUSE", "-dBATCH", "-sOutputFile=%stdout", "-f", "-"};
|
||||
gs.run(args);
|
||||
public void testStdOut() throws Exception {
|
||||
Path path = Paths.get("build/devicenames");
|
||||
try (OutputStream outputStream = Files.newOutputStream(path)) {
|
||||
outputStream.write("devicenames ==\n".getBytes());
|
||||
}
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
List<String> args = List.of("-dNODISPLAY", "-sOutputFile=%stdout", "-f", path.toString());
|
||||
int ret = gs.run(args);
|
||||
} catch (Exception e) {
|
||||
fail(e.getMessage());
|
||||
} finally {
|
||||
Files.delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStdOut() {
|
||||
try (Ghostscript gs = new Ghostscript();
|
||||
InputStream is = new ByteArrayInputStream("devicenames ==\n".getBytes())) {
|
||||
gs.setStdIn(is);
|
||||
String[] args = { "-dNODISPLAY", "-sOutputFile=%stdout", "-f", "-" };
|
||||
gs.run(args);
|
||||
public void testStdErr() throws Exception {
|
||||
Path path = Paths.get("build/broken");
|
||||
try (OutputStream outputStream = Files.newOutputStream(path)) {
|
||||
outputStream.write("foobar\n".getBytes());
|
||||
}
|
||||
try (Ghostscript gs = new Ghostscript()) {
|
||||
List<String> args = List.of("-dNODISPLAY", "-sOutputFile=%stdout", "-f", path.toString());
|
||||
int ret = gs.run(args);
|
||||
} catch (Exception e) {
|
||||
// expect error
|
||||
if (!e.getMessage().contains("error code = -100")) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStdErr() {
|
||||
try (Ghostscript gs = new Ghostscript();
|
||||
InputStream is = new ByteArrayInputStream("stupid\n".getBytes())) {
|
||||
gs.setStdIn(is);
|
||||
String[] args = { "-dNODISPLAY", "-sOutputFile=%stdout", "-f", "-" };
|
||||
gs.run(args);
|
||||
} catch (Exception e) {
|
||||
if (!e.getMessage().contains("error code -100")) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
} finally {
|
||||
Files.delete(path);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +1,15 @@
|
|||
package org.xbib.graphics.ghostscript.test;
|
||||
|
||||
import com.sun.jna.ptr.IntByReference;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.xbib.graphics.ghostscript.internal.GhostscriptLibrary;
|
||||
import org.xbib.graphics.ghostscript.internal.GhostscriptLibraryLoader;
|
||||
|
||||
public class GhostScriptLibraryTester {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(GhostScriptLibraryTester.class.getName());
|
||||
|
||||
private final GhostscriptLibrary ghostscriptLibrary;
|
||||
|
||||
public GhostScriptLibraryTester() {
|
||||
|
@ -33,7 +37,7 @@ public class GhostScriptLibraryTester {
|
|||
GhostscriptLibrary.gs_main_instance.ByReference instanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
|
||||
ghostscriptLibrary.gsapi_new_instance(instanceByRef.getPointer(), null);
|
||||
String[] args = {
|
||||
"-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
|
||||
"gs", "-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
|
||||
};
|
||||
ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(), args.length, args);
|
||||
IntByReference exitCode = new IntByReference();
|
||||
|
@ -47,10 +51,8 @@ public class GhostScriptLibraryTester {
|
|||
GhostscriptLibrary.gs_main_instance.ByReference instanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
|
||||
ghostscriptLibrary.gsapi_new_instance(instanceByRef.getPointer(), null);
|
||||
String[] args = {
|
||||
"ps2pdf",
|
||||
"-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER", "-sDEVICE=pdfwrite",
|
||||
"-sOutputFile=" + output,
|
||||
"-c", ".setpdfwrite", "-f", input
|
||||
"ps2pdf", "-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER", "-sDEVICE=pdfwrite",
|
||||
"-sOutputFile=" + output, "-f", input
|
||||
};
|
||||
int result = ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(), args.length, args);
|
||||
ghostscriptLibrary.gsapi_exit(instanceByRef.getValue());
|
||||
|
@ -62,7 +64,7 @@ public class GhostScriptLibraryTester {
|
|||
GhostscriptLibrary.gs_main_instance.ByReference instanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
|
||||
ghostscriptLibrary.gsapi_new_instance(instanceByRef.getPointer(), null);
|
||||
String[] args = {
|
||||
"-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
|
||||
"gs", "-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
|
||||
};
|
||||
ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(), args.length, args);
|
||||
IntByReference exitCode = new IntByReference();
|
||||
|
@ -77,7 +79,7 @@ public class GhostScriptLibraryTester {
|
|||
GhostscriptLibrary.gs_main_instance.ByReference instanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
|
||||
ghostscriptLibrary.gsapi_new_instance(instanceByRef.getPointer(), null);
|
||||
String[] args = {
|
||||
"-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
|
||||
"gs", "-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
|
||||
};
|
||||
ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(), args.length, args);
|
||||
IntByReference exitCode = new IntByReference();
|
||||
|
@ -94,7 +96,7 @@ public class GhostScriptLibraryTester {
|
|||
GhostscriptLibrary.gs_main_instance.ByReference instanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
|
||||
ghostscriptLibrary.gsapi_new_instance(instanceByRef.getPointer(), null);
|
||||
String[] args = {
|
||||
"-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
|
||||
"gs", "-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
|
||||
};
|
||||
ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(), args.length, args);
|
||||
IntByReference exitCode = new IntByReference();
|
||||
|
@ -108,9 +110,7 @@ public class GhostScriptLibraryTester {
|
|||
GhostscriptLibrary.gs_main_instance.ByReference instanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
|
||||
ghostscriptLibrary.gsapi_new_instance(instanceByRef.getPointer(), null);
|
||||
final StringBuilder stdOutBuffer = new StringBuilder();
|
||||
final StringBuilder stdInBuffer = new StringBuilder();
|
||||
GhostscriptLibrary.stdin_fn stdinCallback = (caller_handle, buf, len) -> {
|
||||
stdInBuffer.append("OK");
|
||||
return 0;
|
||||
};
|
||||
GhostscriptLibrary.stdout_fn stdoutCallback = (caller_handle, str, len) -> {
|
||||
|
@ -120,8 +120,7 @@ public class GhostScriptLibraryTester {
|
|||
GhostscriptLibrary.stderr_fn stderrCallback = (caller_handle, str, len) -> len;
|
||||
ghostscriptLibrary.gsapi_set_stdio(instanceByRef.getValue(), stdinCallback, stdoutCallback, stderrCallback);
|
||||
String[] args = {
|
||||
"-dNODISPLAY", "-dQUIET", "-dNOPAUSE", "-dBATCH",
|
||||
"-sOutputFile=%stdout", "-f", "-"
|
||||
"gs", "-dNODISPLAY", "-dQUIET", "-dNOPAUSE", "-dBATCH", "-sOutputFile=%stdout", "-f", "-"
|
||||
};
|
||||
ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(),
|
||||
args.length, args);
|
||||
|
@ -130,6 +129,8 @@ public class GhostScriptLibraryTester {
|
|||
ghostscriptLibrary.gsapi_run_string_with_length(instanceByRef.getValue(), command, command.length(), 0, exitCode);
|
||||
ghostscriptLibrary.gsapi_exit(instanceByRef.getValue());
|
||||
ghostscriptLibrary.gsapi_delete_instance(instanceByRef.getValue());
|
||||
logger.log(Level.FINE, stdOutBuffer.toString());
|
||||
|
||||
}
|
||||
|
||||
public String setDisplayCallback() {
|
||||
|
@ -176,7 +177,7 @@ public class GhostScriptLibraryTester {
|
|||
displayCallback.size = displayCallback.size();
|
||||
ghostscriptLibrary.gsapi_set_display_callback(instanceByRef.getValue(), displayCallback);
|
||||
String[] args = new String[]{
|
||||
"-dQUIET", "-dNOPAUSE", "-dBATCH", "-dSAFER",
|
||||
"gs", "-dQUIET", "-dNOPAUSE", "-dBATCH", "-dSAFER",
|
||||
"-sDEVICE=display", "-sDisplayHandle=0", "-dDisplayFormat=16#a0800"
|
||||
};
|
||||
ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(), args.length, args);
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package org.xbib.graphics.ghostscript.test;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
@ -19,9 +19,10 @@ public class GhostscriptLibraryTest {
|
|||
private static GhostScriptLibraryTester gslib;
|
||||
|
||||
@BeforeAll
|
||||
public static void setUp() throws Exception {
|
||||
public static void setUp() {
|
||||
logger.log(Level.INFO, "setUp: loading ghostscript library");
|
||||
gslib = new GhostScriptLibraryTester();
|
||||
logger.info("setUp: ghostscript library loaded");
|
||||
logger.log(Level.INFO, "setUp: ghostscript library loaded");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -35,13 +36,10 @@ public class GhostscriptLibraryTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Disabled("GPL Ghostscript 9.54.0: Unrecoverable error, exit code 1")
|
||||
public void gsapiInitWithArgs() {
|
||||
String input = dir + "input.ps";
|
||||
String output = "build/output.pdf";
|
||||
gslib.withInput(input, output);
|
||||
File outputFile = new File(output);
|
||||
assertTrue(outputFile.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -70,9 +68,10 @@ public class GhostscriptLibraryTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Disabled
|
||||
public void gsapiSetDisplayCallback() {
|
||||
String display = gslib.setDisplayCallback();
|
||||
assertEquals("OPEN-PRESIZE-UPDATE-SIZE-PAGE-UPDATE-SYNC-PRECLOSE-CLOSE", display);
|
||||
assertTrue(Set.of("OPEN-PRESIZE-UPDATE-SIZE-PRECLOSE-CLOSEOPEN-PRESIZE-UPDATE-SIZE-UPDATE-PAGE-PRECLOSE-CLOSE", // gs 9.54
|
||||
"OPEN-PRESIZE-UPDATE-SIZE-UPDATE-PRECLOSE-CLOSEOPEN-PRESIZE-UPDATE-SIZE-PAGE-UPDATE-PRECLOSE-CLOSE") // gs 10
|
||||
.contains(display));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,32 @@
|
|||
package org.xbib.graphics.ghostscript.test;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.ghostscript.PDFConverter;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class PDFConverterTest {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(PDFConverterTest.class.getName());
|
||||
|
||||
@Test
|
||||
public void testConvertWithPS() throws Exception {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
PDFConverter converter = new PDFConverter();
|
||||
converter.convert(getClass().getClassLoader().getResourceAsStream("input.ps"), baos);
|
||||
assertTrue(baos.size() > 0);
|
||||
baos.close();
|
||||
assertTrue(baos.toString(StandardCharsets.UTF_8).startsWith("%PDF-1.4"));
|
||||
PDFConverter converter = new PDFConverter(List.of("ps2pdf"));
|
||||
try (InputStream inputStream = getClass().getResourceAsStream("input.ps");
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
converter.convert(inputStream, outputStream);
|
||||
assertTrue(outputStream.size() > 0);
|
||||
assertTrue(outputStream.toString(StandardCharsets.UTF_8).startsWith("%PDF-1.4"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -25,13 +34,13 @@ public class PDFConverterTest {
|
|||
final ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
|
||||
final ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
|
||||
final ByteArrayOutputStream baos3 = new ByteArrayOutputStream();
|
||||
final PDFConverter converter = new PDFConverter();
|
||||
final PDFConverter converter = new PDFConverter(List.of("ps2pdf"));
|
||||
Thread thread1 = new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
converter.convert(this.getClass().getClassLoader().getResourceAsStream("input.ps"), baos1);
|
||||
converter.convert(this.getClass().getResourceAsStream("input.ps"), baos1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -39,9 +48,9 @@ public class PDFConverterTest {
|
|||
Thread thread2 = new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
converter.convert(this.getClass().getClassLoader().getResourceAsStream("input.ps"), baos2);
|
||||
converter.convert(this.getClass().getResourceAsStream("input.ps"), baos2);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -49,9 +58,9 @@ public class PDFConverterTest {
|
|||
Thread thread3 = new Thread() {
|
||||
public void run() {
|
||||
try {
|
||||
converter.convert(this.getClass().getClassLoader().getResourceAsStream("input.ps"), baos3);
|
||||
converter.convert(this.getClass().getResourceAsStream("input.ps"), baos3);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -69,9 +78,19 @@ public class PDFConverterTest {
|
|||
|
||||
@Test
|
||||
public void testConvertWithUnsupportedDocument() throws Exception {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
PDFConverter converter = new PDFConverter();
|
||||
converter.convert(this.getClass().getClassLoader().getResourceAsStream("input.pdf"), baos);
|
||||
baos.close();
|
||||
try (InputStream inputStream = getClass().getResourceAsStream("input.pdf");
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
converter.convert(inputStream, outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertDistiller() throws Exception {
|
||||
PDFConverter converter = new PDFConverter(List.of("-dFIXEDMEDIA", "-dPDFFitPage"));
|
||||
try (InputStream inputStream = getClass().getResourceAsStream("3977940_retrieve_74_.pdf");
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
|
||||
converter.convert(inputStream, outputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public class PDFRasterizerTest {
|
|||
Path targetFile = Paths.get("build/color.pdf");
|
||||
PDFRasterizer pdfRasterizer = new PDFRasterizer();
|
||||
int pagecount = pdfRasterizer.mergeImagesToPDF(sourceDir, targetFile);
|
||||
logger.info("pagecount = " + pagecount);
|
||||
logger.log(Level.FINE, "pagecount = " + pagecount);
|
||||
assertEquals(1, pagecount);
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ public class PDFRasterizerTest {
|
|||
Path targetFile = Paths.get("build/3656573.pdf");
|
||||
PDFRasterizer pdfRasterizer = new PDFRasterizer();
|
||||
int pagecount = pdfRasterizer.mergeImagesToPDF(sourceDir, targetFile);
|
||||
logger.info("pagecount = " + pagecount);
|
||||
logger.log(Level.FINE, "pagecount = " + pagecount);
|
||||
assertEquals(9, pagecount);
|
||||
}
|
||||
|
||||
|
@ -50,10 +50,10 @@ public class PDFRasterizerTest {
|
|||
int pagecount = 0;
|
||||
try {
|
||||
PDFRasterizer pdfRasterizer = new PDFRasterizer();
|
||||
pdfRasterizer.pdfToImage(source, path, null, null);
|
||||
pdfRasterizer.pdfToImage(source, path, "test");
|
||||
Path tmpTarget = path.resolve(target.getFileName());
|
||||
pagecount = pdfRasterizer.mergeImagesToPDF(path, tmpTarget);
|
||||
logger.info("pagecount = " + pagecount);
|
||||
logger.log(Level.FINE, "pagecount = " + pagecount);
|
||||
pdfRasterizer.scalePDF(tmpTarget, target);
|
||||
} finally {
|
||||
delete(path);
|
||||
|
@ -61,6 +61,14 @@ public class PDFRasterizerTest {
|
|||
assertEquals(28, pagecount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDowngrade() throws IOException {
|
||||
Path source = Paths.get("src/test/resources/org/xbib/graphics/ghostscript/test/3977940_retrieve_74_.pdf");
|
||||
Path target = Paths.get("build/3977940-new.pdf");
|
||||
PDFRasterizer pdfRasterizer = new PDFRasterizer();
|
||||
pdfRasterizer.downgradePDF(source, target);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPDFRasterizerToImage() throws Exception {
|
||||
Path path = Paths.get("build/resources/test");
|
||||
|
@ -72,7 +80,7 @@ public class PDFRasterizerTest {
|
|||
delete(target);
|
||||
Files.createDirectories(target);
|
||||
PDFRasterizer rasterizer = new PDFRasterizer();
|
||||
rasterizer.pdfToImage(p, target, "pdf-", "1-");
|
||||
rasterizer.pdfToImage(p, target, "pdf-");
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.SEVERE, e.getMessage(), e);
|
||||
fail(e);
|
||||
|
@ -88,7 +96,7 @@ public class PDFRasterizerTest {
|
|||
try (Stream<Path> stream = Files.list(path)) {
|
||||
stream.forEach(p -> {
|
||||
if (p.toString().endsWith(".pdf")) {
|
||||
logger.info("found " + p.toString());
|
||||
logger.log(Level.FINE, "found " + p);
|
||||
Path target = Paths.get("build/" + p.getFileName());
|
||||
try {
|
||||
delete(target);
|
||||
|
|
Binary file not shown.
3
graphics-jpeg2000/build.gradle
Normal file
3
graphics-jpeg2000/build.gradle
Normal file
|
@ -0,0 +1,3 @@
|
|||
dependencies {
|
||||
testImplementation testLibs.assertj
|
||||
}
|
11
graphics-jpeg2000/src/main/java/module-info.java
Normal file
11
graphics-jpeg2000/src/main/java/module-info.java
Normal file
|
@ -0,0 +1,11 @@
|
|||
import org.xbib.graphics.jpeg2000.imageio.JPEG2000ReaderSpi;
|
||||
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
|
||||
module org.xbib.graphics.jpegtwothousand {
|
||||
requires java.desktop;
|
||||
exports org.xbib.graphics.jpeg2000;
|
||||
exports org.xbib.graphics.jpeg2000.imageio;
|
||||
uses ImageReaderSpi;
|
||||
provides ImageReaderSpi with JPEG2000ReaderSpi;
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class is defined to represent a Bits Per Component Box of JPEG
|
||||
* JP2 file format. A Bits Per Component box has a length, and a fixed
|
||||
* type of "bpcc". Its content is a byte array containing the bit
|
||||
* depths of the color components.
|
||||
* <p>
|
||||
* This box is necessary only when the bit depth are not identical for all
|
||||
* the components.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class BitsPerComponentBox extends Box {
|
||||
|
||||
private byte[] data;
|
||||
|
||||
public BitsPerComponentBox() {
|
||||
super(fromString("bpcc"));
|
||||
}
|
||||
|
||||
public BitsPerComponentBox(byte[] bitDepth) {
|
||||
this();
|
||||
this.data = bitDepth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return data.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
data = new byte[in.length()];
|
||||
in.readFully(data, 0, data.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.write(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bit depths for all the image components.
|
||||
*/
|
||||
public byte[] getBitDepth() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeStartElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
out.writeStartElement("bpc");
|
||||
out.writeCharacters(Integer.toString(data[i] & 0xFF));
|
||||
out.writeEndElement();
|
||||
}
|
||||
out.writeEndElement();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(",\"bpc\":[");
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(data[i]);
|
||||
}
|
||||
sb.append("]}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class is defined to create the box of JP2 file format. A box has
|
||||
* a length, a type, an optional extra length and its content. The subclasses
|
||||
* should explain the content information.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class Box {
|
||||
|
||||
private static final Map<Integer, Class<? extends Box>> boxClasses = new HashMap<Integer, Class<? extends Box>>();
|
||||
|
||||
static {
|
||||
//children for the root
|
||||
boxClasses.put(Integer.valueOf(fromString("ftyp")), FileTypeBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("jp2h")), HeaderBox.class);
|
||||
// boxClasses.put(Integer.valueOf(0x69686472), LabelBox.class); // L.9.13
|
||||
boxClasses.put(Integer.valueOf(fromString("ihdr")), ImageHeaderBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("bpcc")), BitsPerComponentBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("colr")), ColorSpecificationBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("pclr")), PaletteBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("cmap")), ComponentMappingBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("cdef")), ChannelDefinitionBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("res ")), ResolutionSuperBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("resc")), RescBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("resd")), ResdBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("jp2c")), CodeStreamBox.class);
|
||||
// boxClasses.put(Integer.valueOf(0x6A703269), IntellectualPropertyBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("xml ")), XMLBox.class); // L.9.18
|
||||
boxClasses.put(Integer.valueOf(fromString("uuid")), UUIDBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("uinf")), UUIDInfoBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("ulst")), UUIDListBox.class);
|
||||
boxClasses.put(Integer.valueOf(fromString("url ")), URLBox.class);
|
||||
|
||||
// Children of JPEG2000UUIDInfoBox
|
||||
}
|
||||
|
||||
private final int type;
|
||||
private byte[] raw;
|
||||
|
||||
public Box(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static int fromString(String s) {
|
||||
if (s.length() != 4) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return (s.charAt(0) << 24) | (s.charAt(1) << 16) | (s.charAt(2) << 8) | s.charAt(3);
|
||||
}
|
||||
|
||||
public static String toString(byte[] v) {
|
||||
String s = new BigInteger(1, v).toString(16);
|
||||
if ((s.length() & 1) == 1) {
|
||||
s = "0" + s;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public static String toString(int v) {
|
||||
StringBuilder sb = new StringBuilder(4);
|
||||
for (int i = 24; i >= 0; i -= 8) {
|
||||
int c = (v >> i) & 0xFF;
|
||||
if (c >= 0x20 && c <= 0x7f) {
|
||||
sb.append((char) c);
|
||||
} else {
|
||||
String s = "0000000" + Integer.toHexString(v);
|
||||
return "0x" + s.substring(s.length() - 8);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static Box createBox(int type) {
|
||||
Class<? extends Box> cl = boxClasses.get(type);
|
||||
if (cl == null) {
|
||||
return new Box(type);
|
||||
} else {
|
||||
try {
|
||||
return cl.newInstance();
|
||||
} catch (InstantiationException e) {
|
||||
if (e.getCause() instanceof RuntimeException) {
|
||||
throw (RuntimeException) e.getCause();
|
||||
}
|
||||
// Shouldn't happen
|
||||
throw new Error("Failed during box creation", e);
|
||||
} catch (Exception e) {
|
||||
// Shouldn't happen
|
||||
throw new Error("Failed during box creation", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the content from the specified IO, which should be truncated
|
||||
* to the correct length. The current position of the specified "in"
|
||||
* is at the start of the "box contents" (DBox field)
|
||||
*/
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
raw = new byte[in.length()];
|
||||
in.readFully(raw, 0, raw.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the content of this box to the OutputStream. The content
|
||||
* itself is written, not the length
|
||||
*/
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.write(raw);
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
return raw == null ? 0 : raw.length;
|
||||
}
|
||||
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeStartElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
if (raw != null) {
|
||||
out.writeCharacters(toString(raw));
|
||||
}
|
||||
out.writeEndElement();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String sb = "{\"type\":\"" +
|
||||
toString(type) +
|
||||
"\",\"length\":" +
|
||||
getLength() +
|
||||
"}";
|
||||
return sb;
|
||||
}
|
||||
|
||||
public static class RescBox extends ResolutionBox {
|
||||
RescBox() {
|
||||
super(fromString("resc"));
|
||||
}
|
||||
}
|
||||
|
||||
public static class ResdBox extends ResolutionBox {
|
||||
ResdBox() {
|
||||
super(fromString("resd"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* This class is designed to represent a Channel Definition Box of
|
||||
* JPEG JP2 file format. A Channel Definition Box has a length, and
|
||||
* a fixed type of "cdef". Its content defines the type of the image
|
||||
* channels: color channel, alpha channel or premultiplied alpha channel.
|
||||
* <p>
|
||||
* CORRECTION - it is actually "ComponentDefinitionBox" in the spec.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class ChannelDefinitionBox extends Box {
|
||||
|
||||
/**
|
||||
* The cached data elements.
|
||||
*/
|
||||
private short num;
|
||||
private short[] channels;
|
||||
private short[] types;
|
||||
private short[] associations;
|
||||
|
||||
public ChannelDefinitionBox() {
|
||||
super(fromString("cdef"));
|
||||
}
|
||||
|
||||
/** Constructs a <code>ChannelDefinitionBox</code> based on the provided <code>ColorModel</code>.
|
||||
*
|
||||
* This was from JAI but is untested by BFO
|
||||
*
|
||||
public ChannelDefinitionBox(ColorModel colorModel) {
|
||||
this();
|
||||
|
||||
// creates the buffers for the channel definitions.
|
||||
short length = (short)(colorModel.getComponentSize().length - 1);
|
||||
num = (short)(length * (colorModel.isAlphaPremultiplied() ? 3 : 2));
|
||||
channels = new short[num];
|
||||
types = new short[num];
|
||||
associations = new short[num];
|
||||
|
||||
// fills the arrays.
|
||||
fillBasedOnBands(length, colorModel.isAlphaPremultiplied(), channels, types, associations);
|
||||
}
|
||||
|
||||
private static void fillBasedOnBands(int numComps, boolean isPremultiplied, short[] c, short[] t, short[] a) {
|
||||
int num = numComps * (isPremultiplied ? 3 : 2);
|
||||
if (isPremultiplied) {
|
||||
for (int i = numComps * 2; i < num; i++) {
|
||||
c[i] = (short)(i - numComps * 2);
|
||||
t[i] = 2; // 2 -- premultiplied
|
||||
a[i] = (short)(i + 1 - numComps * 2);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < numComps; i++) {
|
||||
int j = i + numComps;
|
||||
c[i] = (short)i;
|
||||
t[i] = 0; // The original channel
|
||||
a[j] = a[i] = (short)(i + 1);
|
||||
|
||||
c[j] = (short)numComps;
|
||||
t[j] = 1; // 1 -- transparency
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructs a <code>ChannelDefinitionBox</code> based on the provided
|
||||
* channel definitions.
|
||||
*/
|
||||
public ChannelDefinitionBox(short[] channel, short[] types, short[] associations) {
|
||||
this();
|
||||
this.num = (short) channel.length;
|
||||
this.channels = channel;
|
||||
this.types = types;
|
||||
this.associations = associations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
// Note all of these are actually unsigned shorts, so any images with > 16383 channels will fail...
|
||||
num = in.readShort();
|
||||
channels = new short[num];
|
||||
types = new short[num];
|
||||
associations = new short[num];
|
||||
|
||||
for (int i = 0; i < num; i++) {
|
||||
channels[i] = in.readShort();
|
||||
types[i] = in.readShort();
|
||||
associations[i] = in.readShort();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 2 + num * 6;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeShort(num);
|
||||
for (int i = 0; i < num; i++) {
|
||||
out.writeShort(channels[i]);
|
||||
out.writeShort(types[i]);
|
||||
out.writeShort(associations[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the defined channels.
|
||||
*/
|
||||
public short[] getChannel() {
|
||||
return channels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the channel types. Values are 0 (color), 1 (opacity), 2 (premultiplied opacity) or -1 (unspecified)
|
||||
*/
|
||||
public short[] getTypes() {
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the association which associates a color channel to a color
|
||||
* component in the color space of the image.
|
||||
*/
|
||||
public short[] getAssociation() {
|
||||
return associations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeStartElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
for (int i = 0; i < channels.length; i++) {
|
||||
out.writeEmptyElement("cmap");
|
||||
out.writeAttribute("channel", Integer.toString(channels[i]));
|
||||
out.writeAttribute("type", Integer.toString(types[i]));
|
||||
out.writeAttribute("assoc", Integer.toString(associations[i]));
|
||||
}
|
||||
out.writeEndElement();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(",\"channels\":[");
|
||||
for (int i = 0; i < channels.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("{\"channel\":");
|
||||
sb.append(channels[i]);
|
||||
sb.append(",\"type\":");
|
||||
sb.append(types[i]);
|
||||
sb.append(",\"association\":");
|
||||
sb.append(associations[i]);
|
||||
sb.append("}");
|
||||
}
|
||||
sb.append("]}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.HeaderInfo;
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.reader.HeaderDecoder;
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This represents the "jp2c" box, which contains the CodeStream
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class CodeStreamBox extends Box {
|
||||
|
||||
private byte[] data;
|
||||
private int length;
|
||||
private RandomAccessIO io;
|
||||
|
||||
public CodeStreamBox() {
|
||||
super(fromString("jp2c"));
|
||||
}
|
||||
|
||||
public CodeStreamBox(byte[] data) {
|
||||
this();
|
||||
this.data = data;
|
||||
this.length = data.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(RandomAccessIO io) throws IOException {
|
||||
this.io = io;
|
||||
this.length = io.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
if (data != null) {
|
||||
out.write(data);
|
||||
} else if (io != null) {
|
||||
byte[] b = new byte[8192];
|
||||
io.seek(0);
|
||||
int remaining = io.length();
|
||||
while (remaining > 0) {
|
||||
int c = Math.min(b.length, remaining);
|
||||
io.readFully(b, 0, c);
|
||||
out.write(b, 0, c);
|
||||
remaining -= c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a RandomAccessIO which contains the codestream to pass to the BitstreamReader
|
||||
*/
|
||||
public RandomAccessIO getRandomAccessIO() throws IOException {
|
||||
if (io != null) {
|
||||
io.seek(0);
|
||||
return io;
|
||||
}
|
||||
throw new IllegalStateException("Not created from a RandomAccessIO");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeStartElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
|
||||
J2KReadParam param = new SimpleJ2KReadParam();
|
||||
HeaderInfo hi = new HeaderInfo();
|
||||
try {
|
||||
HeaderDecoder hd = new HeaderDecoder(getRandomAccessIO(), param, hi);
|
||||
|
||||
out.writeStartElement("SIZ");
|
||||
out.writeAttribute("iw", Integer.toString(hi.siz.xsiz - hi.siz.x0siz));
|
||||
out.writeAttribute("ih", Integer.toString(hi.siz.ysiz - hi.siz.y0siz));
|
||||
out.writeAttribute("tw", Integer.toString(hi.siz.xtsiz));
|
||||
out.writeAttribute("th", Integer.toString(hi.siz.ytsiz));
|
||||
out.writeAttribute("numc", Integer.toString(hi.siz.csiz));
|
||||
for (int i = 0; i < hi.siz.csiz; i++) {
|
||||
out.writeStartElement("component");
|
||||
out.writeAttribute("depth", Integer.toString(hi.siz.getOrigBitDepth(i)));
|
||||
out.writeAttribute("signed", Boolean.toString(hi.siz.isOrigSigned(i)));
|
||||
out.writeAttribute("subx", Integer.toString(hi.siz.xrsiz[i]));
|
||||
out.writeAttribute("suby", Integer.toString(hi.siz.yrsiz[i]));
|
||||
out.writeEndElement();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
out.writeEndElement();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.ICC_ColorSpace;
|
||||
import java.awt.color.ICC_Profile;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This represents the "colr" box.
|
||||
* Its content contains the method to define the color space,
|
||||
* the precedence and approximation accuracy (0 for JP2 files), the
|
||||
* enumerated color space, and the ICC color profile if any.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class ColorSpecificationBox extends Box {
|
||||
|
||||
/**
|
||||
* The enumerated color space defined in JP2 file format.
|
||||
*/
|
||||
public static final int ECS_sRGB = 16;
|
||||
public static final int ECS_GRAY = 17;
|
||||
public static final int ECS_YCC = 18;
|
||||
|
||||
private byte method;
|
||||
private byte precedence;
|
||||
private byte approximation;
|
||||
private int ecs;
|
||||
private volatile byte[] profileData;
|
||||
private volatile ICC_Profile profile;
|
||||
|
||||
public ColorSpecificationBox() {
|
||||
super(fromString("colr"));
|
||||
method = 1;
|
||||
approximation = 1;
|
||||
}
|
||||
|
||||
public ColorSpecificationBox(ColorSpace cs) {
|
||||
this();
|
||||
if (cs.isCS_sRGB()) {
|
||||
ecs = 16;
|
||||
} else if (cs.getNumComponents() == 1) {
|
||||
ecs = 17;
|
||||
} else if (cs.getNumComponents() == 4) {
|
||||
ecs = 12;
|
||||
} else if (cs instanceof ICC_ColorSpace) {
|
||||
method = 2;
|
||||
profile = ((ICC_ColorSpace) cs).getProfile();
|
||||
}
|
||||
}
|
||||
|
||||
public ColorSpecificationBox(int ecs) {
|
||||
this(1, 0, 1, ecs, null);
|
||||
}
|
||||
|
||||
public ColorSpecificationBox(ICC_Profile profile) {
|
||||
this(2, 0, 1, 0, profile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a <code>ColorSpecificationBox</code> from the provided data
|
||||
* elements.
|
||||
*/
|
||||
public ColorSpecificationBox(int m, int p, int a, int ecs, ICC_Profile profile) {
|
||||
this();
|
||||
this.method = (byte) m;
|
||||
this.precedence = (byte) p;
|
||||
this.approximation = (byte) a;
|
||||
this.ecs = ecs;
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method to define the color space.
|
||||
*/
|
||||
public byte getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(",\"method\":");
|
||||
sb.append(method);
|
||||
sb.append(",\"precedence\":");
|
||||
sb.append(precedence);
|
||||
sb.append(",\"approximation\":");
|
||||
sb.append(approximation);
|
||||
sb.append(",\"ecs\":");
|
||||
sb.append(ecs);
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>Precedence</code>.
|
||||
*/
|
||||
public byte getPrecedence() {
|
||||
return precedence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>ApproximationAccuracy</code>.
|
||||
*/
|
||||
public byte getApproximationAccuracy() {
|
||||
return approximation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the enumerated color space.
|
||||
*/
|
||||
public int getEnumeratedColorSpace() {
|
||||
return ecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ICC color profile in this color specification box,
|
||||
* or null none exists.
|
||||
*/
|
||||
public ICC_Profile getICCProfile() {
|
||||
if (profile == null && profileData != null) {
|
||||
synchronized (this) {
|
||||
if (profile == null && profileData != null) {
|
||||
profile = ICC_Profile.getInstance(profileData);
|
||||
}
|
||||
}
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw bytes of the ICC color profile in this color
|
||||
* specification box, or null if none exists..
|
||||
*/
|
||||
public byte[] getICCProfileData() {
|
||||
// Reason for this method is to allows access to the ICC profile
|
||||
// data without instantiation of the ICC_Profile object.
|
||||
if (profileData == null && profile != null) {
|
||||
synchronized (this) {
|
||||
if (profileData == null && profile != null) {
|
||||
profileData = profile.getData();
|
||||
}
|
||||
}
|
||||
}
|
||||
return profileData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 3 + (method == 1 ? 4 : getICCProfileData().length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
method = in.readByte();
|
||||
precedence = in.readByte();
|
||||
approximation = in.readByte();
|
||||
if (method == 2 || method == 3) {
|
||||
profileData = new byte[in.length() - in.getPos()];
|
||||
in.readFully(profileData, 0, profileData.length);
|
||||
} else {
|
||||
ecs = in.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.write(method);
|
||||
out.write(precedence);
|
||||
out.write(approximation);
|
||||
if (method == 1) {
|
||||
out.writeInt(ecs);
|
||||
} else if (getICCProfileData() != null) {
|
||||
out.write(getICCProfileData());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeStartElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
out.writeAttribute("method", Integer.toString(getMethod()));
|
||||
out.writeAttribute("precedence", Integer.toString(getPrecedence()));
|
||||
out.writeAttribute("approximation", Integer.toString(getApproximationAccuracy()));
|
||||
if (getMethod() == 1) {
|
||||
out.writeStartElement("enumcs");
|
||||
out.writeCharacters(Integer.toString(getEnumeratedColorSpace()));
|
||||
out.writeEndElement();
|
||||
} else if (getICCProfile() != null) {
|
||||
out.writeStartElement("profile");
|
||||
out.writeCharacters(toString(getICCProfileData()));
|
||||
out.writeEndElement();
|
||||
}
|
||||
out.writeEndElement();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This represents the "cmap" box.
|
||||
* This box exists if and only is a PaletteBox exists. Its
|
||||
* content defines the type LUT output components and their mapping to the
|
||||
* color component.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class ComponentMappingBox extends Box {
|
||||
private short[] components;
|
||||
private byte[] type;
|
||||
private byte[] map;
|
||||
|
||||
public ComponentMappingBox() {
|
||||
super(fromString("cmap"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>ComponentMappingBox</code> from the provided
|
||||
* component mapping.
|
||||
*/
|
||||
public ComponentMappingBox(short[] comp, byte[] t, byte[] m) {
|
||||
this();
|
||||
this.components = comp;
|
||||
this.type = t;
|
||||
this.map = m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return components.length * 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
int len = in.length() / 4;
|
||||
components = new short[len];
|
||||
type = new byte[len];
|
||||
map = new byte[len];
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
components[i] = in.readShort();
|
||||
type[i] = in.readByte();
|
||||
map[i] = in.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
for (int i = 0; i < type.length; i++) {
|
||||
out.writeShort(components[i]);
|
||||
out.write(type[i]);
|
||||
out.write(map[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public short[] getComponent() {
|
||||
return components;
|
||||
}
|
||||
|
||||
public byte[] getComponentType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public byte[] getComponentAssociation() {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeStartElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
for (int i = 0; i < components.length; i++) {
|
||||
out.writeEmptyElement("cmap");
|
||||
out.writeAttribute("component", Integer.toString(components[i]));
|
||||
out.writeAttribute("type", Integer.toString(type[i]));
|
||||
out.writeAttribute("assoc", Integer.toString(map[i]));
|
||||
}
|
||||
out.writeEndElement();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(",\"components\":[");
|
||||
for (int i = 0; i < components.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("{\"component\":");
|
||||
sb.append(components[i]);
|
||||
sb.append(",\"type\":");
|
||||
sb.append(type[i]);
|
||||
sb.append(",\"association\":");
|
||||
sb.append(map[i]);
|
||||
sb.append("}");
|
||||
}
|
||||
sb.append("]}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.SubRandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This represents any Box that contains other Boxes.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class ContainerBox extends Box {
|
||||
|
||||
private final List<Box> boxes;
|
||||
|
||||
public ContainerBox(int type) {
|
||||
super(type);
|
||||
boxes = new ArrayList<Box>();
|
||||
}
|
||||
|
||||
public static Box readBox(RandomAccessIO in) throws IOException {
|
||||
int start = in.getPos();
|
||||
int len = in.readInt();
|
||||
int type = in.readInt();
|
||||
Box box = Box.createBox(type);
|
||||
RandomAccessIO sub;
|
||||
if (len == 0) {
|
||||
sub = new SubRandomAccessIO(in, in.length() - in.getPos());
|
||||
} else if (len == 1) {
|
||||
throw new IOException("Long boxes not supported");
|
||||
} else if (len < 8) {
|
||||
throw new IOException("Invalid box length " + len);
|
||||
} else {
|
||||
sub = new SubRandomAccessIO(in, len - 8);
|
||||
}
|
||||
// System.out.println("Reading box at "+start+" "+toString(type)+" len="+len+" stream="+sub.getPos()+"/"+sub.length());
|
||||
box.read(sub);
|
||||
// System.out.println("Skip to "+start +"+"+ len+" = "+(start+len)+" from "+in.getPos()+"/"+in.length());
|
||||
if (len != 0 || start + len < in.length()) {
|
||||
in.seek(len == 0 ? in.length() : start + len);
|
||||
}
|
||||
return box;
|
||||
}
|
||||
|
||||
public static void writeBox(Box box, DataOutputStream out) throws IOException {
|
||||
int len = box.getLength();
|
||||
out.writeInt(len == 0 ? 0 : len + 8);
|
||||
out.writeInt(box.getType());
|
||||
box.write(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
int len = 0;
|
||||
for (int i = 0; i < boxes.size(); i++) {
|
||||
int sublen = boxes.get(i).getLength();
|
||||
if (sublen == 0) {
|
||||
return 0;
|
||||
}
|
||||
len += 8 + sublen;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the content from the specified IO, which should be truncated
|
||||
* to the correct length. The current position of the specified "in"
|
||||
* is at the start of the "box contents" (DBox field)
|
||||
*/
|
||||
@Override
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
while (in.length() - in.getPos() > 0) {
|
||||
add(readBox(in));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
for (int i = 0; i < boxes.size(); i++) {
|
||||
writeBox(boxes.get(i), out);
|
||||
}
|
||||
}
|
||||
|
||||
public ContainerBox add(Box box) {
|
||||
boxes.add(box);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<Box> getBoxes() {
|
||||
return Collections.unmodifiableList(boxes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeStartElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
for (Box box : boxes) {
|
||||
box.write(out);
|
||||
}
|
||||
out.writeEndElement();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(",\"boxes\":[");
|
||||
for (int i = 0; i < boxes.size(); i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(boxes.get(i).toString());
|
||||
}
|
||||
sb.append("]}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This represents the "ftyp: box.
|
||||
* <p>
|
||||
* The content of a file type box contains the brand ("jp2 " for JP2 file",
|
||||
* the minor version (0 for JP2 file format), and a compatibility list (one of
|
||||
* which should be "jp2 " if brand is not "jp2 ".)
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class FileTypeBox extends Box {
|
||||
|
||||
private int brand;
|
||||
private int minorVersion;
|
||||
private int[] compat;
|
||||
|
||||
public FileTypeBox() {
|
||||
super(fromString("ftyp"));
|
||||
brand = 0x6a703220;
|
||||
minorVersion = 0;
|
||||
compat = new int[]{fromString("jp2 ")};
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>FileTypeBox</code> from the provided brand, minor
|
||||
* version and compatibility list.
|
||||
*/
|
||||
public FileTypeBox(int br, int minorVersion, int[] compat) {
|
||||
this();
|
||||
this.brand = br;
|
||||
this.minorVersion = minorVersion;
|
||||
this.compat = compat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 8 + compat.length * 4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
brand = in.readInt();
|
||||
minorVersion = in.readInt();
|
||||
int len = (in.length() - in.getPos()) / 4;
|
||||
if (len > 0) {
|
||||
compat = new int[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
compat[i] = in.readInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(brand);
|
||||
out.writeInt(minorVersion);
|
||||
for (int i = 0; i < compat.length; i++) {
|
||||
out.writeInt(compat[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the brand of this file type box.
|
||||
*/
|
||||
public int getBrand() {
|
||||
return brand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minor version of this file type box.
|
||||
*/
|
||||
public int getMinorVersion() {
|
||||
return minorVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the compatibility list of this file type box.
|
||||
*/
|
||||
public int[] getCompatibilityList() {
|
||||
return compat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeStartElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
out.writeAttribute("brand", toString(brand));
|
||||
out.writeAttribute("minorVersion", "0x" + Integer.toHexString(minorVersion));
|
||||
for (int i = 0; i < compat.length; i++) {
|
||||
out.writeStartElement("compat");
|
||||
out.writeCharacters(toString(compat[i]));
|
||||
out.writeEndElement();
|
||||
}
|
||||
out.writeEndElement();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(",\"brand\":\"");
|
||||
sb.append(toString(brand));
|
||||
sb.append("\",\"minorVersion\":");
|
||||
sb.append(minorVersion);
|
||||
sb.append("\",\"compat\":[");
|
||||
for (int i = 0; i < compat.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("\"");
|
||||
sb.append(toString(compat[i]));
|
||||
sb.append("\"");
|
||||
}
|
||||
sb.append("]}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
/**
|
||||
* This represents the "jp2h" box
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class HeaderBox extends ContainerBox {
|
||||
|
||||
private ImageHeaderBox ihdr;
|
||||
private BitsPerComponentBox bpcc;
|
||||
private PaletteBox pclr;
|
||||
private ComponentMappingBox cmap;
|
||||
private ChannelDefinitionBox cdef;
|
||||
private ResolutionSuperBox res;
|
||||
private ColorSpecificationBox colr; // the first one seen
|
||||
|
||||
public HeaderBox() {
|
||||
super(fromString("jp2h"));
|
||||
}
|
||||
|
||||
public ImageHeaderBox getImageHeaderBox() {
|
||||
return ihdr;
|
||||
}
|
||||
|
||||
public BitsPerComponentBox getBitsPerComponentBox() {
|
||||
return bpcc;
|
||||
}
|
||||
|
||||
public PaletteBox getPaletteBox() {
|
||||
return pclr;
|
||||
}
|
||||
|
||||
public ComponentMappingBox getComponentMappingBox() {
|
||||
return cmap;
|
||||
}
|
||||
|
||||
public ChannelDefinitionBox getChannelDefinitionBox() {
|
||||
return cdef;
|
||||
}
|
||||
|
||||
public ResolutionSuperBox getResolutionSuperBox() {
|
||||
return res;
|
||||
}
|
||||
|
||||
public ColorSpecificationBox getColorSpecificationBoxes() {
|
||||
return colr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContainerBox add(Box box) {
|
||||
if (box instanceof ImageHeaderBox) {
|
||||
if (ihdr == null) {
|
||||
ihdr = (ImageHeaderBox) box;
|
||||
} else {
|
||||
throw new IllegalStateException("More than one ihdr box");
|
||||
}
|
||||
} else {
|
||||
if (ihdr == null) {
|
||||
throw new IllegalStateException("ihdr box must come first");
|
||||
}
|
||||
if (box instanceof BitsPerComponentBox) {
|
||||
if (bpcc == null) {
|
||||
bpcc = (BitsPerComponentBox) box;
|
||||
} else {
|
||||
throw new IllegalStateException("More than one bpcc box");
|
||||
}
|
||||
} else if (box instanceof ColorSpecificationBox) {
|
||||
if (colr == null) {
|
||||
colr = (ColorSpecificationBox) box;
|
||||
}
|
||||
// More than one is allowed
|
||||
} else if (box instanceof PaletteBox) {
|
||||
if (pclr == null) {
|
||||
pclr = (PaletteBox) box;
|
||||
} else {
|
||||
throw new IllegalStateException("More than one pclr box");
|
||||
}
|
||||
} else if (box instanceof ComponentMappingBox) {
|
||||
if (cmap == null) {
|
||||
cmap = (ComponentMappingBox) box;
|
||||
} else {
|
||||
throw new IllegalStateException("More than one cmap box");
|
||||
}
|
||||
} else if (box instanceof ChannelDefinitionBox) {
|
||||
if (cdef == null) {
|
||||
cdef = (ChannelDefinitionBox) box;
|
||||
} else {
|
||||
throw new IllegalStateException("More than one cdef box");
|
||||
}
|
||||
} else if (box instanceof ResolutionSuperBox) {
|
||||
if (res == null) {
|
||||
res = (ResolutionSuperBox) box;
|
||||
} else {
|
||||
throw new IllegalStateException("More than one res box");
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.add(box);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This represents the "ihdr" Box
|
||||
* <p>
|
||||
* The content of an image header box contains the width/height, number of
|
||||
* image components, the bit depth (coded with sign/unsign information),
|
||||
* the compression type (7 for JP2 file), the flag to indicate the color
|
||||
* space is known or not, and a flag to indicate whether the intellectual
|
||||
* property information included in this file.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class ImageHeaderBox extends Box {
|
||||
|
||||
private int width;
|
||||
private int height;
|
||||
private short numComp;
|
||||
private byte bitDepth;
|
||||
private byte compressionType;
|
||||
private byte unknownColor;
|
||||
private byte intelProp;
|
||||
|
||||
public ImageHeaderBox() {
|
||||
super(fromString("ihdr"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an Image Header Box from the element values.
|
||||
*/
|
||||
public ImageHeaderBox(int width, int height, int numComp, int bitDepth, boolean unknownColor, boolean intelProp) {
|
||||
this();
|
||||
this.height = height;
|
||||
this.width = width;
|
||||
this.numComp = (short) numComp;
|
||||
this.bitDepth = (byte) bitDepth;
|
||||
this.compressionType = (byte) 7;
|
||||
this.unknownColor = (byte) (unknownColor ? 1 : 0);
|
||||
this.intelProp = (byte) (intelProp ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 14;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
height = in.readInt();
|
||||
width = in.readInt();
|
||||
numComp = in.readShort();
|
||||
bitDepth = in.readByte();
|
||||
compressionType = in.readByte();
|
||||
unknownColor = in.readByte();
|
||||
intelProp = in.readByte();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeInt(height);
|
||||
out.writeInt(width);
|
||||
out.writeShort(numComp);
|
||||
out.write(bitDepth);
|
||||
out.write(compressionType);
|
||||
out.write(unknownColor);
|
||||
out.write(intelProp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the height of the image.
|
||||
*/
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the width of the image.
|
||||
*/
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of image components.
|
||||
*/
|
||||
public short getNumComponents() {
|
||||
return numComp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the compression type.
|
||||
*/
|
||||
public byte getCompressionType() {
|
||||
return compressionType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bit depth for all the image components.
|
||||
*/
|
||||
public byte getBitDepth() {
|
||||
return bitDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>UnknowColorspace</code> flag.
|
||||
*/
|
||||
public byte getUnknownColorspace() {
|
||||
return unknownColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>IntellectualProperty</code> flag.
|
||||
*/
|
||||
public byte getIntellectualProperty() {
|
||||
return intelProp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeEmptyElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
out.writeAttribute("width", Integer.toString(getWidth()));
|
||||
out.writeAttribute("height", Integer.toString(getHeight()));
|
||||
out.writeAttribute("numc", Integer.toString(getNumComponents()));
|
||||
if (getBitDepth() != 255) {
|
||||
out.writeAttribute("depth", Integer.toString(getBitDepth()));
|
||||
}
|
||||
if (getCompressionType() != 7) {
|
||||
out.writeAttribute("compression", Integer.toString(getCompressionType()));
|
||||
}
|
||||
out.writeAttribute("unknownColorSpace", Integer.toString(getUnknownColorspace()));
|
||||
out.writeAttribute("ip", Integer.toString(getIntellectualProperty()));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(",\"width\":\"");
|
||||
sb.append(getWidth());
|
||||
sb.append(",\"height\":\"");
|
||||
sb.append(getHeight());
|
||||
sb.append(",\"numc\":\"");
|
||||
sb.append(getNumComponents());
|
||||
if (getBitDepth() != 255) {
|
||||
sb.append(",\"depth\":\"");
|
||||
sb.append(getBitDepth());
|
||||
}
|
||||
if (getCompressionType() != 7) {
|
||||
sb.append(",\"compression\":\"");
|
||||
sb.append(getCompressionType());
|
||||
}
|
||||
sb.append("\",\"unknownColorSpace\":");
|
||||
sb.append(getUnknownColorspace());
|
||||
sb.append("\",\"ip\":");
|
||||
sb.append(getIntellectualProperty());
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The J2KFile is the top level representation of a JP2 or JPX encoded
|
||||
* file. It contains boxes and may be read or written in the same was
|
||||
* as any {@link ContainerBox}
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class J2KFile {
|
||||
|
||||
private static final long SIGMARKER = 0x6a5020200d0a870aL;
|
||||
private HeaderBox jp2h;
|
||||
private FileTypeBox ftyp;
|
||||
private CodeStreamBox jp2c;
|
||||
private final List<Box> boxes;
|
||||
|
||||
public J2KFile() {
|
||||
boxes = new ArrayList<Box>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a J2KFile from the specified input
|
||||
*/
|
||||
public J2KFile read(RandomAccessIO in) throws IOException {
|
||||
if (in.readInt() != 12 || in.readInt() != SIGMARKER >> 32 || in.readInt() != (int) SIGMARKER) {
|
||||
throw new IOException("No JP2 Signature Box");
|
||||
}
|
||||
while (in.length() - in.getPos() >= 8) { // 8 is minimum length for box
|
||||
add(ContainerBox.readBox(in));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Box to this JP2File
|
||||
*
|
||||
* @param box the box
|
||||
* @return this
|
||||
*/
|
||||
public J2KFile add(Box box) throws IOException {
|
||||
if (box instanceof FileTypeBox) {
|
||||
if (ftyp == null) {
|
||||
ftyp = (FileTypeBox) box;
|
||||
} else {
|
||||
throw new IOException("More than one ftyp box");
|
||||
}
|
||||
} else if (ftyp == null) {
|
||||
throw new IOException("No ftyp Box");
|
||||
} else if (box instanceof HeaderBox) {
|
||||
if (jp2h == null) {
|
||||
jp2h = (HeaderBox) box;
|
||||
} else {
|
||||
throw new IOException("More than one jp2h box");
|
||||
}
|
||||
} else if (box instanceof CodeStreamBox) {
|
||||
if (jp2h == null) {
|
||||
throw new IOException("jp2c must follow jp2h");
|
||||
} else if (jp2c == null) {
|
||||
jp2c = (CodeStreamBox) box;
|
||||
} else {
|
||||
// Others are allowed.
|
||||
}
|
||||
}
|
||||
boxes.add(box);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link HeaderBox} from the file
|
||||
*/
|
||||
public HeaderBox getHeaderBox() {
|
||||
return jp2h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link CodeStreamBox} from the file
|
||||
*/
|
||||
public CodeStreamBox getCodeStreamBox() {
|
||||
return jp2c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the full list of boxes from the file.
|
||||
* The returned list is read-only
|
||||
*/
|
||||
public List<Box> getBoxes() {
|
||||
return Collections.unmodifiableList(boxes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the J2KFile to the specified OutputStream
|
||||
*/
|
||||
public OutputStream write(OutputStream out) throws IOException {
|
||||
if (jp2h == null || jp2c == null) {
|
||||
throw new IOException("Missing jp2h or jp2c");
|
||||
}
|
||||
DataOutputStream o = new DataOutputStream(out);
|
||||
o.writeInt(12);
|
||||
o.writeLong(SIGMARKER);
|
||||
for (int i = 0; i < boxes.size(); i++) {
|
||||
ContainerBox.writeBox(boxes.get(i), o);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the J2KFile as XML to the specified XMLStreamWriter
|
||||
*/
|
||||
public XMLStreamWriter write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeStartElement("j2k");
|
||||
for (Box box : boxes) {
|
||||
box.write(out);
|
||||
}
|
||||
out.writeEndElement();
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
/**
|
||||
* Interface which defines the parameters required to write a JP2 image.
|
||||
* Abstracted away from J2KImageReadParamJava
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public interface J2KReadParam {
|
||||
|
||||
/**
|
||||
* If true, no ROI de-scaling is performed. Decompression is done
|
||||
* like there is no ROI in the image.
|
||||
* A suitable default is "true"
|
||||
*/
|
||||
boolean getNoROIDescaling();
|
||||
|
||||
/**
|
||||
* Specifies the decoding rate in bits per pixel (bpp) where the
|
||||
* number of pixels is related to the image's original size (Note:
|
||||
* this parameter is not affected by <code>resolution</code>).
|
||||
* A value of <code>Double.MAX_VALUE</code> means decode
|
||||
* with the encoding rate - this is a suitable default.
|
||||
*/
|
||||
double getDecodingRate();
|
||||
|
||||
/**
|
||||
* Specifies the resolution level wanted for the decoded image
|
||||
* (0 means the lowest available resolution, the resolution
|
||||
* level gives an image with the original dimension). If the given index
|
||||
* is greater than the number of available resolution levels of the
|
||||
* compressed image, the decoded image has the lowest available
|
||||
* resolution (among all tile-components). This parameter affects only
|
||||
* the inverse wavelet transform and not the number of bytes read by the
|
||||
* codestream parser, which depends only on <code>decodingRate</code>.
|
||||
* A value of -1 means to use the resolution level at encoding.
|
||||
* This is a suitable default.
|
||||
*/
|
||||
int getResolution();
|
||||
|
||||
}
|
|
@ -0,0 +1,603 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.HeaderInfo;
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.reader.BitstreamReaderAgent;
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.reader.HeaderDecoder;
|
||||
import org.xbib.graphics.jpeg2000.j2k.decoder.DecoderSpecs;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.decoder.EntropyDecoder;
|
||||
import org.xbib.graphics.jpeg2000.j2k.image.BlkImgDataSrc;
|
||||
import org.xbib.graphics.jpeg2000.j2k.image.DataBlkInt;
|
||||
import org.xbib.graphics.jpeg2000.j2k.image.ImgDataConverter;
|
||||
import org.xbib.graphics.jpeg2000.j2k.image.invcomptransf.InvCompTransf;
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.dequantizer.Dequantizer;
|
||||
import org.xbib.graphics.jpeg2000.j2k.roi.ROIDeScaler;
|
||||
import org.xbib.graphics.jpeg2000.j2k.util.FacilityManager;
|
||||
import org.xbib.graphics.jpeg2000.j2k.util.MsgLogger;
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.synthesis.InverseWT;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.color.ICC_ColorSpace;
|
||||
import java.awt.color.ICC_Profile;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ComponentColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.DataBufferByte;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.SampleModel;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* An InputStream giving access to the decoded image data. Tiles are decoded on demand, meaning
|
||||
* the entire image doesn't have to be decoded in memory. The image is converted to 8-bit, YCbCr
|
||||
* images are converted to RGB and component subsampling is removed, but otherwise the image data
|
||||
* is unchanged.
|
||||
* </p>
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class J2KReader extends InputStream implements MsgLogger {
|
||||
|
||||
private RandomAccessIO in;
|
||||
private Thread registerThread;
|
||||
private BlkImgDataSrc src; // image data source
|
||||
private DecoderSpecs decSpec;
|
||||
private InverseWT invWT;
|
||||
private BitstreamReaderAgent breader;
|
||||
private int fulliw, fullih, numtx, numty, iw, ih, scanline, numc, fullscale, scale, ntw, nth;
|
||||
private int[] depth;
|
||||
private int[] channels;
|
||||
|
||||
// variable
|
||||
private DataBlkInt db;
|
||||
private int pos, ty, length;
|
||||
private byte[] buf;
|
||||
private final boolean baseline = true;
|
||||
private boolean seenapprox;
|
||||
private int[][] palette;
|
||||
private ColorSpace cs;
|
||||
private int cstype;
|
||||
private ResolutionBox resc, resd;
|
||||
|
||||
/**
|
||||
* Create a new J2KReader from a "jp2" file
|
||||
*
|
||||
* @param file the J2KFile to read from
|
||||
*/
|
||||
public J2KReader(J2KFile file) throws IOException {
|
||||
for (Box box : file.getHeaderBox().getBoxes()) {
|
||||
addBox(box);
|
||||
}
|
||||
init(file.getCodeStreamBox().getRandomAccessIO());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new J2KReader from a raw codestream.
|
||||
*
|
||||
* @param box the CodeStream to read from
|
||||
*/
|
||||
public J2KReader(CodeStreamBox box) throws IOException {
|
||||
init(box.getRandomAccessIO());
|
||||
}
|
||||
|
||||
private void init(RandomAccessIO in) throws IOException {
|
||||
this.in = in;
|
||||
registerThread = Thread.currentThread();
|
||||
FacilityManager.registerMsgLogger(registerThread, this);
|
||||
|
||||
HeaderInfo hi = new HeaderInfo();
|
||||
J2KReadParam param = new SimpleJ2KReadParam();
|
||||
HeaderDecoder hd = new HeaderDecoder(in, param, hi);
|
||||
depth = new int[hd.getNumComps()];
|
||||
for (int i = 0; i < depth.length; i++) {
|
||||
depth[i] = hd.getOriginalBitDepth(i);
|
||||
}
|
||||
decSpec = hd.getDecoderSpecs();
|
||||
breader = BitstreamReaderAgent.createInstance(in, hd, param, decSpec, false, hi);
|
||||
if (isInterrupted()) {
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
EntropyDecoder entdec = hd.createEntropyDecoder(breader, param);
|
||||
if (isInterrupted()) {
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
ROIDeScaler roids = hd.createROIDeScaler(entdec, param, decSpec);
|
||||
if (isInterrupted()) {
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
Dequantizer deq = hd.createDequantizer(roids, depth, decSpec);
|
||||
if (isInterrupted()) {
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
invWT = InverseWT.createInstance(deq, decSpec);
|
||||
if (isInterrupted()) {
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
|
||||
fullscale = breader.getImgRes();
|
||||
fulliw = breader.getImgWidth(fullscale);
|
||||
fullih = breader.getImgHeight(fullscale);
|
||||
setTargetSize(fulliw, fullih);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the target size for the output image. The default size is
|
||||
* the full size of the image, but it's possible to access lower
|
||||
* resolution versions of the image by calling this method with
|
||||
* the desired size. While the file image size may not match
|
||||
* exactly, it will be as close as usefully possible.
|
||||
*
|
||||
* @param targetwidth the desired target width of the image
|
||||
* @param targetheight the desired target height of the image
|
||||
*/
|
||||
public void setTargetSize(int targetwidth, int targetheight) {
|
||||
// Find the best scale so that final width/height are >= 1 and < 2
|
||||
// times the desired width.
|
||||
int newscale = fullscale;
|
||||
for (int i = fullscale; i >= 1; i--) {
|
||||
if (targetwidth > breader.getImgWidth(i) || targetheight > breader.getImgHeight(i)) {
|
||||
break;
|
||||
}
|
||||
newscale = i;
|
||||
}
|
||||
if (newscale != scale) {
|
||||
scale = newscale;
|
||||
invWT.setImgResLevel(scale);
|
||||
ImgDataConverter converter = new ImgDataConverter(invWT, 0);
|
||||
src = new InvCompTransf(converter, decSpec, depth);
|
||||
iw = src.getImgWidth();
|
||||
ih = src.getImgHeight();
|
||||
numtx = src.getNumTiles(null).x;
|
||||
numty = src.getNumTiles(null).y;
|
||||
numc = src.getNumComps();
|
||||
scanline = iw * numc;
|
||||
}
|
||||
}
|
||||
|
||||
protected void addBox(Box box) {
|
||||
if (box instanceof ImageHeaderBox b) {
|
||||
channels = new int[b.getNumComponents()];
|
||||
for (int i = 0; i < channels.length; i++) {
|
||||
channels[i] = i;
|
||||
}
|
||||
} else if (box instanceof PaletteBox b) {
|
||||
int indexsize = b.getNumEntries();
|
||||
int numc = b.getNumComp();
|
||||
palette = new int[indexsize][numc];
|
||||
for (int i = 0; i < indexsize; i++) {
|
||||
for (int c = 0; c < numc; c++) {
|
||||
palette[i][c] = b.getComponentValue(i, c);
|
||||
}
|
||||
}
|
||||
} else if (box instanceof ColorSpecificationBox b) {
|
||||
int method = b.getMethod();
|
||||
if (method == 1) {
|
||||
cs = createColorSpace(b.getEnumeratedColorSpace(), null);
|
||||
} else if (method == 2 || method == 3) {
|
||||
cs = createColorSpace(0, b.getICCProfileData());
|
||||
}
|
||||
} else if (box instanceof ChannelDefinitionBox b) {
|
||||
// ComponentDefinitionBox
|
||||
short[] c = b.getChannel();
|
||||
short[] a = b.getAssociation();
|
||||
for (int i = 0; i < c.length; i++) {
|
||||
channels[c[i]] = a[i] - 1;
|
||||
}
|
||||
} else if (box instanceof ResolutionBox) {
|
||||
if (Box.toString(box.getType()).equals("resc")) {
|
||||
resc = (ResolutionBox) box;
|
||||
} else if (Box.toString(box.getType()).equals("resd")) {
|
||||
resd = (ResolutionBox) box;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
public void printmsg(int sev, String msg) {
|
||||
// System.out.println(msg);
|
||||
}
|
||||
|
||||
public void println(String str, int flind, int ind) {
|
||||
// System.out.println(str);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// InputStream methods
|
||||
|
||||
private boolean nextRow(boolean skip) throws IOException {
|
||||
try {
|
||||
rowCallback();
|
||||
// System.out.println("IN: ty="+ty+"/"+numty+" numtx="+numtx+" numc="+numc+" skip="+skip+" pos="+pos+" length="+length);
|
||||
if (ty == numty) {
|
||||
return false;
|
||||
}
|
||||
if (!skip) {
|
||||
for (int tx = 0; tx < numtx; tx++) {
|
||||
src.setTile(tx, ty);
|
||||
final int tileix = src.getTileIdx();
|
||||
// Determine tile width/height - this is not as simple as
|
||||
// calling src.getTileWidth when using less than full res.
|
||||
int tw = 0;
|
||||
int th = 0;
|
||||
for (int iz = 0; iz < numc; iz++) {
|
||||
tw = Math.max(tw, src.getTileCompWidth(tileix, iz));
|
||||
th = Math.max(th, src.getTileCompHeight(tileix, iz));
|
||||
}
|
||||
if (db == null) {
|
||||
// First pass
|
||||
buf = new byte[scanline * th];
|
||||
db = new DataBlkInt(0, 0, tw, th);
|
||||
ntw = tw;
|
||||
nth = th;
|
||||
}
|
||||
db.w = tw;
|
||||
db.h = th;
|
||||
length = scanline * th;
|
||||
final int itx = tx * ntw;
|
||||
final int ity = 0;
|
||||
for (int iz = 0; iz < numc; iz++) {
|
||||
int riz = channels == null ? iz : channels[iz]; // output channel, could differ from input channel
|
||||
if (riz < 0) {
|
||||
// This is the OPACITY channel. Well technically
|
||||
// it's something that applies to all channels, but
|
||||
// given the limitations of what we can do with that
|
||||
// we'll assume opacity, as that's the only example
|
||||
// seen to date.
|
||||
riz = numc - 1;
|
||||
}
|
||||
final int depth = src.getNomRangeBits(iz);
|
||||
final int mid = 1 << (depth - 1);
|
||||
final int csx = src.getCompSubsX(iz);
|
||||
final int csy = src.getCompSubsY(iz);
|
||||
final int fb = src.getFixedPoint(iz);
|
||||
// System.out.println("iwh="+iw+"x"+ih+" txy="+tx+"x"+ty+" of "+numtx+","+numty+" itxy="+src.getTilePartULX()+"x"+src.getTilePartULY()+" tcwh="+tw+"x"+th+" twh="+src.getTileWidth()+"x"+src.getTileHeight()+" ntwh="+src.getNomTileWidth()+"x"+src.getNomTileHeight()+" iz="+iz+"="+riz+" ss="+csx+"x"+csy+" d="+depth+" mid="+mid+" fb="+fb+" sl="+scanline+" buf="+buf.length+" channels="+java.util.Arrays.toString(channels));
|
||||
int[] shift = null;
|
||||
if (depth < 8) {
|
||||
shift = new int[1 << depth];
|
||||
for (int i = 0; i < shift.length; i++) {
|
||||
shift[i] = Math.round(i * 255f / ((1 << depth) - 1));
|
||||
}
|
||||
}
|
||||
do {
|
||||
db = (DataBlkInt) src.getInternCompData(db, iz);
|
||||
} while (db.progressive);
|
||||
// Main loop: retrieve value, scaled to 8 bits and adjust midpoint
|
||||
for (int iy = 0; iy < th; iy++) {
|
||||
if (isInterrupted()) {
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
for (int ix = 0; ix < tw; ix++) {
|
||||
int val = (db.data[db.offset + iy * tw + ix] >> fb) + mid;
|
||||
if (depth == 8) {
|
||||
val = Math.max(0, Math.min(255, val));
|
||||
} else if (depth > 8) {
|
||||
val = Math.max(0, Math.min(255, val >> (depth - 8)));
|
||||
} else {
|
||||
val = shift[val < 0 ? 0 : val >= shift.length ? shift.length - 1 : val];
|
||||
}
|
||||
buf[((ity + (iy * csy)) * scanline) + ((itx + (ix * csx)) * numc) + riz] = (byte) val;
|
||||
}
|
||||
}
|
||||
if (csx != 1 || csy != 1) {
|
||||
// Component is subsampled; use bilinear interpolation to fill the gaps. Quick and dirty,
|
||||
// tested with limited test data
|
||||
for (int iy = 0; iy < th; iy++) {
|
||||
if (isInterrupted()) {
|
||||
throw new InterruptedIOException();
|
||||
}
|
||||
for (int ix = 0; ix < tw; ix++) {
|
||||
// Values on each of the four corners of our space
|
||||
int v00 = buf[((ity + (iy * csy)) * scanline) + ((itx + (ix * csx)) * numc) + riz] & 0xFF;
|
||||
int v01 = ix + 1 == tw ? v00 : buf[((ity + (iy * csy)) * scanline) + ((itx + ((ix + 1) * csx)) * numc) + riz] & 0xFF;
|
||||
int v10 = iy + 1 == th ? v00 : buf[((ity + ((iy + 1) * csy)) * scanline) + ((itx + (ix * csx)) * numc) + riz] & 0xFF;
|
||||
int v11 = iy + 1 == th ? (ix + 1 == tw ? v00 : v10) : (ix + 1 == tw ? v10 : buf[((ity + ((iy + 1) * csy)) * scanline) + ((itx + ((ix + 1) * csx)) * numc) + riz] & 0xFF);
|
||||
for (int jy = 0; jy < csy; jy++) {
|
||||
for (int jx = 0; jx < csx; jx++) {
|
||||
if (jx + jy != 0 && ix + jx < tw && iy + jy < th) {
|
||||
// q = interpolated(v00, v01, v10, v11)
|
||||
int q0 = v00 + ((v10 - v00) * jx / (csx - 1));
|
||||
int q1 = v01 + ((v11 - v01) * jx / (csx - 1));
|
||||
int q = q0 + ((q1 - q0) * jy / (csy - 1));
|
||||
buf[((ity + (iy * csy) + jy) * scanline) + ((itx + (ix * csx) + jx) * numc) + riz] = (byte) q;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ty++;
|
||||
if (ty == numty) {
|
||||
free();
|
||||
}
|
||||
pos = 0;
|
||||
return true;
|
||||
} catch (RuntimeException e) {
|
||||
throw new IOException("Decode failed at " + pos, e);
|
||||
}
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
if (pos == length) {
|
||||
if (!nextRow(false)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return buf[pos++] & 0xFF;
|
||||
}
|
||||
|
||||
public int read(byte[] out) throws IOException {
|
||||
return read(out, 0, out.length);
|
||||
}
|
||||
|
||||
public int read(byte[] out, int off, int len) throws IOException {
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
int origlen = len;
|
||||
while (len > 0) {
|
||||
if (pos == length) {
|
||||
if (!nextRow(false)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
int avail = Math.min(len, length - pos);
|
||||
System.arraycopy(buf, pos, out, off, avail);
|
||||
len -= avail;
|
||||
off += avail;
|
||||
pos += avail;
|
||||
}
|
||||
return len == origlen ? -1 : origlen - len;
|
||||
}
|
||||
|
||||
public long skip(long len) throws IOException {
|
||||
long origlen = len;
|
||||
if (buf == null && len > 0) {
|
||||
// Ensure read buffer is initialized before we try and skip
|
||||
int v = read();
|
||||
if (v < 0) {
|
||||
return 0;
|
||||
}
|
||||
len--;
|
||||
}
|
||||
while (len > 0) {
|
||||
int avail = Math.min((int) len, length - pos);
|
||||
len -= avail;
|
||||
pos += avail;
|
||||
if (pos == length) {
|
||||
if (!nextRow(len > buf.length)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return origlen - len;
|
||||
}
|
||||
|
||||
public int available() {
|
||||
return buf.length - pos;
|
||||
}
|
||||
|
||||
private void free() throws IOException {
|
||||
if (in != null) {
|
||||
FacilityManager.unregisterMsgLogger(registerThread);
|
||||
registerThread = null;
|
||||
in.close();
|
||||
in = null;
|
||||
src = null;
|
||||
decSpec = null;
|
||||
invWT = null;
|
||||
breader = null;
|
||||
db = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
free();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
// Image methods
|
||||
|
||||
/**
|
||||
* Return the overwall width of the image, in pixels
|
||||
*/
|
||||
public int getWidth() {
|
||||
return iw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the overall height of the image, in pixels
|
||||
*/
|
||||
public int getHeight() {
|
||||
return ih;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of components in the image data,
|
||||
* which will be 1 for indexed images, otherwise the number
|
||||
* of components in the image ColorSpace, plus one if the
|
||||
* image has an alpha channel
|
||||
*/
|
||||
public int getNumComponents() {
|
||||
return numc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of bytes in each scanline of the image
|
||||
*/
|
||||
public int getRowSpan() {
|
||||
return getNumComponents() * getWidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of bits for each component - currently this is always 8.
|
||||
*/
|
||||
public int getBitsPerComponent() {
|
||||
return 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the original bit depth for the specified component from the source image.
|
||||
*/
|
||||
public int getOriginalBitsPerComponent(int comp) {
|
||||
return depth[comp];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ColorSpace for the image, which may be null if this
|
||||
* implementation has no support for the encoded space (eg. Lab or CMYK)
|
||||
*/
|
||||
public ColorSpace getColorSpace() {
|
||||
return cs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the image is indexed with a palette
|
||||
*/
|
||||
public boolean isIndexed() {
|
||||
return palette != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of entries in the index
|
||||
*/
|
||||
public int getIndexSize() {
|
||||
return palette != null ? palette.length : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "capture" resolution specified in the file in dots-per-meter,
|
||||
* with the horizontal and vertical resolution stored as the X and Y
|
||||
* values of the returned point. If no resolution is specified,
|
||||
* return null
|
||||
*/
|
||||
public Point2D getCaptureResolution() {
|
||||
return resc == null ? null : new Point2D.Double(resc.getHorizontalResolution(), resc.getVerticalResolution());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "display" resolution specified in the file in dots-per-meter,
|
||||
* with the horizontal and vertical resolution stored as the X and Y
|
||||
* values of the returned point. If no resolution is specified,
|
||||
* return null
|
||||
*/
|
||||
public Point2D getDisplayResolution() {
|
||||
return resd == null ? null : new Point2D.Double(resd.getHorizontalResolution(), resd.getVerticalResolution());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specified component from the image palette
|
||||
*
|
||||
* @param color the color, from 0..getIndexSize()
|
||||
* @param component the component, from 0..getColorSpace().getNumComponents();
|
||||
*/
|
||||
public int getIndexComponent(int color, int component) {
|
||||
return palette[color][component];
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "{JPX: w=" + getWidth() + " h=" + getHeight() + " numc=" + getNumComponents() + " bpc=" + getBitsPerComponent() + (isIndexed() ? " ix" + getIndexSize() : "") + " rs=" + getRowSpan() + " hash=0x" + Integer.toHexString(System.identityHashCode(this)) + "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the enumerated colorspace or ICC profile data to a {@link ColorSpace}.
|
||||
* This method could be overriden by subclasses to increase the number
|
||||
* of supported ColorSpaces.
|
||||
*
|
||||
* @param e the enumerated colorspace value, eg 16 for sRGB, or 0 if an ICC profile is specified.
|
||||
* @param iccprofile the raw data of the ICC profile of specified, or null if an enumerated colorspace is used.
|
||||
* @return the ColorSpace, or null if it is unsupported.
|
||||
*/
|
||||
protected ColorSpace createColorSpace(int e, byte[] iccprofile) {
|
||||
if (iccprofile != null) {
|
||||
return new ICC_ColorSpace(ICC_Profile.getInstance(iccprofile));
|
||||
} else {
|
||||
switch (e) {
|
||||
case 16:
|
||||
return ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
||||
case 17:
|
||||
return ColorSpace.getInstance(ColorSpace.CS_GRAY);
|
||||
default:
|
||||
cstype = e;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the reading process should throw an InterruptedIOException.
|
||||
* By default this just checks if Thread.isInterrupted, but different Thread
|
||||
* interruption mechanisms can be used by overriding this method.
|
||||
*/
|
||||
protected boolean isInterrupted() {
|
||||
return Thread.currentThread().isInterrupted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a row of tiles is loaded. For benchmarking, the default is a no-op
|
||||
*/
|
||||
protected void rowCallback() throws IOException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the content of this J2KReader and return it as a BufferedImage object
|
||||
* The ColorSpace must be supported by Java, which means - without extensions
|
||||
* to this API - only RGB, GrayScale and indexed-RGB are supported.
|
||||
* The InputStream this obejct represents will be read fully and closed.
|
||||
*
|
||||
* @throws IOException if an IOException is encountered during read
|
||||
*/
|
||||
public BufferedImage getBufferedImage() throws IOException {
|
||||
int width = getWidth();
|
||||
int height = getHeight();
|
||||
ColorSpace colorSpace = getColorSpace();
|
||||
if (colorSpace == null) {
|
||||
throw new IllegalStateException("Can't create image: unsupported ColorSpace type " + cstype);
|
||||
}
|
||||
int bpc = getBitsPerComponent();
|
||||
int numc = getNumComponents();
|
||||
ColorModel colorModel;
|
||||
|
||||
if (isIndexed() && colorSpace.isCS_sRGB()) {
|
||||
// IndexColorModel is always sRGB in Java.
|
||||
int indexSize = getIndexSize();
|
||||
byte[] palette = new byte[3 * indexSize];
|
||||
for (int i = 0; i < indexSize; i++) {
|
||||
palette[i * 3] = (byte) getIndexComponent(i, 0);
|
||||
palette[i * 3 + 1] = (byte) getIndexComponent(i, 1);
|
||||
palette[i * 3 + 2] = (byte) getIndexComponent(i, 2);
|
||||
}
|
||||
colorModel = new IndexColorModel(bpc, indexSize, palette, 0, false);
|
||||
} else {
|
||||
boolean opaque = getNumComponents() == colorSpace.getNumComponents();
|
||||
if (opaque) {
|
||||
colorModel = new ComponentColorModel(colorSpace, false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
||||
} else {
|
||||
colorModel = new ComponentColorModel(colorSpace, true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
|
||||
}
|
||||
}
|
||||
SampleModel sampleModel = colorModel.createCompatibleSampleModel(width, height);
|
||||
DataBufferByte buffer = (DataBufferByte) sampleModel.createDataBuffer();
|
||||
byte[] buf = buffer.getData();
|
||||
int off = 0, l;
|
||||
while (off < buf.length && (l = read(buf, off, buf.length - off)) >= 0) {
|
||||
off += l;
|
||||
}
|
||||
close();
|
||||
WritableRaster raster = Raster.createWritableRaster(sampleModel, buffer, null);
|
||||
return new BufferedImage(colorModel, raster, false, null);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.IntegerSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.StringSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.CBlkSizeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.PrecinctSizeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.ProgressionSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.encoder.LayersInfo;
|
||||
import org.xbib.graphics.jpeg2000.j2k.image.forwcomptransf.ForwCompTransfSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.GuardBitsSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.QuantStepSizeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.QuantTypeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.roi.MaxShiftSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.analysis.AnWTFilterSpec;
|
||||
|
||||
/**
|
||||
* Interface which defines the parameters required to write a JP2 image.
|
||||
* Abstracted away from the horror that is J2KImageWriteParamJava
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public interface J2KWriteParam {
|
||||
|
||||
/**
|
||||
* Return the desired compression ratio; a value of
|
||||
* 1 implies completely lossless; values of 4-6 are
|
||||
* visually lossless, up towards 20 for lossy but
|
||||
* acceptable
|
||||
*/
|
||||
float getCompressionRatio();
|
||||
|
||||
boolean getLossless();
|
||||
|
||||
int getNumComponents();
|
||||
|
||||
String getLayers();
|
||||
|
||||
IntegerSpec getDecompositionLevel();
|
||||
|
||||
PrecinctSizeSpec getPrecinctPartition();
|
||||
|
||||
ProgressionSpec getProgressionType();
|
||||
|
||||
void setProgressionType(LayersInfo lyrs, String values);
|
||||
|
||||
String getProgressionName();
|
||||
|
||||
StringSpec getSOP();
|
||||
|
||||
StringSpec getEPH();
|
||||
|
||||
ForwCompTransfSpec getComponentTransformation();
|
||||
|
||||
CBlkSizeSpec getCodeBlockSize();
|
||||
|
||||
StringSpec getBypass();
|
||||
|
||||
StringSpec getResetMQ();
|
||||
|
||||
StringSpec getTerminateOnByte();
|
||||
|
||||
StringSpec getCausalCXInfo();
|
||||
|
||||
StringSpec getMethodForMQLengthCalc();
|
||||
|
||||
StringSpec getMethodForMQTermination();
|
||||
|
||||
StringSpec getCodeSegSymbol();
|
||||
|
||||
AnWTFilterSpec getFilters();
|
||||
|
||||
QuantStepSizeSpec getQuantizationStep();
|
||||
|
||||
QuantTypeSpec getQuantizationType();
|
||||
|
||||
GuardBitsSpec getGuardBits();
|
||||
|
||||
MaxShiftSpec getROIs();
|
||||
|
||||
int getStartLevelROI();
|
||||
|
||||
boolean getAlignROI();
|
||||
|
||||
int getNumTiles();
|
||||
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.writer.FileCodestreamWriter;
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.writer.HeaderEncoder;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.encoder.EntropyCoder;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.encoder.PostCompRateAllocator;
|
||||
import org.xbib.graphics.jpeg2000.j2k.image.BlkImgDataSrc;
|
||||
import org.xbib.graphics.jpeg2000.j2k.image.ImgDataConverter;
|
||||
import org.xbib.graphics.jpeg2000.j2k.image.forwcomptransf.ForwCompTransf;
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.AbstractDataSource;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.quantizer.Quantizer;
|
||||
import org.xbib.graphics.jpeg2000.j2k.roi.encoder.ROIScaler;
|
||||
import org.xbib.graphics.jpeg2000.j2k.util.FacilityManager;
|
||||
import org.xbib.graphics.jpeg2000.j2k.util.MsgLogger;
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.analysis.ForwardWT;
|
||||
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* A class to create a J2KFile. J2K compressed data may be
|
||||
* created from any source, although for convenience a
|
||||
* method is supplied to create from a BufferedImage. Compression
|
||||
* requires all the image data all the time, so compression from
|
||||
* a stream is not possible.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class J2KWriter implements MsgLogger {
|
||||
|
||||
private ColorSpecificationBox colr;
|
||||
private PaletteBox pclr;
|
||||
private ResolutionBox resc, resd;
|
||||
private J2KWriteParam param;
|
||||
private float ratio;
|
||||
private boolean reversible;
|
||||
private BlkImgDataSrc src;
|
||||
|
||||
/**
|
||||
* Create a new J2KWriter
|
||||
*/
|
||||
public J2KWriter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void printmsg(int sev, String msg) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(String str, int flind, int ind) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the write parameters. Usually this isn't required, but
|
||||
* it may be called for fine control of the encoding
|
||||
*/
|
||||
public void setParams(J2KWriteParam param) {
|
||||
this.param = param;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the compresison ratio.
|
||||
*
|
||||
*/
|
||||
public void setCompressionRatio(float ratio, boolean reversible) {
|
||||
this.ratio = ratio;
|
||||
this.reversible = reversible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ColorSpace that is written out. This is required if
|
||||
* a BufferedImage wasn't used as a source
|
||||
*/
|
||||
public void setColorSpace(ColorSpace space) {
|
||||
colr = new ColorSpecificationBox(space);
|
||||
pclr = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ColorSpace that is written out, and use a palette
|
||||
*
|
||||
* @param space the underlying ColorSpace
|
||||
* @param size the number of entries in the palette
|
||||
* @param numc the number of components in the palette index
|
||||
* @param palette the palette entries, which are accessed as <code>palette[entry * numc + component]</code>
|
||||
*/
|
||||
public void setColorSpace(ColorSpace space, int size, int numc, byte[] palette) {
|
||||
colr = new ColorSpecificationBox(space);
|
||||
pclr = new PaletteBox(size, numc, palette);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the "capture" resolution that is written out.
|
||||
*
|
||||
* @param horiz the horizontal resolution in dots-per-meter, or 0 for no box
|
||||
* @param vertical the horizontal resolution in dots-per-meter, or 0 for no box
|
||||
*/
|
||||
public void setCaptureResolution(double horiz, double vertical) {
|
||||
resc = horiz > 0 && vertical > 0 ? new ResolutionBox(Box.fromString("resc"), (float) horiz, (float) vertical) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the "diisplay" resolution that is written out.
|
||||
*
|
||||
* @param horiz the horizontal resolution in dots-per-meter, or 0 for no box
|
||||
* @param vertical the horizontal resolution in dots-per-meter, or 0 for no box
|
||||
*/
|
||||
public void setDisplayResolution(double horiz, double vertical) {
|
||||
resd = horiz > 0 && vertical > 0 ? new ResolutionBox(Box.fromString("resd"), (float) horiz, (float) vertical) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Source for the image. Any BlkImgDataSrc may be used, but
|
||||
* a {@link AbstractDataSource} would be the easiest
|
||||
*/
|
||||
public void setSource(BlkImgDataSrc src) {
|
||||
this.src = src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Source for the image to the BufferedImage.
|
||||
*
|
||||
* @param img the image
|
||||
* @param tilesize the tilesize, 256 is recommended
|
||||
*/
|
||||
public void setSource(BufferedImage img, int tilesize) {
|
||||
setSource(AbstractDataSource.newInstance(img, tilesize));
|
||||
ColorModel cm = img.getColorModel();
|
||||
if (cm instanceof IndexColorModel) {
|
||||
throw new UnsupportedOperationException("No indexed yet");
|
||||
// TODO
|
||||
} else {
|
||||
setColorSpace(cm.getColorSpace());
|
||||
}
|
||||
}
|
||||
|
||||
private J2KFile doCreate(OutputStream out) throws IOException {
|
||||
if (src == null) {
|
||||
throw new IllegalStateException("No source");
|
||||
}
|
||||
if (param == null) {
|
||||
param = new SimpleJ2KWriteParam(src.getNumComps(), src.getNumTiles());
|
||||
((SimpleJ2KWriteParam) param).setProgressionName("res");
|
||||
}
|
||||
if (ratio != 0 && param instanceof SimpleJ2KWriteParam) {
|
||||
((SimpleJ2KWriteParam) param).setCompression(ratio, reversible);
|
||||
}
|
||||
if (param.getNumComponents() != src.getNumComps() || param.getNumTiles() != src.getNumTiles()) {
|
||||
throw new IllegalStateException("Param and source do not match");
|
||||
}
|
||||
|
||||
Thread registerThread = Thread.currentThread();
|
||||
|
||||
J2KFile file = new J2KFile();
|
||||
HeaderBox jp2h = new HeaderBox();
|
||||
int bpc = src.getNomRangeBits(0);
|
||||
int totbpc = bpc;
|
||||
for (int i = 1; i < src.getNumComps(); i++) {
|
||||
totbpc += src.getNomRangeBits(i);
|
||||
if (src.getNomRangeBits(i) != bpc) {
|
||||
bpc = 255;
|
||||
}
|
||||
}
|
||||
jp2h.add(new ImageHeaderBox(src.getImgWidth(), src.getImgHeight(), src.getNumComps(), bpc, false, false));
|
||||
if (colr != null) {
|
||||
jp2h.add(colr);
|
||||
}
|
||||
if (pclr != null) {
|
||||
jp2h.add(pclr);
|
||||
}
|
||||
if (resc != null || resd != null) {
|
||||
ResolutionSuperBox res = new ResolutionSuperBox();
|
||||
if (resc != null) {
|
||||
res.add(resc);
|
||||
}
|
||||
if (resd != null) {
|
||||
res.add(resd);
|
||||
}
|
||||
jp2h.add(res);
|
||||
}
|
||||
if (bpc == 255) {
|
||||
byte[] b = new byte[src.getNumComps()];
|
||||
for (int i = 0; i < b.length; i++) {
|
||||
b[i] = (byte) src.getNomRangeBits(i);
|
||||
}
|
||||
jp2h.add(new BitsPerComponentBox(b));
|
||||
}
|
||||
file.add(new FileTypeBox());
|
||||
file.add(jp2h);
|
||||
|
||||
OutputStream bout;
|
||||
if (out == null) {
|
||||
bout = new ByteArrayOutputStream();
|
||||
} else {
|
||||
file.add(new CodeStreamBox());
|
||||
file.write(out);
|
||||
bout = out;
|
||||
}
|
||||
|
||||
try {
|
||||
FacilityManager.registerMsgLogger(registerThread, this);
|
||||
ForwCompTransf fctransf = new ForwCompTransf(src, param);
|
||||
ImgDataConverter converter = new ImgDataConverter(fctransf);
|
||||
ForwardWT dwt = ForwardWT.createInstance(converter, param);
|
||||
Quantizer quant = Quantizer.createInstance(dwt, param);
|
||||
ROIScaler rois = ROIScaler.createInstance(quant, param);
|
||||
EntropyCoder ecoder = EntropyCoder.createInstance(rois, param, param.getCodeBlockSize(), param.getPrecinctPartition(), param.getBypass(), param.getResetMQ(), param.getTerminateOnByte(), param.getCausalCXInfo(), param.getCodeSegSymbol(), param.getMethodForMQLengthCalc(), param.getMethodForMQTermination());
|
||||
|
||||
FileCodestreamWriter bwriter = new FileCodestreamWriter(bout, Integer.MAX_VALUE);
|
||||
ratio = param.getCompressionRatio();
|
||||
float rate = ratio == 1 ? Float.POSITIVE_INFINITY : totbpc / ratio;
|
||||
PostCompRateAllocator ralloc = PostCompRateAllocator.createInstance(ecoder, rate, bwriter, param);
|
||||
HeaderEncoder headenc = new HeaderEncoder(src, new boolean[src.getNumComps()], dwt, src, param, rois, ralloc);
|
||||
ralloc.setHeaderEncoder(headenc);
|
||||
headenc.encodeMainHeader();
|
||||
ralloc.initialize();
|
||||
headenc.reset();
|
||||
headenc.encodeMainHeader();
|
||||
bwriter.commitBitstreamHeader(headenc);
|
||||
ralloc.runAndWrite();
|
||||
bwriter.close();
|
||||
|
||||
if (out == null) {
|
||||
file.add(new CodeStreamBox(((ByteArrayOutputStream) bout).toByteArray()));
|
||||
}
|
||||
return file;
|
||||
} finally {
|
||||
FacilityManager.unregisterMsgLogger(registerThread);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a {@link J2KFile} which has the compressed image data
|
||||
*/
|
||||
public J2KFile create() throws IOException {
|
||||
return doCreate(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and write a {@link J2KFile} to the specified OutputStream. This
|
||||
* method does not need any intermediate buffers and can write the compressed
|
||||
* image straight to the OutputStream, unlike {@link #create} which has to
|
||||
* store the image in memory.
|
||||
*/
|
||||
public void write(OutputStream out) throws IOException {
|
||||
doCreate(out);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class represents the "pclr" box.
|
||||
* <p>
|
||||
* Its content contains the number of palette entry, the number of color
|
||||
* components, the bit depths of the output components, the LUT.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class PaletteBox extends Box {
|
||||
|
||||
private int numEntries;
|
||||
private int numc;
|
||||
private int[] bitDepth;
|
||||
private int[] lut;
|
||||
|
||||
public PaletteBox() {
|
||||
super(fromString("pclr"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>PlatteBox</code> from an <code>IndexColorModel</code>.
|
||||
* Lifted from JAI, untested
|
||||
*/
|
||||
public PaletteBox(IndexColorModel icm) {
|
||||
this(icm.hasAlpha() ? new int[]{8, 8, 8, 8} : new int[]{8, 8, 8}, getLUT(icm));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>PlatteBox</code> from the provided length, bit
|
||||
* depths of the color components and the LUT.
|
||||
*/
|
||||
public PaletteBox(int[] depths, int[] lut) {
|
||||
this();
|
||||
this.bitDepth = depths;
|
||||
this.lut = lut;
|
||||
this.numc = depths.length;
|
||||
this.numEntries = lut.length / numc;
|
||||
}
|
||||
|
||||
public PaletteBox(int len, int numc, byte[] lut) {
|
||||
this();
|
||||
this.numEntries = len;
|
||||
this.numc = numc;
|
||||
this.bitDepth = new int[numc];
|
||||
for (int i = 0; i < numc; i++) {
|
||||
bitDepth[i] = 8;
|
||||
}
|
||||
this.lut = new int[len * numc];
|
||||
for (int i = 0; i < lut.length; i++) {
|
||||
this.lut[i] = lut[i] & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the LUT from the <code>IndexColorModel</code> as an two-dimensional
|
||||
* byte array.
|
||||
*/
|
||||
private static int[] getLUT(IndexColorModel icm) {
|
||||
int size = icm.getMapSize();
|
||||
int numc = icm.hasAlpha() ? 3 : 4; // IndexColorModel always RGB or RGBA
|
||||
int[] lut = new int[size * numc];
|
||||
int k = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
lut[k++] = icm.getRed(i);
|
||||
lut[k++] = icm.getGreen(i);
|
||||
lut[k++] = icm.getBlue(i);
|
||||
if (numc == 4) {
|
||||
lut[k++] = icm.getAlpha(i);
|
||||
}
|
||||
}
|
||||
return lut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of palette entries.
|
||||
*/
|
||||
public int getNumEntries() {
|
||||
return numEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of color components.
|
||||
*/
|
||||
public int getNumComp() {
|
||||
return numc;
|
||||
}
|
||||
|
||||
public int getComponentDepth(int component) {
|
||||
return (bitDepth[component] & 0x7F) + 1;
|
||||
}
|
||||
|
||||
public boolean isComponentSigned(int component) {
|
||||
return (bitDepth[component] & 0x80) != 0;
|
||||
}
|
||||
|
||||
public int getComponentValue(int entry, int component) {
|
||||
return lut[entry * numc + component];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
numEntries = in.readShort();
|
||||
numc = in.readByte() & 0xFF;
|
||||
bitDepth = new int[numc];
|
||||
for (int i = 0; i < numc; i++) {
|
||||
bitDepth[i] = in.readByte() & 0xFF;
|
||||
}
|
||||
lut = new int[in.length() - in.getPos()];
|
||||
for (int i = 0; i < lut.length; i++) {
|
||||
int c = i % numc;
|
||||
int d = getComponentDepth(c);
|
||||
boolean signed = isComponentSigned(c);
|
||||
if (d <= 8) {
|
||||
lut[i] = signed ? (int) in.readByte() : in.readByte() & 0xFF;
|
||||
} else {
|
||||
lut[i] = signed ? (int) in.readShort() : in.readShort() & 0xFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeShort(numEntries);
|
||||
out.write(numc);
|
||||
for (int i = 0; i < numc; i++) {
|
||||
out.write(bitDepth[i]);
|
||||
}
|
||||
for (int i = 0; i < lut.length; i++) {
|
||||
int c = i % numc;
|
||||
int v = i / numc;
|
||||
int d = getComponentDepth(c);
|
||||
if (d <= 8) {
|
||||
out.write(getComponentValue(v, c));
|
||||
} else {
|
||||
out.writeShort(getComponentValue(v, c));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(",\"depth\":[");
|
||||
for (int i = 0; i < numc; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(bitDepth[i]);
|
||||
}
|
||||
sb.append("],\"lut\":[");
|
||||
for (int i = 0; i < lut.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append(lut[i]);
|
||||
}
|
||||
sb.append("]}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class represents the "resc" and "resd" boxes.
|
||||
* <p>
|
||||
* Its contens includes the resolution numerators, denominator, and the
|
||||
* exponents for both horizontal and vertical directions.
|
||||
*
|
||||
* @author http://bfo.com, with large parts copied from JAI source
|
||||
*/
|
||||
public class ResolutionBox extends Box {
|
||||
|
||||
private short numV;
|
||||
private short numH;
|
||||
private short denomV;
|
||||
private short denomH;
|
||||
private byte expV;
|
||||
private byte expH;
|
||||
|
||||
/**
|
||||
* The cached horizontal/vertical resolutions.
|
||||
*/
|
||||
private float hRes;
|
||||
private float vRes;
|
||||
|
||||
public ResolutionBox(int type) {
|
||||
super(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>ResolutionBox</code> from the provided type and
|
||||
* horizontal/vertical resolutions.
|
||||
*/
|
||||
public ResolutionBox(int type, float hRes, float vRes) {
|
||||
this(type);
|
||||
this.hRes = hRes;
|
||||
this.vRes = vRes;
|
||||
denomH = denomV = 1;
|
||||
|
||||
expV = 0;
|
||||
if (vRes >= 32768) {
|
||||
int temp = (int) vRes;
|
||||
while (temp >= 32768) {
|
||||
expV++;
|
||||
temp /= 10;
|
||||
}
|
||||
numV = (short) (temp & 0xFFFF);
|
||||
} else {
|
||||
numV = (short) vRes;
|
||||
}
|
||||
|
||||
expH = 0;
|
||||
if (hRes >= 32768) {
|
||||
int temp = (int) hRes;
|
||||
while (temp >= 32768) {
|
||||
expH++;
|
||||
temp /= 10;
|
||||
}
|
||||
numH = (short) (temp & 0xFFFF);
|
||||
} else {
|
||||
numH = (short) hRes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the horizontal resolution.
|
||||
*/
|
||||
public float getHorizontalResolution() {
|
||||
return hRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the vertical resolution.
|
||||
*/
|
||||
public float getVerticalResolution() {
|
||||
return vRes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
numV = in.readShort();
|
||||
denomV = in.readShort();
|
||||
numH = in.readShort();
|
||||
denomH = in.readShort();
|
||||
expV = in.readByte();
|
||||
expH = in.readByte();
|
||||
vRes = (float) ((numV & 0xFFFF) * Math.pow(10, expV) / (denomV & 0xFFFF));
|
||||
hRes = (float) ((numH & 0xFFFF) * Math.pow(10, expH) / (denomH & 0xFFFF));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeShort(numV);
|
||||
out.writeShort(denomV);
|
||||
out.writeShort(numH);
|
||||
out.writeShort(denomH);
|
||||
out.write(expV);
|
||||
out.write(expH);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeEmptyElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
out.writeAttribute("hres", Float.toString(hRes));
|
||||
out.writeAttribute("vres", Float.toString(vRes));
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(",\"nv\":");
|
||||
sb.append(numV);
|
||||
sb.append(",\"dv\":");
|
||||
sb.append(denomV);
|
||||
sb.append(",\"ev\":");
|
||||
sb.append(expV);
|
||||
sb.append(",\"nh\":");
|
||||
sb.append(numH);
|
||||
sb.append(",\"dh\":");
|
||||
sb.append(denomH);
|
||||
sb.append(",\"eh\":");
|
||||
sb.append(expH);
|
||||
sb.append(",\"hres\":");
|
||||
sb.append(hRes);
|
||||
sb.append(",\"vres\":");
|
||||
sb.append(vRes);
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
/**
|
||||
* Represents the "res" resolution superbox
|
||||
*/
|
||||
public class ResolutionSuperBox extends ContainerBox {
|
||||
|
||||
public ResolutionSuperBox() {
|
||||
super(fromString("res "));
|
||||
}
|
||||
|
||||
public ResolutionSuperBox(ResolutionBox box) {
|
||||
this();
|
||||
add(box);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
/**
|
||||
* Interface which defines the parameters required to read a JP2 image.
|
||||
* The default values for each property are used.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class SimpleJ2KReadParam implements J2KReadParam {
|
||||
|
||||
public boolean getNoROIDescaling() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public double getDecodingRate() {
|
||||
return Double.MAX_VALUE;
|
||||
}
|
||||
|
||||
public int getResolution() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.IntegerSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.ModuleSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.StringSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.CBlkSizeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.PrecinctSizeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.ProgressionSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.encoder.LayersInfo;
|
||||
import org.xbib.graphics.jpeg2000.j2k.image.forwcomptransf.ForwCompTransfSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.GuardBitsSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.QuantStepSizeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.QuantTypeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.roi.MaxShiftSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.analysis.AnWTFilterSpec;
|
||||
|
||||
/**
|
||||
* A minimal instance of the J2KWriteParam interface.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class SimpleJ2KWriteParam implements J2KWriteParam {
|
||||
|
||||
private final int numc, numtiles;
|
||||
private final StringSpec stringtrue, stringfalse;
|
||||
private IntegerSpec decompositionLevel;
|
||||
private PrecinctSizeSpec precinctPartition;
|
||||
private ProgressionSpec progressionType;
|
||||
private GuardBitsSpec guardBits;
|
||||
private AnWTFilterSpec filters;
|
||||
private ForwCompTransfSpec componentTransformation;
|
||||
private QuantStepSizeSpec quantizationStep;
|
||||
private QuantTypeSpec quantizationType;
|
||||
private CBlkSizeSpec codeBlockSize;
|
||||
private StringSpec methodForMQTermination;
|
||||
private StringSpec methodForMQLengthCalc;
|
||||
private int startLevelROI;
|
||||
private float ratio;
|
||||
private String layers;
|
||||
private String progressionName;
|
||||
private boolean alignROI;
|
||||
private boolean sop;
|
||||
private boolean eph;
|
||||
private boolean bypass;
|
||||
private boolean resetMQ;
|
||||
private boolean terminateOnByte;
|
||||
private boolean causalCXInfo;
|
||||
private boolean codeSegSymbol;
|
||||
private boolean lossless;
|
||||
private MaxShiftSpec rois;
|
||||
|
||||
/**
|
||||
* Create a new SimpleJ2KWriteParam
|
||||
*
|
||||
* @param numc the number of components
|
||||
* @param numtiles the number of tiles
|
||||
*/
|
||||
public SimpleJ2KWriteParam(int numc, int numtiles) {
|
||||
this.numc = numc;
|
||||
this.numtiles = numtiles;
|
||||
stringtrue = new StringSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, "false", new String[]{"true", "false"}, null, "true");
|
||||
stringfalse = new StringSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, "false", new String[]{"true", "false"}, null, null);
|
||||
|
||||
setLayers("0.015 +20 2.0 +10");
|
||||
setProgressionName("layer");
|
||||
setDecompositionLevel(5);
|
||||
setGuardBits(2);
|
||||
setQuantizationStep(Double.NaN);
|
||||
setCodeBlockSize(64, 64);
|
||||
setFilters(true, true);
|
||||
setROIs(-1, false, null);
|
||||
setMQ(null, null);
|
||||
setCompression(1, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the desired Compression Ratio. A value of
|
||||
* 1 implies lossless, higher ratios involve loss
|
||||
*
|
||||
* @param ratio the compression ratio
|
||||
* @param reversible if true, the reversible filter is used. The irreversible one tends to give slightly better results but may use more memory
|
||||
*/
|
||||
public void setCompression(float ratio, boolean reversible) {
|
||||
this.ratio = Math.max(1, ratio);
|
||||
lossless = ratio == 1;
|
||||
setFilters(lossless || reversible, true);
|
||||
}
|
||||
|
||||
public float getCompressionRatio() {
|
||||
return ratio;
|
||||
}
|
||||
|
||||
public int getNumComponents() {
|
||||
return numc;
|
||||
}
|
||||
|
||||
public int getNumTiles() {
|
||||
return numtiles;
|
||||
}
|
||||
|
||||
public boolean getLossless() {
|
||||
return lossless;
|
||||
}
|
||||
|
||||
public String getLayers() {
|
||||
return layers;
|
||||
}
|
||||
|
||||
private void setLayers(String layers) {
|
||||
this.layers = layers;
|
||||
}
|
||||
|
||||
public IntegerSpec getDecompositionLevel() {
|
||||
return decompositionLevel;
|
||||
}
|
||||
|
||||
public void setDecompositionLevel(int level) {
|
||||
decompositionLevel = new IntegerSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, this, Integer.toString(level), "5");
|
||||
precinctPartition = new PrecinctSizeSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, null, getDecompositionLevel(), this, null);
|
||||
}
|
||||
|
||||
public PrecinctSizeSpec getPrecinctPartition() {
|
||||
return precinctPartition;
|
||||
}
|
||||
|
||||
public void setProgressionType(LayersInfo lyrs, String values) {
|
||||
progressionType = new ProgressionSpec(getNumTiles(), getNumComponents(), lyrs.getTotNumLayers(), getDecompositionLevel(), ModuleSpec.SPEC_TYPE_TILE_COMP, this, values);
|
||||
}
|
||||
|
||||
public ProgressionSpec getProgressionType() {
|
||||
return progressionType;
|
||||
}
|
||||
|
||||
public String getProgressionName() {
|
||||
return progressionName;
|
||||
}
|
||||
|
||||
public void setProgressionName(String name) {
|
||||
if ("res".equals(name) || "layer".equals(name) || "res-pos".equals(name) || "pos-comp".equals(name) || "comp-pos".equals(name)) {
|
||||
progressionName = name;
|
||||
} else {
|
||||
throw new IllegalArgumentException(name);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFilters(boolean filter53, boolean transform) {
|
||||
if (filter53) {
|
||||
quantizationType = new QuantTypeSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, this, "reversible");
|
||||
filters = new AnWTFilterSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, getQuantizationType(), this, "w5x3");
|
||||
} else {
|
||||
quantizationType = new QuantTypeSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, this, "expounded");
|
||||
filters = new AnWTFilterSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, getQuantizationType(), this, "w9x7");
|
||||
}
|
||||
componentTransformation = new ForwCompTransfSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE, getFilters(), this, Boolean.toString(transform));
|
||||
}
|
||||
|
||||
public AnWTFilterSpec getFilters() {
|
||||
return filters;
|
||||
}
|
||||
|
||||
public QuantTypeSpec getQuantizationType() {
|
||||
return quantizationType;
|
||||
}
|
||||
|
||||
public ForwCompTransfSpec getComponentTransformation() {
|
||||
return componentTransformation;
|
||||
}
|
||||
|
||||
public void setCodeBlockSize(int w, int h) {
|
||||
codeBlockSize = new CBlkSizeSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, this, w + " " + h);
|
||||
}
|
||||
|
||||
public CBlkSizeSpec getCodeBlockSize() {
|
||||
return codeBlockSize;
|
||||
}
|
||||
|
||||
public StringSpec getSOP() {
|
||||
// return sop ? stringtrue : stringfalse;
|
||||
return new StringSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, "false", new String[]{"true", "false"}, null, "false");
|
||||
}
|
||||
|
||||
public StringSpec getEPH() {
|
||||
// return eph ? stringtrue : stringfalse;
|
||||
return new StringSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, "false", new String[]{"true", "false"}, null, "false");
|
||||
}
|
||||
|
||||
public StringSpec getBypass() {
|
||||
// return bypass ? stringtrue : stringfalse;
|
||||
return new StringSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, "false", new String[]{"true", "false"}, null, "false");
|
||||
}
|
||||
|
||||
public StringSpec getResetMQ() {
|
||||
// return resetMQ ? stringtrue : stringfalse;
|
||||
return new StringSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, "false", new String[]{"true", "false"}, null, null);
|
||||
}
|
||||
|
||||
public StringSpec getTerminateOnByte() {
|
||||
// return terminateOnByte ? stringtrue : stringfalse;
|
||||
return new StringSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, "false", new String[]{"true", "false"}, null, null);
|
||||
}
|
||||
|
||||
public StringSpec getCausalCXInfo() {
|
||||
// return causalCXInfo ? stringtrue : stringfalse;
|
||||
return new StringSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, "false", new String[]{"true", "false"}, null, null);
|
||||
}
|
||||
|
||||
public StringSpec getCodeSegSymbol() {
|
||||
// return codeSegSymbol ? stringtrue : stringfalse;
|
||||
return new StringSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, "false", new String[]{"true", "false"}, null, null);
|
||||
}
|
||||
|
||||
public void setMQ(String lengthcalc, String termination) {
|
||||
if (lengthcalc == null) {
|
||||
lengthcalc = "near_opt";
|
||||
}
|
||||
if (termination == null) {
|
||||
termination = "near_opt";
|
||||
}
|
||||
methodForMQLengthCalc = new StringSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, "near_opt", new String[]{"near_opt", "lazy_good", "lazy"}, this, lengthcalc);
|
||||
methodForMQTermination = new StringSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, "near_opt", new String[]{"near_opt", "easy", "predict", "full"}, this, termination);
|
||||
}
|
||||
|
||||
public StringSpec getMethodForMQLengthCalc() {
|
||||
return methodForMQLengthCalc;
|
||||
}
|
||||
|
||||
public StringSpec getMethodForMQTermination() {
|
||||
return methodForMQTermination;
|
||||
}
|
||||
|
||||
public QuantStepSizeSpec getQuantizationStep() {
|
||||
return quantizationStep;
|
||||
}
|
||||
|
||||
public void setQuantizationStep(double val) {
|
||||
quantizationStep = new QuantStepSizeSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, this, val == val ? Double.toString(val) : null);
|
||||
}
|
||||
|
||||
public GuardBitsSpec getGuardBits() {
|
||||
return guardBits;
|
||||
}
|
||||
|
||||
public void setGuardBits(int bits) {
|
||||
if (bits <= 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
guardBits = new GuardBitsSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, this, Integer.toString(bits));
|
||||
}
|
||||
|
||||
public void setROIs(int start, boolean align, String rois) {
|
||||
this.startLevelROI = start;
|
||||
this.alignROI = align;
|
||||
this.rois = new MaxShiftSpec(getNumTiles(), getNumComponents(), ModuleSpec.SPEC_TYPE_TILE_COMP, rois);
|
||||
}
|
||||
|
||||
public MaxShiftSpec getROIs() {
|
||||
return rois;
|
||||
}
|
||||
|
||||
public int getStartLevelROI() {
|
||||
return startLevelROI;
|
||||
}
|
||||
|
||||
public boolean getAlignROI() {
|
||||
return alignROI;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String sb = "{ lossless:" + getLossless() +
|
||||
", numc:" + getNumComponents() +
|
||||
", numt:" + getNumTiles() +
|
||||
", layers:'" + getLayers() + "'" +
|
||||
", decomp:" + getDecompositionLevel() +
|
||||
", precinct:" + getPrecinctPartition() +
|
||||
", prog:" + getProgressionType() +
|
||||
", progn:'" + getProgressionName() + "'" +
|
||||
", sop:" + getSOP() +
|
||||
", eph:" + getEPH() +
|
||||
", tran:" + getComponentTransformation() +
|
||||
", cbsize:" + getCodeBlockSize() +
|
||||
", bypass:" + getBypass() +
|
||||
", resetmq:" + getResetMQ() +
|
||||
", termonbyte:" + getTerminateOnByte() +
|
||||
", causalcxinfo:" + getCausalCXInfo() +
|
||||
", mqlengthcalc:" + getMethodForMQLengthCalc() +
|
||||
", mqterm:" + getMethodForMQTermination() +
|
||||
", codeseg:" + getCodeSegSymbol() +
|
||||
", filters:" + getFilters() +
|
||||
", quantstep:" + getQuantizationStep() +
|
||||
", quanttype:" + getQuantizationType() +
|
||||
", guardbits:" + getGuardBits() +
|
||||
", rois:" + getROIs() +
|
||||
", startlevelroi:" + getStartLevelROI() +
|
||||
", alignroi:" + getAlignROI() +
|
||||
"}";
|
||||
return sb;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* This class represents the "url " box.
|
||||
* Its content are a one-byte version, a three-byte flags and
|
||||
* a URL pertains to the UUID List box within its UUID Info superbox.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class URLBox extends Box {
|
||||
|
||||
/**
|
||||
* The element values.
|
||||
*/
|
||||
private int version;
|
||||
private int flags;
|
||||
private String url;
|
||||
|
||||
public URLBox() {
|
||||
super(fromString("url "));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>DataEntryURLBox</code> from its data elements.
|
||||
*/
|
||||
public URLBox(int version, int flags, String url) {
|
||||
this();
|
||||
this.version = version;
|
||||
this.flags = flags;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 4 + url.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
version = in.read();
|
||||
flags = (in.read() << 16) | (in.read() << 8) | in.read();
|
||||
|
||||
byte[] b = new byte[in.length() - in.getPos()];
|
||||
in.readFully(b, 0, b.length);
|
||||
url = new String(b, StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.write(version);
|
||||
out.write(flags >> 16);
|
||||
out.write(flags >> 8);
|
||||
out.write(flags);
|
||||
out.write(url.getBytes(StandardCharsets.ISO_8859_1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>Version</code> data element.
|
||||
*/
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>Flags</code> data element.
|
||||
*/
|
||||
public int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>URL</code> data element.
|
||||
*/
|
||||
public String getURL() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeStartElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
out.writeAttribute("version", Integer.toString(getVersion()));
|
||||
out.writeAttribute("flags", "0x" + Integer.toHexString(getFlags()));
|
||||
out.writeCharacters(getURL());
|
||||
out.writeEndElement();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(",\"version\":");
|
||||
sb.append(getVersion());
|
||||
sb.append(",\"flags\":");
|
||||
sb.append(getFlags());
|
||||
sb.append(",\"url\":\"");
|
||||
sb.append(getURL().replaceAll("\"", "\\\""));
|
||||
sb.append("\"}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.namespace.NamespaceContext;
|
||||
import javax.xml.stream.XMLEventReader;
|
||||
import javax.xml.stream.XMLEventWriter;
|
||||
import javax.xml.stream.XMLOutputFactory;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import javax.xml.stream.events.XMLEvent;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.stax.StAXResult;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* This class represents the "uuid" box.
|
||||
* Its content is a 16-byte UUID followed with a various-length data.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class UUIDBox extends Box {
|
||||
|
||||
public static final String UUID_XMP = "be7acfcb97a942e89c71999491e3afac";
|
||||
private byte[] uuid;
|
||||
private byte[] data;
|
||||
|
||||
/**
|
||||
* Constructs a <code>UUIDBox</code> from its content data array.
|
||||
*/
|
||||
public UUIDBox() {
|
||||
super(fromString("uuid"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new UUID box
|
||||
*
|
||||
* @param key the key, which must be a 16 byte long array encoded as a 32-character long hex string
|
||||
* @parma data the data
|
||||
*/
|
||||
public UUIDBox(String key, byte[] data) {
|
||||
this();
|
||||
if (key.length() != 32) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
uuid = new byte[16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
uuid[i] = (byte) ((Character.digit(key.charAt(i * 2), 16) << 4) + Character.digit(key.charAt(i * 2 + 1), 16));
|
||||
}
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return uuid.length + data.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
uuid = new byte[16];
|
||||
in.readFully(uuid, 0, 16);
|
||||
data = new byte[in.length() - in.getPos()];
|
||||
in.readFully(data, 0, data.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.write(uuid, 0, uuid.length);
|
||||
out.write(data, 0, data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UUID of this box.
|
||||
*/
|
||||
public String getUUID() {
|
||||
return toString(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the UUID data of this box.
|
||||
*/
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeStartElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
out.writeAttribute("uuid", getUUID());
|
||||
boolean raw = true;
|
||||
if (UUID_XMP.equals(getUUID())) {
|
||||
try {
|
||||
String s = new String(getData(), StandardCharsets.UTF_8);
|
||||
TransformerFactory tf = TransformerFactory.newInstance();
|
||||
Transformer t = tf.newTransformer();
|
||||
t.transform(new StreamSource(new StringReader(s)), new StreamResult(new StringWriter()));
|
||||
// Syntax is valid, redo output to actual outputstream, removing startDoc/endDoc
|
||||
final XMLEventWriter w = XMLOutputFactory.newInstance().createXMLEventWriter(new StAXResult(out));
|
||||
t.transform(new StreamSource(new StringReader(s)), new StAXResult(new XMLEventWriter() {
|
||||
public void add(XMLEvent event) throws XMLStreamException {
|
||||
if (!event.isStartDocument() && !event.isEndDocument()) {
|
||||
w.add(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(XMLEventReader reader) throws XMLStreamException {
|
||||
w.add(reader);
|
||||
}
|
||||
|
||||
public void close() throws XMLStreamException {
|
||||
}
|
||||
|
||||
public void flush() throws XMLStreamException {
|
||||
w.flush();
|
||||
}
|
||||
|
||||
public NamespaceContext getNamespaceContext() {
|
||||
return w.getNamespaceContext();
|
||||
}
|
||||
|
||||
public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
|
||||
w.setNamespaceContext(context);
|
||||
}
|
||||
|
||||
public String getPrefix(String uri) throws XMLStreamException {
|
||||
return w.getPrefix(uri);
|
||||
}
|
||||
|
||||
public void setDefaultNamespace(String uri) throws XMLStreamException {
|
||||
w.setDefaultNamespace(uri);
|
||||
}
|
||||
|
||||
public void setPrefix(String prefix, String uri) throws XMLStreamException {
|
||||
w.setPrefix(prefix, uri);
|
||||
}
|
||||
}));
|
||||
raw = false;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
if (raw) {
|
||||
out.writeCharacters(toString(data));
|
||||
}
|
||||
out.writeEndElement();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append("\"uuid\":\"");
|
||||
sb.append(getUUID());
|
||||
sb.append("\",\"data\":");
|
||||
sb.append(toString(getData()));
|
||||
sb.append("\"}");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
/**
|
||||
* Represents the "uinf" box
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class UUIDInfoBox extends ContainerBox {
|
||||
|
||||
private UUIDListBox ulst;
|
||||
private URLBox url;
|
||||
|
||||
public UUIDInfoBox() {
|
||||
super(fromString("uinf"));
|
||||
}
|
||||
|
||||
public UUIDInfoBox(UUIDListBox ulst, URLBox url) {
|
||||
this();
|
||||
add(ulst);
|
||||
add(url);
|
||||
}
|
||||
|
||||
public UUIDListBox getUUIDListBox() {
|
||||
return ulst;
|
||||
}
|
||||
|
||||
public URLBox getURLBox() {
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContainerBox add(Box box) {
|
||||
if (box instanceof UUIDListBox) {
|
||||
if (ulst == null) {
|
||||
ulst = (UUIDListBox) box;
|
||||
} else {
|
||||
throw new IllegalStateException("More than one ulst box");
|
||||
}
|
||||
} else if (box instanceof URLBox) {
|
||||
if (ulst == null) {
|
||||
throw new IllegalStateException("ulst box must come before url box");
|
||||
} else if (url == null) {
|
||||
url = (URLBox) box;
|
||||
} else {
|
||||
throw new IllegalStateException("More than one url box");
|
||||
}
|
||||
}
|
||||
return super.add(box);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class represents the "ulst" box.
|
||||
* Its contents include the number of UUID entry and a list of 16-byte UUIDs.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class UUIDListBox extends Box {
|
||||
|
||||
private byte[][] uuids;
|
||||
|
||||
public UUIDListBox() {
|
||||
super(fromString("ulst"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>UUIDListBox</code> from the provided list of UUIDs
|
||||
*
|
||||
* @param uuids a list of uuids, each represented as 32-character long strings representing a hex-encoded 16-byte array
|
||||
*/
|
||||
public UUIDListBox(String[] uuids) {
|
||||
this();
|
||||
this.uuids = new byte[uuids.length][16];
|
||||
for (int j = 0; j < uuids.length; j++) {
|
||||
String key = uuids[j];
|
||||
if (key.length() != 32) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
for (int i = 0; i < 16; i++) {
|
||||
this.uuids[j][i] = (byte) ((Character.digit(key.charAt(i * 2), 16) << 4) + Character.digit(key.charAt(i * 2 + 1), 16));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return uuids.length;
|
||||
}
|
||||
|
||||
public String getUUID(int i) {
|
||||
return toString(uuids[i]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLength() {
|
||||
return 2 + uuids.length * 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(RandomAccessIO in) throws IOException {
|
||||
int num = in.readShort();
|
||||
uuids = new byte[num][16];
|
||||
for (int i = 0; i < num; i++) {
|
||||
in.readFully(uuids[i], 0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream out) throws IOException {
|
||||
out.writeShort(uuids.length);
|
||||
for (int i = 0; i < uuids.length; i++) {
|
||||
out.write(uuids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(XMLStreamWriter out) throws XMLStreamException {
|
||||
out.writeStartElement(toString(getType()).trim());
|
||||
out.writeAttribute("length", Integer.toString(getLength()));
|
||||
for (int i = 0; i < uuids.length; i++) {
|
||||
out.writeStartElement("uuid");
|
||||
out.writeCharacters(toString(uuids[i]));
|
||||
out.writeEndElement();
|
||||
}
|
||||
out.writeEndElement();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
sb.append(",\"uuids\":[");
|
||||
for (int i = 0; i < uuids.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(",");
|
||||
}
|
||||
sb.append("\"");
|
||||
sb.append(toString(uuids[i]));
|
||||
sb.append("\"");
|
||||
}
|
||||
sb.append("]}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package org.xbib.graphics.jpeg2000;
|
||||
|
||||
/**
|
||||
* This class represnts the "xml " box.
|
||||
*
|
||||
* @author http://bfo.com
|
||||
*/
|
||||
public class XMLBox extends Box {
|
||||
|
||||
public XMLBox() {
|
||||
super(fromString("xml "));
|
||||
}
|
||||
|
||||
// TODO
|
||||
}
|
|
@ -0,0 +1,265 @@
|
|||
package org.xbib.graphics.jpeg2000.imageio;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.J2KFile;
|
||||
import org.xbib.graphics.jpeg2000.J2KReader;
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.AbstractRandomAccessIO;
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* ImageIO compatible reader for JPEG2000 images.
|
||||
*/
|
||||
public class JPEG2000Reader extends ImageReader {
|
||||
|
||||
private BufferedImage image;
|
||||
|
||||
public JPEG2000Reader(ImageReaderSpi imageReaderImpl) {
|
||||
super(imageReaderImpl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canReadRaster() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumImages(boolean allowSearch) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth(int imageIndex) throws IOException {
|
||||
return getImage().getWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight(int imageIndex) throws IOException {
|
||||
return getImage().getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
|
||||
BufferedImage image = getImage();
|
||||
return Collections.singleton(new ImageTypeSpecifier(image.getColorModel(), image.getSampleModel())).iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIOMetadata getStreamMetadata() {
|
||||
throw new UnsupportedOperationException("Metadata not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIOMetadata getImageMetadata(int imageIndex) {
|
||||
throw new UnsupportedOperationException("Metadata not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
|
||||
return getImage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInput(Object input, boolean seekForwardOnly, boolean ignoreMetadata) {
|
||||
super.setInput(input, seekForwardOnly, ignoreMetadata);
|
||||
image = null;
|
||||
}
|
||||
|
||||
private BufferedImage getImage() throws IOException {
|
||||
if (image == null) {
|
||||
ImageInputStream in = (ImageInputStream) getInput();
|
||||
J2KFile jfile = new J2KFile();
|
||||
RandomAccessIO io;
|
||||
if (in.length() > 0) {
|
||||
io = new FixedJ2KRandomAccessIO(in);
|
||||
} else {
|
||||
io = new VariableJ2KRandomAccessIO(in);
|
||||
}
|
||||
jfile.read(io);
|
||||
J2KReader reader = new J2KReader(jfile);
|
||||
image = reader.getBufferedImage();
|
||||
reader.close();
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* AbstractRandomAccessIO that proxies to an unknown-length ImageInputStream,
|
||||
* which reads the source stream into memory
|
||||
*/
|
||||
private static class VariableJ2KRandomAccessIO extends AbstractRandomAccessIO {
|
||||
private byte[] buffer;
|
||||
private int pos;
|
||||
|
||||
VariableJ2KRandomAccessIO(ImageInputStream in) throws IOException {
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream(32768);
|
||||
byte[] buffer = new byte[32768];
|
||||
int len = 0;
|
||||
while (len >= 0) {
|
||||
len = in.read(buffer);
|
||||
if (len > 0) {
|
||||
bout.write(buffer, 0, len);
|
||||
}
|
||||
}
|
||||
this.buffer = bout.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
buffer = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPos() throws IOException {
|
||||
if (buffer == null) {
|
||||
throw new IOException("Closed");
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() throws IOException {
|
||||
if (buffer == null) {
|
||||
throw new IOException("Closed");
|
||||
}
|
||||
return buffer.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek(int off) throws IOException {
|
||||
// RandomAccessIO requires EOF if we seek beyond stream bounds; ImageInputStream does not
|
||||
if (buffer == null) {
|
||||
throw new IOException("Closed");
|
||||
}
|
||||
if (pos > buffer.length || pos < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
pos = off;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
// RandomAccessIO requires an EOFException rather than a -1 return value
|
||||
if (buffer == null) {
|
||||
throw new IOException("Closed");
|
||||
}
|
||||
if (pos >= buffer.length || pos < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return buffer[pos++] & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFully(byte[] b, int off, int len) throws IOException {
|
||||
if (buffer == null) {
|
||||
throw new IOException("Closed");
|
||||
} else if (len > buffer.length - pos) {
|
||||
throw new EOFException("Requested " + len + " but " + (buffer.length - pos) + " remaining");
|
||||
}
|
||||
System.arraycopy(buffer, pos, b, off, len);
|
||||
pos += len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* AbstractRandomAccessIO that proxies to a fixed-length ImageInputStream,
|
||||
* so doesn't have to read anything into memory
|
||||
*/
|
||||
private static class FixedJ2KRandomAccessIO extends AbstractRandomAccessIO {
|
||||
private final ImageInputStream in;
|
||||
private final long start;
|
||||
private boolean closed;
|
||||
|
||||
FixedJ2KRandomAccessIO(ImageInputStream in) throws IOException {
|
||||
this.in = in;
|
||||
this.start = in.getStreamPosition();
|
||||
if (in.length() - this.start > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException("Can't support stream of " + in.length() + " bytes");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
closed = true;
|
||||
// in.close(); No, don't proxy this.
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPos() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Closed");
|
||||
}
|
||||
return (int) (in.getStreamPosition() - start);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Closed");
|
||||
}
|
||||
return (int) (in.length() - start);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void seek(int off) throws IOException {
|
||||
// RandomAccessIO requires EOF if we seek beyond stream bounds; ImageInputStream does not
|
||||
if (closed) {
|
||||
throw new IOException("Closed");
|
||||
}
|
||||
if (off < 0 || off > length()) {
|
||||
throw new EOFException("off=" + off + " len=" + length());
|
||||
}
|
||||
in.seek(start + off);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Closed");
|
||||
}
|
||||
int v = in.read();
|
||||
if (v < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFully(byte[] b, int off, int len) throws IOException {
|
||||
if (closed) {
|
||||
throw new IOException("Closed");
|
||||
}
|
||||
in.readFully(b, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package org.xbib.graphics.jpeg2000.imageio;
|
||||
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Checks for JPEG2000 and creates the nessesary Reader.
|
||||
*/
|
||||
public class JPEG2000ReaderSpi extends ImageReaderSpi {
|
||||
private static final byte[] magicNumber = new byte[]
|
||||
{
|
||||
0, 0, 0, 12, 106, 80
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean canDecodeInput(Object source) throws IOException {
|
||||
if (source instanceof ImageInputStream in) {
|
||||
in.mark();
|
||||
byte[] magicNumber = new byte[6];
|
||||
in.readFully(magicNumber);
|
||||
in.reset();
|
||||
return Arrays.equals(JPEG2000ReaderSpi.magicNumber, magicNumber);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class[] getInputTypes() {
|
||||
return new Class[]{ImageInputStream.class};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageReader createReaderInstance(Object extension) throws IOException {
|
||||
return new JPEG2000Reader(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getFormatNames() {
|
||||
return new String[]{"jpeg2000", "JPEG2000"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getFileSuffixes() {
|
||||
return new String[]{"jp2", "j2k"};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription(Locale locale) {
|
||||
return "JPEG2000 ImageIO Support";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,346 @@
|
|||
/**
|
||||
* $RCSfile: IntegerSpec.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:01:58 $
|
||||
* $State: Exp $
|
||||
* <p>
|
||||
* Class: IntegerSpec
|
||||
* <p>
|
||||
* Description: Holds specs corresponding to an Integer
|
||||
* <p>
|
||||
* <p>
|
||||
* <p>
|
||||
* COPYRIGHT:
|
||||
* <p>
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
* <p>
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*/
|
||||
package org.xbib.graphics.jpeg2000.j2k;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.J2KWriteParam;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* This class extends ModuleSpec and is responsible of Integer
|
||||
* specifications for each tile-component.
|
||||
*
|
||||
* @see ModuleSpec
|
||||
* */
|
||||
public class IntegerSpec extends ModuleSpec {
|
||||
|
||||
|
||||
/** The largest value of type int */
|
||||
protected static int MAX_INT = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Constructs a new 'IntegerSpec' for the specified number of
|
||||
* tiles and components and with allowed type of
|
||||
* specifications. This constructor is normally called at decoder
|
||||
* side.
|
||||
*
|
||||
* @param nt The number of tiles
|
||||
*
|
||||
* @param nc The number of components
|
||||
*
|
||||
* @param type The type of allowed specifications
|
||||
*
|
||||
**/
|
||||
public IntegerSpec(int nt, int nc, byte type) {
|
||||
super(nt, nc, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new 'IntegerSpec' for the specified number of
|
||||
* tiles and components, the allowed specifications type
|
||||
* instance. This constructor is normally called at
|
||||
* encoder side and parse arguments of specified option.
|
||||
*
|
||||
* @param nt The number of tiles
|
||||
*
|
||||
* @param nc The number of components
|
||||
*
|
||||
* @param type The allowed specifications type
|
||||
**/
|
||||
public IntegerSpec(int nt, int nc, byte type, J2KWriteParam wp, String values,
|
||||
String defaultValue) {
|
||||
super(nt, nc, type);
|
||||
|
||||
if (values == null) { // No parameter specified
|
||||
try {
|
||||
setDefault(Integer.valueOf(defaultValue));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Non recognized value" +
|
||||
" for option -" +
|
||||
": " + defaultValue);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Integer value;
|
||||
|
||||
// Parse argument
|
||||
StringTokenizer stk = new StringTokenizer(values);
|
||||
String word; // current word
|
||||
byte curSpecType = SPEC_DEF; // Specification type of the
|
||||
// current parameter
|
||||
boolean[] tileSpec = null; // Tiles concerned by the specification
|
||||
boolean[] compSpec = null; // Components concerned by the specification
|
||||
|
||||
while (stk.hasMoreTokens()) {
|
||||
word = stk.nextToken();
|
||||
|
||||
switch (word.charAt(0)) {
|
||||
case 't': // Tiles specification
|
||||
tileSpec = parseIdx(word, nTiles);
|
||||
if (curSpecType == SPEC_COMP_DEF)
|
||||
curSpecType = SPEC_TILE_COMP;
|
||||
else
|
||||
curSpecType = SPEC_TILE_DEF;
|
||||
break;
|
||||
case 'c': // Components specification
|
||||
compSpec = parseIdx(word, nComp);
|
||||
if (curSpecType == SPEC_TILE_DEF)
|
||||
curSpecType = SPEC_TILE_COMP;
|
||||
else
|
||||
curSpecType = SPEC_COMP_DEF;
|
||||
break;
|
||||
default:
|
||||
try {
|
||||
value = Integer.valueOf(word);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Non recognized value" +
|
||||
" for option -: " + word);
|
||||
}
|
||||
|
||||
if (curSpecType == SPEC_DEF) {
|
||||
setDefault(value);
|
||||
} else if (curSpecType == SPEC_TILE_DEF) {
|
||||
for (int i = tileSpec.length - 1; i >= 0; i--)
|
||||
if (tileSpec[i]) {
|
||||
setTileDef(i, value);
|
||||
}
|
||||
} else if (curSpecType == SPEC_COMP_DEF) {
|
||||
for (int i = compSpec.length - 1; i >= 0; i--)
|
||||
if (compSpec[i]) {
|
||||
setCompDef(i, value);
|
||||
}
|
||||
} else {
|
||||
for (int i = tileSpec.length - 1; i >= 0; i--) {
|
||||
for (int j = compSpec.length - 1; j >= 0; j--) {
|
||||
if (tileSpec[i] && compSpec[j]) {
|
||||
setTileCompVal(i, j, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-initialize
|
||||
curSpecType = SPEC_DEF;
|
||||
tileSpec = null;
|
||||
compSpec = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that default value has been specified
|
||||
if (getDefault() == null) {
|
||||
int ndefspec = 0;
|
||||
for (int t = nt - 1; t >= 0; t--) {
|
||||
for (int c = nc - 1; c >= 0; c--) {
|
||||
if (specValType[t][c] == SPEC_DEF) {
|
||||
ndefspec++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If some tile-component have received no specification, it takes
|
||||
// the default value
|
||||
if (ndefspec != 0) {
|
||||
try {
|
||||
setDefault(Integer.valueOf(defaultValue));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("Non recognized value" +
|
||||
" for option - : " + defaultValue);
|
||||
}
|
||||
} else {
|
||||
// All tile-component have been specified, takes the first
|
||||
// tile-component value as default.
|
||||
setDefault(getTileCompVal(0, 0));
|
||||
switch (specValType[0][0]) {
|
||||
case SPEC_TILE_DEF:
|
||||
for (int c = nc - 1; c >= 0; c--) {
|
||||
if (specValType[0][c] == SPEC_TILE_DEF)
|
||||
specValType[0][c] = SPEC_DEF;
|
||||
}
|
||||
tileDef[0] = null;
|
||||
break;
|
||||
case SPEC_COMP_DEF:
|
||||
for (int t = nt - 1; t >= 0; t--) {
|
||||
if (specValType[t][0] == SPEC_COMP_DEF)
|
||||
specValType[t][0] = SPEC_DEF;
|
||||
}
|
||||
compDef[0] = null;
|
||||
break;
|
||||
case SPEC_TILE_COMP:
|
||||
specValType[0][0] = SPEC_DEF;
|
||||
tileCompVal.put("t0c0", null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum value of each tile-component
|
||||
*
|
||||
* @return The maximum value
|
||||
*
|
||||
*/
|
||||
public int getMax() {
|
||||
int max = ((Integer) def).intValue();
|
||||
int tmp;
|
||||
|
||||
for (int t = 0; t < nTiles; t++) {
|
||||
for (int c = 0; c < nComp; c++) {
|
||||
tmp = ((Integer) getSpec(t, c)).intValue();
|
||||
if (max < tmp)
|
||||
max = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum value of each tile-component
|
||||
*
|
||||
* @return The minimum value
|
||||
*
|
||||
*/
|
||||
public int getMin() {
|
||||
int min = ((Integer) def).intValue();
|
||||
int tmp;
|
||||
|
||||
for (int t = 0; t < nTiles; t++) {
|
||||
for (int c = 0; c < nComp; c++) {
|
||||
tmp = ((Integer) getSpec(t, c)).intValue();
|
||||
if (min > tmp)
|
||||
min = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum value of each tile for specified component
|
||||
*
|
||||
* @param c The component index
|
||||
*
|
||||
* @return The maximum value
|
||||
*
|
||||
*/
|
||||
public int getMaxInComp(int c) {
|
||||
int max = 0;
|
||||
int tmp;
|
||||
|
||||
for (int t = 0; t < nTiles; t++) {
|
||||
tmp = ((Integer) getSpec(t, c)).intValue();
|
||||
if (max < tmp)
|
||||
max = tmp;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum value of each tile for specified component
|
||||
*
|
||||
* @param c The component index
|
||||
*
|
||||
* @return The minimum value
|
||||
*
|
||||
*/
|
||||
public int getMinInComp(int c) {
|
||||
int min = MAX_INT; // Big value
|
||||
int tmp;
|
||||
|
||||
for (int t = 0; t < nTiles; t++) {
|
||||
tmp = ((Integer) getSpec(t, c)).intValue();
|
||||
if (min > tmp)
|
||||
min = tmp;
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum value of each component in specified tile
|
||||
*
|
||||
* @param t The tile index
|
||||
*
|
||||
* @return The maximum value
|
||||
*
|
||||
*/
|
||||
public int getMaxInTile(int t) {
|
||||
int max = 0;
|
||||
int tmp;
|
||||
|
||||
for (int c = 0; c < nComp; c++) {
|
||||
tmp = ((Integer) getSpec(t, c)).intValue();
|
||||
if (max < tmp)
|
||||
max = tmp;
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the minimum value of each component in specified tile
|
||||
*
|
||||
* @param t The tile index
|
||||
*
|
||||
* @return The minimum value
|
||||
*
|
||||
*/
|
||||
public int getMinInTile(int t) {
|
||||
int min = MAX_INT; // Big value
|
||||
int tmp;
|
||||
|
||||
for (int c = 0; c < nComp; c++) {
|
||||
tmp = ((Integer) getSpec(t, c)).intValue();
|
||||
if (min > tmp)
|
||||
min = tmp;
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* $RCSfile: JJ2KExceptionHandler.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:01:58 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: JJ2KExceptionHandler
|
||||
*
|
||||
* Description: A class to handle exceptions
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k;
|
||||
|
||||
/**
|
||||
* This class handles exceptions. It should be used in places where it
|
||||
* is not known how to handle the exception, and the exception can not
|
||||
* be thrown higher in the stack.
|
||||
*
|
||||
* <P>Different options can be registered for each Thread and
|
||||
* ThreadGroup. <i>This feature is not implemented yet</i>
|
||||
*/
|
||||
public class JJ2KExceptionHandler {
|
||||
|
||||
/**
|
||||
* Handles the exception. If no special action is registered for
|
||||
* the current thread, then the Exception's stack trace and a
|
||||
* descriptive message are printed to standard error and the
|
||||
* current thread is stopped.
|
||||
*
|
||||
* <P><i>Registration of special actions is not implemented yet.</i>
|
||||
*
|
||||
* @param e The exception to handle
|
||||
*/
|
||||
public static void handleException(Throwable e) {
|
||||
// Test if there is an special action (not implemented yet)
|
||||
|
||||
// If no special action
|
||||
|
||||
// Print the Exception message and stack to standard error
|
||||
// including this method in the stack.
|
||||
e.fillInStackTrace();
|
||||
e.printStackTrace();
|
||||
// Print an explicative message
|
||||
System.err.println("The Thread is being terminated bacause an " +
|
||||
"Exception (shown above)\n" +
|
||||
"has been thrown and no special action was " +
|
||||
"defined for this Thread.");
|
||||
// Stop the thread (do not use stop, since it's deprecated in
|
||||
// Java 1.2)
|
||||
throw new ThreadDeath();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* $RCSfile: JJ2KInfo.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:01:58 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: JJ2KInfo
|
||||
*
|
||||
* Description: Holds general JJ2000 informartion (version,
|
||||
* copyright, etc.)
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k;
|
||||
|
||||
/**
|
||||
* This class holds general JJ2000 information, such as the version number,
|
||||
* copyright, contact address, etc.
|
||||
*/
|
||||
public class JJ2KInfo {
|
||||
|
||||
/**
|
||||
* The version number (such as 2.0, 2.1.1, etc.)
|
||||
*/
|
||||
public static final String version = "4.1";
|
||||
|
||||
/**
|
||||
* The copyright message string. Double newlines separate paragraphs.
|
||||
* Newlines should be respected when displaying the message.
|
||||
*/
|
||||
public static final String copyright =
|
||||
"This software module was originally developed by Raphaël Grosbois " +
|
||||
"and Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); " +
|
||||
"Joel Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, " +
|
||||
"David Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon" +
|
||||
" Research Centre " +
|
||||
"France S.A) in the course of development of the JPEG 2000 standard " +
|
||||
"as " +
|
||||
"specified by ISO/IEC 15444 (JPEG 2000 Standard). This software " +
|
||||
"module is an implementation of a part of the JPEG 2000 Standard. " +
|
||||
"Swiss Federal Institute of Technology-EPFL, Ericsson Radio Systems " +
|
||||
"AB and Canon Research Centre France S.A (collectively JJ2000 " +
|
||||
"Partners) agree not to assert against ISO/IEC and users of the JPEG " +
|
||||
"2000 Standard (Users) any of their rights under the copyright, not " +
|
||||
"including other intellectual property rights, for this software " +
|
||||
"module with respect to the usage by ISO/IEC and Users of this " +
|
||||
"software module or modifications thereof for use in hardware or " +
|
||||
"software products claiming conformance to the JPEG 2000 Standard. " +
|
||||
"Those intending to use this software module in hardware or software " +
|
||||
"products are advised that their use may infringe existing patents. " +
|
||||
"The original developers of this software module, JJ2000 Partners " +
|
||||
"and " +
|
||||
"ISO/IEC assume no liability for use of this software module or " +
|
||||
"modifications thereof. No license or right to this software module " +
|
||||
"is granted for non JPEG 2000 Standard conforming products. JJ2000 " +
|
||||
"Partners have full right to use this software module for his/her " +
|
||||
"own purpose, assign or donate this software module to any third " +
|
||||
"party and to inhibit third parties from using this software module " +
|
||||
"for non JPEG 2000 Standard conforming products. This copyright " +
|
||||
"notice must be included in all copies or derivative works of this " +
|
||||
"software module.\n\nCopyright (c) 1999/2000 JJ2000 Partners.";
|
||||
|
||||
/**
|
||||
* The bug reporting e-mail address
|
||||
*/
|
||||
public final static String bugaddr = "jj2000-bugs@ltssg3.epfl.ch";
|
||||
}
|
|
@ -0,0 +1,637 @@
|
|||
/*
|
||||
* $RCSfile: ModuleSpec.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:01:58 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: ModuleSpec
|
||||
*
|
||||
* Description: Generic class for storing module specs
|
||||
*
|
||||
* from WTFilterSpec (Diego Santa Cruz)
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* This generic class is used to handle values to be used by a module for each
|
||||
* tile and component. It uses attribute to determine which value to use. It
|
||||
* should be extended by each module needing this feature.
|
||||
* <p>
|
||||
* This class might be used for values that are only tile specific or
|
||||
* component specific but not both.
|
||||
*
|
||||
* <P>The attributes to use are defined by a hierarchy. The hierarchy is:
|
||||
*
|
||||
* <ul>
|
||||
* <li> Tile and component specific attribute</li>
|
||||
* <li> Tile specific default attribute</li>
|
||||
* <li> Component main default attribute</li>
|
||||
* <li> Main default attribute</li>
|
||||
* </ul>
|
||||
*/
|
||||
|
||||
public class ModuleSpec implements Cloneable {
|
||||
|
||||
/**
|
||||
* The identifier for a specification module that applies only to
|
||||
* components
|
||||
*/
|
||||
public final static byte SPEC_TYPE_COMP = 0;
|
||||
|
||||
/**
|
||||
* The identifier for a specification module that applies only to
|
||||
* tiles
|
||||
*/
|
||||
public final static byte SPEC_TYPE_TILE = 1;
|
||||
|
||||
/**
|
||||
* The identifier for a specification module that applies both to
|
||||
* tiles and components
|
||||
*/
|
||||
public final static byte SPEC_TYPE_TILE_COMP = 2;
|
||||
|
||||
/**
|
||||
* The identifier for default specification
|
||||
*/
|
||||
public final static byte SPEC_DEF = 0;
|
||||
|
||||
/**
|
||||
* The identifier for "component default" specification
|
||||
*/
|
||||
public final static byte SPEC_COMP_DEF = 1;
|
||||
|
||||
/**
|
||||
* The identifier for "tile default" specification
|
||||
*/
|
||||
public final static byte SPEC_TILE_DEF = 2;
|
||||
|
||||
/**
|
||||
* The identifier for a "tile-component" specification
|
||||
*/
|
||||
public final static byte SPEC_TILE_COMP = 3;
|
||||
|
||||
/**
|
||||
* The type of the specification module
|
||||
*/
|
||||
protected int specType;
|
||||
|
||||
/**
|
||||
* The number of tiles
|
||||
*/
|
||||
protected int nTiles = 0;
|
||||
|
||||
/**
|
||||
* The number of components
|
||||
*/
|
||||
protected int nComp = 0;
|
||||
|
||||
/**
|
||||
* The spec type for each tile-component. The first index is
|
||||
* the tile index, the second is the component index.
|
||||
*/
|
||||
protected byte[][] specValType;
|
||||
|
||||
/**
|
||||
* Default value for each tile-component
|
||||
*/
|
||||
protected Object def = null;
|
||||
|
||||
/**
|
||||
* The default value for each component. Null if no component
|
||||
* specific value is defined
|
||||
*/
|
||||
protected Object[] compDef = null;
|
||||
|
||||
/**
|
||||
* The default value for each tile. Null if no tile specific
|
||||
* value is defined
|
||||
*/
|
||||
protected Object[] tileDef = null;
|
||||
|
||||
/**
|
||||
* The specific value for each tile-component. Value of tile 16 component
|
||||
* 3 is accessible through the hash value "t16c3". Null if no
|
||||
* tile-component specific value is defined
|
||||
*/
|
||||
protected Hashtable tileCompVal;
|
||||
|
||||
/**
|
||||
* The specified value in string format
|
||||
*/
|
||||
protected String specified;
|
||||
|
||||
/**
|
||||
* Constructs a 'ModuleSpec' object, initializing all the components and
|
||||
* tiles to the 'SPEC_DEF' spec val type, for the specified number of
|
||||
* components and tiles.
|
||||
*
|
||||
* @param nt The number of tiles
|
||||
* @param nc The number of components
|
||||
* @param type the type of the specification module i.e. tile specific,
|
||||
* component specific or both.
|
||||
*/
|
||||
public ModuleSpec(int nt, int nc, byte type) {
|
||||
|
||||
nTiles = nt;
|
||||
nComp = nc;
|
||||
specValType = new byte[nt][nc];
|
||||
switch (type) {
|
||||
case SPEC_TYPE_TILE:
|
||||
specType = SPEC_TYPE_TILE;
|
||||
break;
|
||||
case SPEC_TYPE_COMP:
|
||||
specType = SPEC_TYPE_COMP;
|
||||
break;
|
||||
case SPEC_TYPE_TILE_COMP:
|
||||
specType = SPEC_TYPE_TILE_COMP;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is responsible of parsing tile indexes set and
|
||||
* component indexes set for an option. Such an argument must
|
||||
* follow the following policy:<br>
|
||||
*
|
||||
* <tt>t<indexes set></tt> or <tt>c<indexes set></tt> where
|
||||
* tile or component indexes are separated by commas or a
|
||||
* dashes.
|
||||
*
|
||||
* <p><u>Example:</u><br>
|
||||
* <li> <tt>t0,3,4</tt> means tiles with indexes 0, 3 and 4.<br>
|
||||
* <li> <tt>t2-4</tt> means tiles with indexes 2,3 and 4.<br>
|
||||
* <p>
|
||||
* It returns a boolean array skteching which tile or component are
|
||||
* concerned by the next parameters.
|
||||
*
|
||||
* @param word The word to parse.
|
||||
* @param maxIdx Maximum authorized index
|
||||
* @return Indexes concerned by this parameter.
|
||||
*/
|
||||
public static final boolean[] parseIdx(String word, int maxIdx) {
|
||||
int nChar = word.length(); // Number of characters
|
||||
char c = word.charAt(0); // current character
|
||||
int idx = -1; // Current (tile or component) index
|
||||
int lastIdx = -1; // Last (tile or component) index
|
||||
boolean isDash = false; // Whether or not last separator was a dash
|
||||
|
||||
boolean[] idxSet = new boolean[maxIdx];
|
||||
int i = 1; // index of the current character
|
||||
|
||||
while (i < nChar) {
|
||||
c = word.charAt(i);
|
||||
if (Character.isDigit(c)) {
|
||||
if (idx == -1)
|
||||
idx = 0;
|
||||
idx = idx * 10 + (c - '0');
|
||||
} else {
|
||||
if (idx == -1 || (c != ',' && c != '-')) {
|
||||
throw new IllegalArgumentException("Bad construction for " +
|
||||
"parameter: " + word);
|
||||
}
|
||||
if (idx < 0 || idx >= maxIdx) {
|
||||
throw new IllegalArgumentException("Out of range index in " +
|
||||
"parameter `" + word + "' : " +
|
||||
+idx);
|
||||
}
|
||||
|
||||
// Found a comma
|
||||
if (c == ',') {
|
||||
if (isDash) { // Previously found a dash, fill idxSet
|
||||
for (int j = lastIdx + 1; j < idx; j++) {
|
||||
idxSet[j] = true;
|
||||
}
|
||||
}
|
||||
isDash = false;
|
||||
} else // Found a dash
|
||||
isDash = true;
|
||||
|
||||
// Udate idxSet
|
||||
idxSet[idx] = true;
|
||||
lastIdx = idx;
|
||||
idx = -1;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// Process last found index
|
||||
if (idx < 0 || idx >= maxIdx) {
|
||||
throw new IllegalArgumentException("Out of range index in " +
|
||||
"parameter `" + word + "' : " + idx);
|
||||
}
|
||||
if (isDash)
|
||||
for (int j = lastIdx + 1; j < idx; j++) {
|
||||
idxSet[j] = true;
|
||||
}
|
||||
idxSet[idx] = true;
|
||||
|
||||
return idxSet;
|
||||
}
|
||||
|
||||
public ModuleSpec getCopy() {
|
||||
return (ModuleSpec) this.clone();
|
||||
}
|
||||
|
||||
protected Object clone() {
|
||||
ModuleSpec ms;
|
||||
try {
|
||||
ms = (ModuleSpec) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new Error("Error when cloning ModuleSpec instance");
|
||||
}
|
||||
// Create a copy of the specValType array
|
||||
ms.specValType = new byte[nTiles][nComp];
|
||||
for (int t = 0; t < nTiles; t++) {
|
||||
System.arraycopy(specValType[t], 0, ms.specValType[t], 0, nComp);
|
||||
}
|
||||
// Create a copy of tileDef
|
||||
if (tileDef != null) {
|
||||
ms.tileDef = new Object[nTiles];
|
||||
System.arraycopy(tileDef, 0, ms.tileDef, 0, nTiles);
|
||||
}
|
||||
// Create a copy of tileCompVal
|
||||
if (tileCompVal != null) {
|
||||
ms.tileCompVal = new Hashtable();
|
||||
String tmpKey;
|
||||
Object tmpVal;
|
||||
for (Enumeration e = tileCompVal.keys(); e.hasMoreElements(); ) {
|
||||
tmpKey = (String) e.nextElement();
|
||||
tmpVal = tileCompVal.get(tmpKey);
|
||||
ms.tileCompVal.put(tmpKey, tmpVal);
|
||||
}
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotate the ModuleSpec instance by 90 degrees (this modifies only tile
|
||||
* and tile-component specifications).
|
||||
*
|
||||
* @param anT Number of tiles along horizontal and vertical axis after
|
||||
* rotation.
|
||||
*/
|
||||
public void rotate90(Point anT) {
|
||||
// Rotate specValType
|
||||
byte[][] tmpsvt = new byte[nTiles][];
|
||||
int ax, ay;
|
||||
Point bnT = new Point(anT.y, anT.x);
|
||||
for (int by = 0; by < bnT.y; by++) {
|
||||
for (int bx = 0; bx < bnT.x; bx++) {
|
||||
ay = bx;
|
||||
ax = bnT.y - by - 1;
|
||||
tmpsvt[ay * anT.x + ax] = specValType[by * bnT.x + bx];
|
||||
}
|
||||
}
|
||||
specValType = tmpsvt;
|
||||
|
||||
// Rotate tileDef
|
||||
if (tileDef != null) {
|
||||
Object[] tmptd = new Object[nTiles];
|
||||
for (int by = 0; by < bnT.y; by++) {
|
||||
for (int bx = 0; bx < bnT.x; bx++) {
|
||||
ay = bx;
|
||||
ax = bnT.y - by - 1;
|
||||
tmptd[ay * anT.x + ax] = tileDef[by * bnT.x + bx];
|
||||
}
|
||||
}
|
||||
tileDef = tmptd;
|
||||
}
|
||||
|
||||
// Rotate tileCompVal
|
||||
if (tileCompVal != null && tileCompVal.size() > 0) {
|
||||
Hashtable tmptcv = new Hashtable();
|
||||
String tmpKey;
|
||||
Object tmpVal;
|
||||
int btIdx, atIdx;
|
||||
int i1, i2;
|
||||
int bx, by;
|
||||
for (Enumeration e = tileCompVal.keys(); e.hasMoreElements(); ) {
|
||||
tmpKey = (String) e.nextElement();
|
||||
tmpVal = tileCompVal.get(tmpKey);
|
||||
i1 = tmpKey.indexOf('t');
|
||||
i2 = tmpKey.indexOf('c');
|
||||
btIdx = (Integer.valueOf(tmpKey.substring(i1 + 1, i2))).intValue();
|
||||
bx = btIdx % bnT.x;
|
||||
by = btIdx / bnT.x;
|
||||
ay = bx;
|
||||
ax = bnT.y - by - 1;
|
||||
atIdx = ax + ay * anT.x;
|
||||
tmptcv.put("t" + atIdx + tmpKey.substring(i2), tmpVal);
|
||||
}
|
||||
tileCompVal = tmptcv;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets default value for this module.
|
||||
*
|
||||
* @return The default value (Must be casted before use)
|
||||
*/
|
||||
public Object getDefault() {
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default value for this module
|
||||
*/
|
||||
public void setDefault(Object value) {
|
||||
def = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default value for specified component and specValType tag if
|
||||
* allowed by its priority.
|
||||
*
|
||||
* @param c Component index
|
||||
*/
|
||||
public void setCompDef(int c, Object value) {
|
||||
if (specType == SPEC_TYPE_TILE) {
|
||||
String errMsg = "Option whose value is '" + value + "' cannot be "
|
||||
+ "specified for components as it is a 'tile only' specific "
|
||||
+ "option";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
if (compDef == null)
|
||||
compDef = new Object[nComp];
|
||||
for (int i = 0; i < nTiles; i++) {
|
||||
if (specValType[i][c] < SPEC_COMP_DEF) {
|
||||
specValType[i][c] = SPEC_COMP_DEF;
|
||||
}
|
||||
}
|
||||
compDef[c] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets default value of the specified component. If no specification have
|
||||
* been entered for this component, returns default value.
|
||||
*
|
||||
* @param c Component index
|
||||
* @return The default value for this component (Must be casted before
|
||||
* use)
|
||||
* @see #setCompDef
|
||||
*/
|
||||
public Object getCompDef(int c) {
|
||||
if (specType == SPEC_TYPE_TILE) {
|
||||
throw new IllegalArgumentException("Illegal use of ModuleSpec class");
|
||||
}
|
||||
if (compDef == null || compDef[c] == null) {
|
||||
return getDefault();
|
||||
} else
|
||||
return compDef[c];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default value for specified tile and specValType tag if
|
||||
* allowed by its priority.
|
||||
*
|
||||
* @param t Tile index.
|
||||
*/
|
||||
public void setTileDef(int t, Object value) {
|
||||
if (specType == SPEC_TYPE_COMP) {
|
||||
String errMsg = "Option whose value is '" + value + "' cannot be "
|
||||
+ "specified for tiles as it is a 'component only' specific "
|
||||
+ "option";
|
||||
throw new IllegalStateException(errMsg);
|
||||
}
|
||||
if (tileDef == null)
|
||||
tileDef = new Object[nTiles];
|
||||
for (int i = 0; i < nComp; i++) {
|
||||
if (specValType[t][i] < SPEC_TILE_DEF) {
|
||||
specValType[t][i] = SPEC_TILE_DEF;
|
||||
}
|
||||
}
|
||||
tileDef[t] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets default value of the specified tile. If no specification
|
||||
* has been entered, it returns the default value.
|
||||
*
|
||||
* @param t Tile index
|
||||
* @return The default value for this tile (Must be casted before use)
|
||||
* @see #setTileDef
|
||||
*/
|
||||
public Object getTileDef(int t) {
|
||||
if (specType == SPEC_TYPE_COMP) {
|
||||
throw new IllegalStateException("Illegal use of ModuleSpec class");
|
||||
}
|
||||
if (tileDef == null || tileDef[t] == null) {
|
||||
return getDefault();
|
||||
} else
|
||||
return tileDef[t];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets value for specified tile-component.
|
||||
*
|
||||
* @param t Tie index
|
||||
* @param c Component index
|
||||
*/
|
||||
public void setTileCompVal(int t, int c, Object value) {
|
||||
if (specType != SPEC_TYPE_TILE_COMP) {
|
||||
String errMsg = "Option whose value is '" + value + "' cannot be "
|
||||
+ "specified for ";
|
||||
switch (specType) {
|
||||
case SPEC_TYPE_TILE:
|
||||
errMsg += "components as it is a 'tile only' specific option";
|
||||
break;
|
||||
case SPEC_TYPE_COMP:
|
||||
errMsg += "tiles as it is a 'component only' specific option";
|
||||
break;
|
||||
}
|
||||
throw new IllegalStateException(errMsg);
|
||||
}
|
||||
if (tileCompVal == null)
|
||||
tileCompVal = new Hashtable();
|
||||
specValType[t][c] = SPEC_TILE_COMP;
|
||||
tileCompVal.put("t" + t + "c" + c, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets value of specified tile-component. This method calls getSpec but
|
||||
* has a public access.
|
||||
*
|
||||
* @param t Tile index
|
||||
* @param c Component index
|
||||
* @return The value of this tile-component (Must be casted before use)
|
||||
* @see #setTileCompVal
|
||||
* @see #getSpec
|
||||
*/
|
||||
public Object getTileCompVal(int t, int c) {
|
||||
if (specType != SPEC_TYPE_TILE_COMP) {
|
||||
throw new IllegalStateException("Illegal use of ModuleSpec class");
|
||||
}
|
||||
return getSpec(t, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets value of specified tile-component without knowing if a
|
||||
* specific tile-component value has been previously entered. It
|
||||
* first check if a tile-component specific value has been
|
||||
* entered, then if a tile specific value exist, then if a
|
||||
* component specific value exist. If not the default value is
|
||||
* returned.
|
||||
*
|
||||
* @param t Tile index
|
||||
* @param c Component index
|
||||
* @return Value for this tile component.
|
||||
*/
|
||||
protected Object getSpec(int t, int c) {
|
||||
switch (specValType[t][c]) {
|
||||
case SPEC_DEF:
|
||||
return getDefault();
|
||||
case SPEC_COMP_DEF:
|
||||
return getCompDef(c);
|
||||
case SPEC_TILE_DEF:
|
||||
return getTileDef(t);
|
||||
case SPEC_TILE_COMP:
|
||||
return tileCompVal.get("t" + t + "c" + c);
|
||||
default:
|
||||
throw new IllegalArgumentException("Not recognized spec type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the spec type of the given tile-component.
|
||||
*
|
||||
* @param t Tile index
|
||||
* @param c Component index
|
||||
*/
|
||||
public byte getSpecValType(int t, int c) {
|
||||
return specValType[t][c];
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not specifications have been entered for the given
|
||||
* component.
|
||||
*
|
||||
* @param c Index of the component
|
||||
* @return True if component specification has been defined
|
||||
*/
|
||||
public boolean isCompSpecified(int c) {
|
||||
return compDef != null && compDef[c] != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not specifications have been entered for the given
|
||||
* tile.
|
||||
*
|
||||
* @param t Index of the tile
|
||||
* @return True if tile specification has been entered
|
||||
*/
|
||||
public boolean isTileSpecified(int t) {
|
||||
return tileDef != null && tileDef[t] != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not a tile-component specification has been defined
|
||||
*
|
||||
* @param t Tile index
|
||||
* @param c Component index
|
||||
* @return True if a tile-component specification has been defined.
|
||||
*/
|
||||
public boolean isTileCompSpecified(int t, int c) {
|
||||
return tileCompVal != null && tileCompVal.get("t" + t + "c" + c) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a tile-component representative using default value.
|
||||
*
|
||||
* @return Tile component index in an array (first element: tile
|
||||
* index, second element: component index).
|
||||
* */
|
||||
/*
|
||||
public int[] getDefRep(){
|
||||
int[] tcidx = new int[2];
|
||||
for(int t=nTiles-1; t>=0; t--){
|
||||
for(int c=nComp-1; c>=0; c--){
|
||||
if(specValType[t][c]==SPEC_DEF){
|
||||
tcidx[0] = t;
|
||||
tcidx[1] = c;
|
||||
return tcidx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("No representative for "+
|
||||
"default value");
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Returns a component representative using tile default value.
|
||||
*
|
||||
* @param t Tile index
|
||||
*
|
||||
* @return component index of the representant
|
||||
* */
|
||||
/*
|
||||
public int getTileDefRep(int t){
|
||||
for(int c=nComp-1; c>=0; c--)
|
||||
if(specValType[t][c]==SPEC_TILE_DEF){
|
||||
return c;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("No representative for tile "+
|
||||
"default value");
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* Returns a tile representative using component default value.
|
||||
*
|
||||
* @param c Component index
|
||||
*
|
||||
* @return tile index of the representant
|
||||
* */
|
||||
/*
|
||||
public int getCompDefRep(int c){
|
||||
for(int t=nTiles-1; t>=0; t--) {
|
||||
if(specValType[t][c]==SPEC_COMP_DEF){
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("No representative for component "+
|
||||
"default value, c="+c);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
public String getSpecified() {
|
||||
return specified;
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* $RCSfile: NoNextElementException.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:01:58 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: NoNextElementException
|
||||
*
|
||||
* Description: Exception to indicate that there is no next
|
||||
* element.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k;
|
||||
|
||||
/**
|
||||
* This exception is thrown whenever a next???? method is called and
|
||||
* there is no next element to return.
|
||||
*/
|
||||
public class NoNextElementException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Constructs a new <tt>NoNextElementException</tt> exception with no
|
||||
* detail message.
|
||||
*/
|
||||
public NoNextElementException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <tt>NoNextElementException</tt> exception with
|
||||
* the specified detail message.
|
||||
*
|
||||
* @param s The detail message.
|
||||
*/
|
||||
public NoNextElementException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* $RCSfile: NotImplementedError.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:01:59 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: NotImplementedError
|
||||
*
|
||||
* Description: Exception that is thrown whenever a non-implemented
|
||||
* method is called.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k;
|
||||
|
||||
/**
|
||||
* This exception is thrown whenever a feature or functionality that
|
||||
* has not been implemented is calle.
|
||||
*
|
||||
* <P>Its purpose it is to ease the development and testing process. A
|
||||
* class that partially implements its functionality should throw a
|
||||
* <tt>NotImplementedError</tt> when a method that has not yet
|
||||
* been implemented is called.
|
||||
*
|
||||
* <P>This class is made a subclass of <tt>Error</tt> since it should
|
||||
* never be caught by an application. There is no need to declare this
|
||||
* exception in the <tt>throws</tt> clause of a method.
|
||||
*
|
||||
* @see Error
|
||||
*/
|
||||
public class NotImplementedError extends Error {
|
||||
|
||||
/**
|
||||
* Constructs a new <tt>NotImplementedError</tt> exception with
|
||||
* the default detail message. The message is:
|
||||
*
|
||||
* <P><I>The called method has not been implemented yet. Sorry!</I>
|
||||
*/
|
||||
public NotImplementedError() {
|
||||
super("The called method has not been implemented yet. Sorry!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <tt>NotImplementedError</tt> exception with
|
||||
* the specified detail message <tt>m</tt>.
|
||||
*
|
||||
* @param m The detail message to use
|
||||
*/
|
||||
public NotImplementedError(String m) {
|
||||
super(m);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* $RCSfile: StringSpec.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:01:59 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: StringSpec
|
||||
*
|
||||
* Description: String specification for an option
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.J2KWriteParam;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* This class extends ModuleSpec class in order to hold tile-component
|
||||
* specifications using Strings.
|
||||
*
|
||||
* @see ModuleSpec
|
||||
*/
|
||||
public class StringSpec extends ModuleSpec {
|
||||
|
||||
private String specified;
|
||||
|
||||
/**
|
||||
* Constructs an empty 'StringSpec' with specified number of
|
||||
* tile and components. This constructor is called by the decoder.
|
||||
*
|
||||
* @param nt Number of tiles
|
||||
* @param nc Number of components
|
||||
* @param type the type of the specification module i.e. tile specific,
|
||||
* component specific or both.
|
||||
*/
|
||||
public StringSpec(int nt, int nc, byte type) {
|
||||
super(nt, nc, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new 'StringSpec' for the specified number of
|
||||
* components:tiles and the arguments of <tt>optName</tt>
|
||||
* option. This constructor is called by the encoder. It also
|
||||
* checks that the arguments belongs to the recognized arguments
|
||||
* list.
|
||||
*
|
||||
* <P><u>Note:</u> The arguments must not start with 't' or 'c'
|
||||
* since it is reserved for respectively tile and components
|
||||
* indexes specification.
|
||||
*
|
||||
* @param nt The number of tiles
|
||||
* @param nc The number of components
|
||||
* @param type the type of the specification module i.e. tile specific,
|
||||
* component specific or both.
|
||||
* @param list The list of all recognized argument in a String array
|
||||
*/
|
||||
public StringSpec(int nt, int nc, byte type, String defaultValue,
|
||||
String[] list, J2KWriteParam wp, String values) {
|
||||
super(nt, nc, type);
|
||||
specified = values;
|
||||
|
||||
boolean recognized = false;
|
||||
|
||||
String param = values;
|
||||
|
||||
if (values == null) {
|
||||
for (int i = list.length - 1; i >= 0; i--)
|
||||
if (defaultValue.equalsIgnoreCase(list[i])) {
|
||||
recognized = true;
|
||||
break;
|
||||
}
|
||||
if (!recognized)
|
||||
throw new IllegalArgumentException("Default parameter of " +
|
||||
"option - not" +
|
||||
" recognized: " + defaultValue);
|
||||
setDefault(defaultValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse argument
|
||||
StringTokenizer stk = new StringTokenizer(specified);
|
||||
String word; // current word
|
||||
byte curSpecType = SPEC_DEF; // Specification type of the
|
||||
// current parameter
|
||||
boolean[] tileSpec = null; // Tiles concerned by the
|
||||
// specification
|
||||
boolean[] compSpec = null; // Components concerned by the specification
|
||||
Boolean value;
|
||||
|
||||
while (stk.hasMoreTokens()) {
|
||||
word = stk.nextToken();
|
||||
|
||||
if (word.matches("t[0-9]*")) {
|
||||
tileSpec = parseIdx(word, nTiles);
|
||||
if (curSpecType == SPEC_COMP_DEF) {
|
||||
curSpecType = SPEC_TILE_COMP;
|
||||
} else {
|
||||
curSpecType = SPEC_TILE_DEF;
|
||||
}
|
||||
} else if (word.matches("c[0-9]*")) {
|
||||
compSpec = parseIdx(word, nComp);
|
||||
if (curSpecType == SPEC_TILE_DEF) {
|
||||
curSpecType = SPEC_TILE_COMP;
|
||||
} else
|
||||
curSpecType = SPEC_COMP_DEF;
|
||||
} else {
|
||||
recognized = false;
|
||||
|
||||
for (int i = list.length - 1; i >= 0; i--)
|
||||
if (word.equalsIgnoreCase(list[i])) {
|
||||
recognized = true;
|
||||
break;
|
||||
}
|
||||
if (!recognized)
|
||||
throw new IllegalArgumentException("Default parameter of " +
|
||||
"option not" +
|
||||
" recognized: " + word);
|
||||
|
||||
if (curSpecType == SPEC_DEF) {
|
||||
setDefault(word);
|
||||
} else if (curSpecType == SPEC_TILE_DEF) {
|
||||
for (int i = tileSpec.length - 1; i >= 0; i--)
|
||||
if (tileSpec[i]) {
|
||||
setTileDef(i, word);
|
||||
}
|
||||
} else if (curSpecType == SPEC_COMP_DEF) {
|
||||
for (int i = compSpec.length - 1; i >= 0; i--)
|
||||
if (compSpec[i]) {
|
||||
setCompDef(i, word);
|
||||
}
|
||||
} else {
|
||||
for (int i = tileSpec.length - 1; i >= 0; i--) {
|
||||
for (int j = compSpec.length - 1; j >= 0; j--) {
|
||||
if (tileSpec[i] && compSpec[j]) {
|
||||
setTileCompVal(i, j, word);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-initialize
|
||||
curSpecType = SPEC_DEF;
|
||||
tileSpec = null;
|
||||
compSpec = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that default value has been specified
|
||||
if (getDefault() == null) {
|
||||
int ndefspec = 0;
|
||||
for (int t = nt - 1; t >= 0; t--) {
|
||||
for (int c = nc - 1; c >= 0; c--) {
|
||||
if (specValType[t][c] == SPEC_DEF) {
|
||||
ndefspec++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If some tile-component have received no specification, it takes
|
||||
// the default value defined in ParameterList
|
||||
if (ndefspec != 0) {
|
||||
param = defaultValue;
|
||||
for (int i = list.length - 1; i >= 0; i--)
|
||||
if (param.equalsIgnoreCase(list[i])) {
|
||||
recognized = true;
|
||||
break;
|
||||
}
|
||||
if (!recognized)
|
||||
throw new IllegalArgumentException("Default parameter of " +
|
||||
"option not" +
|
||||
" recognized: " + specified);
|
||||
setDefault(param);
|
||||
} else {
|
||||
// All tile-component have been specified, takes the first
|
||||
// tile-component value as default.
|
||||
setDefault(getSpec(0, 0));
|
||||
switch (specValType[0][0]) {
|
||||
case SPEC_TILE_DEF:
|
||||
for (int c = nc - 1; c >= 0; c--) {
|
||||
if (specValType[0][c] == SPEC_TILE_DEF)
|
||||
specValType[0][c] = SPEC_DEF;
|
||||
}
|
||||
tileDef[0] = null;
|
||||
break;
|
||||
case SPEC_COMP_DEF:
|
||||
for (int t = nt - 1; t >= 0; t--) {
|
||||
if (specValType[t][0] == SPEC_COMP_DEF)
|
||||
specValType[t][0] = SPEC_DEF;
|
||||
}
|
||||
compDef[0] = null;
|
||||
break;
|
||||
case SPEC_TILE_COMP:
|
||||
specValType[0][0] = SPEC_DEF;
|
||||
tileCompVal.put("t0c0", null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getSpecified() {
|
||||
return specified;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* $RCSfile: CBlkCoordInfo.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:01:59 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: CBlkCoordInfo
|
||||
*
|
||||
* Description: Used to store the code-blocks coordinates.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* This class is used to store the coordinates of code-blocks.
|
||||
*/
|
||||
public class CBlkCoordInfo extends CoordInfo {
|
||||
|
||||
/**
|
||||
* The code-block horizontal and vertical indexes
|
||||
*/
|
||||
public Point idx;
|
||||
|
||||
/**
|
||||
* Constructor. Creates a CBlkCoordInfo object.
|
||||
*/
|
||||
public CBlkCoordInfo() {
|
||||
this.idx = new Point();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Creates a CBlkCoordInfo object width specified code-block
|
||||
* vertical and horizontal indexes.
|
||||
*
|
||||
* @param m Code-block vertical index.
|
||||
* @param n Code-block horizontal index.
|
||||
*/
|
||||
public CBlkCoordInfo(int m, int n) {
|
||||
this.idx = new Point(n, m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns code-block's information in a String
|
||||
*
|
||||
* @return String with code-block's information
|
||||
*/
|
||||
public String toString() {
|
||||
return super.toString() + ", idx=" + idx;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* $RCSfile: CoordInfo.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:01:59 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: CoordInfo
|
||||
*
|
||||
* Description: Used to store the coordinates of code-blocks/packets
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream;
|
||||
|
||||
/**
|
||||
* This class is used to store the coordinates of objects such as code-blocks
|
||||
* or precincts. As this is an abstract class, it cannot be used directly but
|
||||
* derived classes have been created for code-blocks and packets
|
||||
* (CBlkCoordInfo and PrecCoordInfo).
|
||||
*
|
||||
* @see PrecCoordInfo
|
||||
* @see CBlkCoordInfo
|
||||
*/
|
||||
public abstract class CoordInfo {
|
||||
|
||||
/**
|
||||
* Horizontal upper left coordinate in the subband
|
||||
*/
|
||||
public int ulx;
|
||||
|
||||
/**
|
||||
* Vertical upper left coordinate in the subband
|
||||
*/
|
||||
public int uly;
|
||||
|
||||
/**
|
||||
* Object's width
|
||||
*/
|
||||
public int w;
|
||||
|
||||
/**
|
||||
* Object's height
|
||||
*/
|
||||
public int h;
|
||||
|
||||
/**
|
||||
* Constructor. Creates a CoordInfo object.
|
||||
*
|
||||
* @param ulx The horizontal upper left coordinate in the subband
|
||||
* @param uly The vertical upper left coordinate in the subband
|
||||
* @param w The width
|
||||
* @param h The height
|
||||
*/
|
||||
public CoordInfo(int ulx, int uly, int w, int h) {
|
||||
this.ulx = ulx;
|
||||
this.uly = uly;
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty contructor
|
||||
*/
|
||||
public CoordInfo() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns object's information in a String
|
||||
*
|
||||
* @return String with object's information
|
||||
*/
|
||||
public String toString() {
|
||||
return "ulx=" + ulx + ", uly=" + uly + ", w=" + w + ", h=" + h;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* $RCSfile: CorruptedCodestreamException.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:01:59 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: CorruptedCodestreamException
|
||||
*
|
||||
* Description: Exception thrown when illegal bit stream
|
||||
* values are decoded.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Thsi exception is thrown whenever an illegal value is read from a
|
||||
* bit stream. The cause can be either a corrupted bit stream, or a a
|
||||
* bit stream which is illegal.
|
||||
*/
|
||||
public class CorruptedCodestreamException extends IOException {
|
||||
|
||||
/**
|
||||
* Constructs a new <tt>CorruptedCodestreamException</tt> exception
|
||||
* with no detail message.
|
||||
*/
|
||||
public CorruptedCodestreamException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new <tt>CorruptedCodestreamException</tt> exception
|
||||
* with the specified detail message.
|
||||
*
|
||||
* @param s The detail message.
|
||||
*/
|
||||
public CorruptedCodestreamException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,997 @@
|
|||
/*
|
||||
* $RCSfile: HeaderInfo.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:00 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: HeaderInfo
|
||||
*
|
||||
* Description: Holds information found in main and tile-part
|
||||
* headers
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.FilterTypes;
|
||||
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* Classe that holds information found in the marker segments of the main and
|
||||
* tile-part headers. There is one inner-class per marker segment type found
|
||||
* in these headers.
|
||||
*/
|
||||
public class HeaderInfo implements Markers, ProgressionType, FilterTypes,
|
||||
Cloneable {
|
||||
|
||||
/**
|
||||
* Reference to the SIZ marker segment found in main header
|
||||
*/
|
||||
public SIZ siz;
|
||||
/**
|
||||
* Reference to the SOT marker segments found in tile-part headers. The
|
||||
* kwy is given by "t"+tileIdx"_tp"+tilepartIndex.
|
||||
*/
|
||||
public Hashtable sot = new Hashtable();
|
||||
/**
|
||||
* Reference to the COD marker segments found in main and first tile-part
|
||||
* header. The key is either "main" or "t"+tileIdx.
|
||||
*/
|
||||
public Hashtable cod = new Hashtable();
|
||||
/**
|
||||
* Reference to the COC marker segments found in main and first tile-part
|
||||
* header. The key is either "main_c"+componentIndex or
|
||||
* "t"+tileIdx+"_c"+component_index.
|
||||
*/
|
||||
public Hashtable coc = new Hashtable();
|
||||
/**
|
||||
* Reference to the RGN marker segments found in main and first tile-part
|
||||
* header. The key is either "main_c"+componentIndex or
|
||||
* "t"+tileIdx+"_c"+component_index.
|
||||
*/
|
||||
public Hashtable rgn = new Hashtable();
|
||||
/**
|
||||
* Reference to the QCD marker segments found in main and first tile-part
|
||||
* header. The key is either "main" or "t"+tileIdx.
|
||||
*/
|
||||
public Hashtable qcd = new Hashtable();
|
||||
/**
|
||||
* Reference to the QCC marker segments found in main and first tile-part
|
||||
* header. They key is either "main_c"+componentIndex or
|
||||
* "t"+tileIdx+"_c"+component_index.
|
||||
*/
|
||||
public Hashtable qcc = new Hashtable();
|
||||
/**
|
||||
* Reference to the POC marker segments found in main and first tile-part
|
||||
* header. They key is either "main" or "t"+tileIdx.
|
||||
*/
|
||||
public Hashtable poc = new Hashtable();
|
||||
/**
|
||||
* Reference to the CRG marker segment found in main header
|
||||
*/
|
||||
public CRG crg;
|
||||
/**
|
||||
* Reference to the COM marker segments found in main and tile-part
|
||||
* headers. The key is either "main_"+comIdx or "t"+tileIdx+"_"+comIdx.
|
||||
*/
|
||||
public Hashtable com = new Hashtable();
|
||||
/**
|
||||
* Number of found COM marker segment
|
||||
*/
|
||||
private int ncom = 0;
|
||||
|
||||
/**
|
||||
* Returns a new instance of SIZ
|
||||
*/
|
||||
public SIZ getNewSIZ() {
|
||||
return new SIZ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of SOT
|
||||
*/
|
||||
public SOT getNewSOT() {
|
||||
return new SOT();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of COD
|
||||
*/
|
||||
public COD getNewCOD() {
|
||||
return new COD();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of COC
|
||||
*/
|
||||
public COC getNewCOC() {
|
||||
return new COC();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of RGN
|
||||
*/
|
||||
public RGN getNewRGN() {
|
||||
return new RGN();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of QCD
|
||||
*/
|
||||
public QCD getNewQCD() {
|
||||
return new QCD();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of QCC
|
||||
*/
|
||||
public QCC getNewQCC() {
|
||||
return new QCC();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of POC
|
||||
*/
|
||||
public POC getNewPOC() {
|
||||
return new POC();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of CRG
|
||||
*/
|
||||
public CRG getNewCRG() {
|
||||
return new CRG();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of COM
|
||||
*/
|
||||
public COM getNewCOM() {
|
||||
ncom++;
|
||||
return new COM();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of found COM marker segments
|
||||
*/
|
||||
public int getNumCOM() {
|
||||
return ncom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display information found in the different marker segments of the main
|
||||
* header
|
||||
*/
|
||||
public String toStringMainHeader() {
|
||||
int nc = siz.csiz;
|
||||
// SIZ
|
||||
String str = "" + siz;
|
||||
// COD
|
||||
if (cod.get("main") != null) {
|
||||
str += "" + cod.get("main");
|
||||
}
|
||||
// COCs
|
||||
for (int c = 0; c < nc; c++) {
|
||||
if (coc.get("main_c" + c) != null) {
|
||||
str += "" + coc.get("main_c" + c);
|
||||
}
|
||||
}
|
||||
// QCD
|
||||
if (qcd.get("main") != null) {
|
||||
str += "" + qcd.get("main");
|
||||
}
|
||||
// QCCs
|
||||
for (int c = 0; c < nc; c++) {
|
||||
if (qcc.get("main_c" + c) != null) {
|
||||
str += "" + qcc.get("main_c" + c);
|
||||
}
|
||||
}
|
||||
// RGN
|
||||
for (int c = 0; c < nc; c++) {
|
||||
if (rgn.get("main_c" + c) != null) {
|
||||
str += "" + rgn.get("main_c" + c);
|
||||
}
|
||||
}
|
||||
// POC
|
||||
if (poc.get("main") != null) {
|
||||
str += "" + poc.get("main");
|
||||
}
|
||||
// CRG
|
||||
if (crg != null) {
|
||||
str += "" + crg;
|
||||
}
|
||||
// COM
|
||||
for (int i = 0; i < ncom; i++) {
|
||||
if (com.get("main_" + i) != null) {
|
||||
str += "" + com.get("main_" + i);
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information found in the tile-part headers of a given tile.
|
||||
*
|
||||
* @param t index of the tile
|
||||
* @param ntp Number of tile-parts
|
||||
*/
|
||||
public String toStringTileHeader(int t, int ntp) {
|
||||
int nc = siz.csiz;
|
||||
String str = "";
|
||||
// SOT
|
||||
for (int i = 0; i < ntp; i++) {
|
||||
str += "Tile-part " + i + ", tile " + t + ":\n";
|
||||
str += "" + sot.get("t" + t + "_tp" + i);
|
||||
}
|
||||
// COD
|
||||
if (cod.get("t" + t) != null) {
|
||||
str += "" + cod.get("t" + t);
|
||||
}
|
||||
// COCs
|
||||
for (int c = 0; c < nc; c++) {
|
||||
if (coc.get("t" + t + "_c" + c) != null) {
|
||||
str += "" + coc.get("t" + t + "_c" + c);
|
||||
}
|
||||
}
|
||||
// QCD
|
||||
if (qcd.get("t" + t) != null) {
|
||||
str += "" + qcd.get("t" + t);
|
||||
}
|
||||
// QCCs
|
||||
for (int c = 0; c < nc; c++) {
|
||||
if (qcc.get("t" + t + "_c" + c) != null) {
|
||||
str += "" + qcc.get("t" + t + "_c" + c);
|
||||
}
|
||||
}
|
||||
// RGN
|
||||
for (int c = 0; c < nc; c++) {
|
||||
if (rgn.get("t" + t + "_c" + c) != null) {
|
||||
str += "" + rgn.get("t" + t + "_c" + c);
|
||||
}
|
||||
}
|
||||
// POC
|
||||
if (poc.get("t" + t) != null) {
|
||||
str += "" + poc.get("t" + t);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information found in the tile-part headers of a given tile
|
||||
* exception the SOT marker segment.
|
||||
*
|
||||
* @param t index of the tile
|
||||
* @param ntp Number of tile-parts
|
||||
*/
|
||||
public String toStringThNoSOT(int t, int ntp) {
|
||||
int nc = siz.csiz;
|
||||
String str = "";
|
||||
// COD
|
||||
if (cod.get("t" + t) != null) {
|
||||
str += "" + cod.get("t" + t);
|
||||
}
|
||||
// COCs
|
||||
for (int c = 0; c < nc; c++) {
|
||||
if (coc.get("t" + t + "_c" + c) != null) {
|
||||
str += "" + coc.get("t" + t + "_c" + c);
|
||||
}
|
||||
}
|
||||
// QCD
|
||||
if (qcd.get("t" + t) != null) {
|
||||
str += "" + qcd.get("t" + t);
|
||||
}
|
||||
// QCCs
|
||||
for (int c = 0; c < nc; c++) {
|
||||
if (qcc.get("t" + t + "_c" + c) != null) {
|
||||
str += "" + qcc.get("t" + t + "_c" + c);
|
||||
}
|
||||
}
|
||||
// RGN
|
||||
for (int c = 0; c < nc; c++) {
|
||||
if (rgn.get("t" + t + "_c" + c) != null) {
|
||||
str += "" + rgn.get("t" + t + "_c" + c);
|
||||
}
|
||||
}
|
||||
// POC
|
||||
if (poc.get("t" + t) != null) {
|
||||
str += "" + poc.get("t" + t);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this object
|
||||
*/
|
||||
public HeaderInfo getCopy(int nt) {
|
||||
HeaderInfo nhi = null;
|
||||
// SIZ
|
||||
try {
|
||||
nhi = (HeaderInfo) clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new Error("Cannot clone HeaderInfo instance");
|
||||
}
|
||||
nhi.siz = siz.getCopy();
|
||||
// COD
|
||||
if (cod.get("main") != null) {
|
||||
COD ms = (COD) cod.get("main");
|
||||
nhi.cod.put("main", ms.getCopy());
|
||||
}
|
||||
for (int t = 0; t < nt; t++) {
|
||||
if (cod.get("t" + t) != null) {
|
||||
COD ms = (COD) cod.get("t" + t);
|
||||
nhi.cod.put("t" + t, ms.getCopy());
|
||||
}
|
||||
}
|
||||
return nhi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class holding information found in the SIZ marker segment
|
||||
*/
|
||||
public class SIZ implements Cloneable {
|
||||
public int lsiz;
|
||||
public int rsiz;
|
||||
public int xsiz;
|
||||
public int ysiz;
|
||||
public int x0siz;
|
||||
public int y0siz;
|
||||
public int xtsiz;
|
||||
public int ytsiz;
|
||||
public int xt0siz;
|
||||
public int yt0siz;
|
||||
public int csiz;
|
||||
public int[] ssiz;
|
||||
public int[] xrsiz;
|
||||
public int[] yrsiz;
|
||||
|
||||
/**
|
||||
* Component widths
|
||||
*/
|
||||
private int[] compWidth = null;
|
||||
/**
|
||||
* Maximum width among all components
|
||||
*/
|
||||
private int maxCompWidth = -1;
|
||||
/**
|
||||
* Component heights
|
||||
*/
|
||||
private int[] compHeight = null;
|
||||
/**
|
||||
* Maximum height among all components
|
||||
*/
|
||||
private int maxCompHeight = -1;
|
||||
private int numTiles = -1;
|
||||
private boolean[] origSigned = null;
|
||||
private int[] origBitDepth = null;
|
||||
|
||||
/**
|
||||
* Width of the specified tile-component
|
||||
*
|
||||
* @param c Component index
|
||||
*/
|
||||
public int getCompImgWidth(int c) {
|
||||
if (compWidth == null) {
|
||||
compWidth = new int[csiz];
|
||||
for (int cc = 0; cc < csiz; cc++) {
|
||||
compWidth[cc] =
|
||||
(int) (Math.ceil((xsiz) / (double) xrsiz[cc])
|
||||
- Math.ceil(x0siz / (double) xrsiz[cc]));
|
||||
}
|
||||
}
|
||||
return compWidth[c];
|
||||
}
|
||||
|
||||
public int getMaxCompWidth() {
|
||||
if (compWidth == null) {
|
||||
compWidth = new int[csiz];
|
||||
for (int cc = 0; cc < csiz; cc++) {
|
||||
compWidth[cc] =
|
||||
(int) (Math.ceil((xsiz) / (double) xrsiz[cc])
|
||||
- Math.ceil(x0siz / (double) xrsiz[cc]));
|
||||
}
|
||||
}
|
||||
if (maxCompWidth == -1) {
|
||||
for (int c = 0; c < csiz; c++) {
|
||||
if (compWidth[c] > maxCompWidth) {
|
||||
maxCompWidth = compWidth[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxCompWidth;
|
||||
}
|
||||
|
||||
public int getCompImgHeight(int c) {
|
||||
if (compHeight == null) {
|
||||
compHeight = new int[csiz];
|
||||
for (int cc = 0; cc < csiz; cc++) {
|
||||
compHeight[cc] =
|
||||
(int) (Math.ceil((ysiz) / (double) yrsiz[cc])
|
||||
- Math.ceil(y0siz / (double) yrsiz[cc]));
|
||||
}
|
||||
}
|
||||
return compHeight[c];
|
||||
}
|
||||
|
||||
public int getMaxCompHeight() {
|
||||
if (compHeight == null) {
|
||||
compHeight = new int[csiz];
|
||||
for (int cc = 0; cc < csiz; cc++) {
|
||||
compHeight[cc] =
|
||||
(int) (Math.ceil((ysiz) / (double) yrsiz[cc])
|
||||
- Math.ceil(y0siz / (double) yrsiz[cc]));
|
||||
}
|
||||
}
|
||||
if (maxCompHeight == -1) {
|
||||
for (int c = 0; c < csiz; c++) {
|
||||
if (compHeight[c] != maxCompHeight) {
|
||||
maxCompHeight = compHeight[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
return maxCompHeight;
|
||||
}
|
||||
|
||||
public int getNumTiles() {
|
||||
if (numTiles == -1) {
|
||||
numTiles = ((xsiz - xt0siz + xtsiz - 1) / xtsiz) *
|
||||
((ysiz - yt0siz + ytsiz - 1) / ytsiz);
|
||||
}
|
||||
return numTiles;
|
||||
}
|
||||
|
||||
public boolean isOrigSigned(int c) {
|
||||
if (origSigned == null) {
|
||||
origSigned = new boolean[csiz];
|
||||
for (int cc = 0; cc < csiz; cc++) {
|
||||
origSigned[cc] = ((ssiz[cc] >>> SSIZ_DEPTH_BITS) == 1);
|
||||
}
|
||||
}
|
||||
return origSigned[c];
|
||||
}
|
||||
|
||||
public int getOrigBitDepth(int c) {
|
||||
if (origBitDepth == null) {
|
||||
origBitDepth = new int[csiz];
|
||||
for (int cc = 0; cc < csiz; cc++) {
|
||||
origBitDepth[cc] = (ssiz[cc] & ((1 << SSIZ_DEPTH_BITS) - 1)) + 1;
|
||||
}
|
||||
}
|
||||
return origBitDepth[c];
|
||||
}
|
||||
|
||||
public SIZ getCopy() {
|
||||
SIZ ms = null;
|
||||
try {
|
||||
ms = (SIZ) this.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new Error("Cannot clone SIZ marker segment");
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display information found in SIZ marker segment
|
||||
*/
|
||||
public String toString() {
|
||||
String str = "\n --- SIZ (" + lsiz + " bytes) ---\n";
|
||||
str += " Capabilities : " + rsiz + "\n";
|
||||
str += " Image dim. : " + (xsiz - x0siz) + "x" + (ysiz - y0siz) + ", (off=" +
|
||||
x0siz + "," + y0siz + ")\n";
|
||||
str += " Tile dim. : " + xtsiz + "x" + ytsiz + ", (off=" + xt0siz + "," +
|
||||
yt0siz + ")\n";
|
||||
str += " Component(s) : " + csiz + "\n";
|
||||
str += " Orig. depth : ";
|
||||
for (int i = 0; i < csiz; i++) {
|
||||
str += getOrigBitDepth(i) + " ";
|
||||
}
|
||||
str += "\n";
|
||||
str += " Orig. signed : ";
|
||||
for (int i = 0; i < csiz; i++) {
|
||||
str += isOrigSigned(i) + " ";
|
||||
}
|
||||
str += "\n";
|
||||
str += " Subs. factor : ";
|
||||
for (int i = 0; i < csiz; i++) {
|
||||
str += xrsiz[i] + "," + yrsiz[i] + " ";
|
||||
}
|
||||
str += "\n";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class holding information found in the SOt marker segments
|
||||
*/
|
||||
public class SOT {
|
||||
public int lsot;
|
||||
public int isot;
|
||||
public int psot;
|
||||
public int tpsot;
|
||||
public int tnsot;
|
||||
|
||||
/**
|
||||
* Display information found in this SOT marker segment
|
||||
*/
|
||||
public String toString() {
|
||||
String str = "\n --- SOT (" + lsot + " bytes) ---\n";
|
||||
str += "Tile index : " + isot + "\n";
|
||||
str += "Tile-part length : " + psot + " bytes\n";
|
||||
str += "Tile-part index : " + tpsot + "\n";
|
||||
str += "Num. of tile-parts : " + tnsot + "\n";
|
||||
str += "\n";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class holding information found in the COD marker segments
|
||||
*/
|
||||
public class COD implements Cloneable {
|
||||
public int lcod;
|
||||
public int scod;
|
||||
public int sgcod_po; // Progression order
|
||||
public int sgcod_nl; // Number of layers
|
||||
public int sgcod_mct; // Multiple component transformation
|
||||
public int spcod_ndl; // Number of decomposition levels
|
||||
public int spcod_cw; // Code-blocks width
|
||||
public int spcod_ch; // Code-blocks height
|
||||
public int spcod_cs; // Code-blocks style
|
||||
public int[] spcod_t = new int[1]; // Transformation
|
||||
public int[] spcod_ps; // Precinct size
|
||||
|
||||
public COD getCopy() {
|
||||
COD ms = null;
|
||||
try {
|
||||
ms = (COD) this.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new Error("Cannot clone SIZ marker segment");
|
||||
}
|
||||
return ms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display information found in this COD marker segment
|
||||
*/
|
||||
public String toString() {
|
||||
String str = "\n --- COD (" + lcod + " bytes) ---\n";
|
||||
str += " Coding style : ";
|
||||
if (scod == 0) {
|
||||
str += "Default";
|
||||
} else {
|
||||
if ((scod & SCOX_PRECINCT_PARTITION) != 0) str += "Precints ";
|
||||
if ((scod & SCOX_USE_SOP) != 0) str += "SOP ";
|
||||
if ((scod & SCOX_USE_EPH) != 0) str += "EPH ";
|
||||
int cb0x = ((scod & SCOX_HOR_CB_PART) != 0) ? 1 : 0;
|
||||
int cb0y = ((scod & SCOX_VER_CB_PART) != 0) ? 1 : 0;
|
||||
if (cb0x != 0 || cb0y != 0) {
|
||||
str += "Code-blocks offset";
|
||||
str += "\n Cblk partition : " + cb0x + "," + cb0y;
|
||||
}
|
||||
}
|
||||
str += "\n";
|
||||
str += " Cblk style : ";
|
||||
if (spcod_cs == 0) {
|
||||
str += "Default";
|
||||
} else {
|
||||
if ((spcod_cs & 0x1) != 0) str += "Bypass ";
|
||||
if ((spcod_cs & 0x2) != 0) str += "Reset ";
|
||||
if ((spcod_cs & 0x4) != 0) str += "Terminate ";
|
||||
if ((spcod_cs & 0x8) != 0) str += "Vert_causal ";
|
||||
if ((spcod_cs & 0x10) != 0) str += "Predict ";
|
||||
if ((spcod_cs & 0x20) != 0) str += "Seg_symb ";
|
||||
}
|
||||
str += "\n";
|
||||
str += " Num. of levels : " + spcod_ndl + "\n";
|
||||
switch (sgcod_po) {
|
||||
case LY_RES_COMP_POS_PROG:
|
||||
str += " Progress. type : LY_RES_COMP_POS_PROG\n";
|
||||
break;
|
||||
case RES_LY_COMP_POS_PROG:
|
||||
str += " Progress. type : RES_LY_COMP_POS_PROG\n";
|
||||
break;
|
||||
case RES_POS_COMP_LY_PROG:
|
||||
str += " Progress. type : RES_POS_COMP_LY_PROG\n";
|
||||
break;
|
||||
case POS_COMP_RES_LY_PROG:
|
||||
str += " Progress. type : POS_COMP_RES_LY_PROG\n";
|
||||
break;
|
||||
case COMP_POS_RES_LY_PROG:
|
||||
str += " Progress. type : COMP_POS_RES_LY_PROG\n";
|
||||
break;
|
||||
}
|
||||
str += " Num. of layers : " + sgcod_nl + "\n";
|
||||
str += " Cblk dimension : " + (1 << (spcod_cw + 2)) + "x" +
|
||||
(1 << (spcod_ch + 2)) + "\n";
|
||||
switch (spcod_t[0]) {
|
||||
case W9X7:
|
||||
str += " Filter : 9-7 irreversible\n";
|
||||
break;
|
||||
case W5X3:
|
||||
str += " Filter : 5-3 reversible\n";
|
||||
break;
|
||||
}
|
||||
str += " Multi comp tr. : " + (sgcod_mct == 1) + "\n";
|
||||
if (spcod_ps != null) {
|
||||
str += " Precincts : ";
|
||||
for (int i = 0; i < spcod_ps.length; i++) {
|
||||
str += (1 << (spcod_ps[i] & 0x000F)) + "x" +
|
||||
(1 << (((spcod_ps[i] & 0x00F0) >> 4))) + " ";
|
||||
}
|
||||
}
|
||||
str += "\n";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class holding information found in the COC marker segments
|
||||
*/
|
||||
public class COC {
|
||||
public int lcoc;
|
||||
public int ccoc;
|
||||
public int scoc;
|
||||
public int spcoc_ndl; // Number of decomposition levels
|
||||
public int spcoc_cw;
|
||||
public int spcoc_ch;
|
||||
public int spcoc_cs;
|
||||
public int[] spcoc_t = new int[1];
|
||||
public int[] spcoc_ps;
|
||||
|
||||
/**
|
||||
* Display information found in this COC marker segment
|
||||
*/
|
||||
public String toString() {
|
||||
String str = "\n --- COC (" + lcoc + " bytes) ---\n";
|
||||
str += " Component : " + ccoc + "\n";
|
||||
str += " Coding style : ";
|
||||
if (scoc == 0) {
|
||||
str += "Default";
|
||||
} else {
|
||||
if ((scoc & 0x1) != 0) str += "Precints ";
|
||||
if ((scoc & 0x2) != 0) str += "SOP ";
|
||||
if ((scoc & 0x4) != 0) str += "EPH ";
|
||||
}
|
||||
str += "\n";
|
||||
str += " Cblk style : ";
|
||||
if (spcoc_cs == 0) {
|
||||
str += "Default";
|
||||
} else {
|
||||
if ((spcoc_cs & 0x1) != 0) str += "Bypass ";
|
||||
if ((spcoc_cs & 0x2) != 0) str += "Reset ";
|
||||
if ((spcoc_cs & 0x4) != 0) str += "Terminate ";
|
||||
if ((spcoc_cs & 0x8) != 0) str += "Vert_causal ";
|
||||
if ((spcoc_cs & 0x10) != 0) str += "Predict ";
|
||||
if ((spcoc_cs & 0x20) != 0) str += "Seg_symb ";
|
||||
}
|
||||
str += "\n";
|
||||
str += " Num. of levels : " + spcoc_ndl + "\n";
|
||||
str += " Cblk dimension : " + (1 << (spcoc_cw + 2)) + "x" +
|
||||
(1 << (spcoc_ch + 2)) + "\n";
|
||||
switch (spcoc_t[0]) {
|
||||
case W9X7:
|
||||
str += " Filter : 9-7 irreversible\n";
|
||||
break;
|
||||
case W5X3:
|
||||
str += " Filter : 5-3 reversible\n";
|
||||
break;
|
||||
}
|
||||
if (spcoc_ps != null) {
|
||||
str += " Precincts : ";
|
||||
for (int i = 0; i < spcoc_ps.length; i++) {
|
||||
str += (1 << (spcoc_ps[i] & 0x000F)) + "x" +
|
||||
(1 << (((spcoc_ps[i] & 0x00F0) >> 4))) + " ";
|
||||
}
|
||||
}
|
||||
str += "\n";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class holding information found in the RGN marker segments
|
||||
*/
|
||||
public class RGN {
|
||||
public int lrgn;
|
||||
public int crgn;
|
||||
public int srgn;
|
||||
public int sprgn;
|
||||
|
||||
/**
|
||||
* Display information found in this RGN marker segment
|
||||
*/
|
||||
public String toString() {
|
||||
String str = "\n --- RGN (" + lrgn + " bytes) ---\n";
|
||||
str += " Component : " + crgn + "\n";
|
||||
if (srgn == 0) {
|
||||
str += " ROI style : Implicit\n";
|
||||
} else {
|
||||
str += " ROI style : Unsupported\n";
|
||||
}
|
||||
str += " ROI shift : " + sprgn + "\n";
|
||||
str += "\n";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class holding information found in the QCD marker segments
|
||||
*/
|
||||
public class QCD {
|
||||
public int lqcd;
|
||||
public int sqcd;
|
||||
public int[][] spqcd;
|
||||
|
||||
private int qType = -1;
|
||||
private int gb = -1;
|
||||
|
||||
public int getQuantType() {
|
||||
if (qType == -1) {
|
||||
qType = sqcd & ~(SQCX_GB_MSK << SQCX_GB_SHIFT);
|
||||
}
|
||||
return qType;
|
||||
}
|
||||
|
||||
public int getNumGuardBits() {
|
||||
if (gb == -1) {
|
||||
gb = (sqcd >> SQCX_GB_SHIFT) & SQCX_GB_MSK;
|
||||
}
|
||||
return gb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display information found in this QCD marker segment
|
||||
*/
|
||||
public String toString() {
|
||||
String str = "\n --- QCD (" + lqcd + " bytes) ---\n";
|
||||
str += " Quant. type : ";
|
||||
int qt = getQuantType();
|
||||
if (qt == SQCX_NO_QUANTIZATION) str += "No quantization \n";
|
||||
else if (qt == SQCX_SCALAR_DERIVED) str += "Scalar derived\n";
|
||||
else if (qt == SQCX_SCALAR_EXPOUNDED) str += "Scalar expounded\n";
|
||||
str += " Guard bits : " + getNumGuardBits() + "\n";
|
||||
if (qt == SQCX_NO_QUANTIZATION) {
|
||||
str += " Exponents :\n";
|
||||
int exp;
|
||||
for (int i = 0; i < spqcd.length; i++) {
|
||||
for (int j = 0; j < spqcd[i].length; j++) {
|
||||
if (i == 0 && j == 0) {
|
||||
exp = (spqcd[0][0] >> SQCX_EXP_SHIFT) & SQCX_EXP_MASK;
|
||||
str += "\tr=0 : " + exp + "\n";
|
||||
} else if (i != 0 && j > 0) {
|
||||
exp = (spqcd[i][j] >> SQCX_EXP_SHIFT) & SQCX_EXP_MASK;
|
||||
str += "\tr=" + i + ",s=" + j + " : " + exp + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
str += " Exp / Mantissa : \n";
|
||||
int exp;
|
||||
double mantissa;
|
||||
for (int i = 0; i < spqcd.length; i++) {
|
||||
for (int j = 0; j < spqcd[i].length; j++) {
|
||||
if (i == 0 && j == 0) {
|
||||
exp = (spqcd[0][0] >> 11) & 0x1f;
|
||||
mantissa = (-1f - ((float) (spqcd[0][0] & 0x07ff)) /
|
||||
(1 << 11)) / (-1 << exp);
|
||||
str += "\tr=0 : " + exp + " / " + mantissa + "\n";
|
||||
} else if (i != 0 && j > 0) {
|
||||
exp = (spqcd[i][j] >> 11) & 0x1f;
|
||||
mantissa = (-1f - ((float) (spqcd[i][j] & 0x07ff)) /
|
||||
(1 << 11)) / (-1 << exp);
|
||||
str += "\tr=" + i + ",s=" + j + " : " + exp + " / " +
|
||||
mantissa + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
str += "\n";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class holding information found in the QCC marker segments
|
||||
*/
|
||||
public class QCC {
|
||||
public int lqcc;
|
||||
public int cqcc;
|
||||
public int sqcc;
|
||||
public int[][] spqcc;
|
||||
|
||||
private int qType = -1;
|
||||
private int gb = -1;
|
||||
|
||||
public int getQuantType() {
|
||||
if (qType == -1) {
|
||||
qType = sqcc & ~(SQCX_GB_MSK << SQCX_GB_SHIFT);
|
||||
}
|
||||
return qType;
|
||||
}
|
||||
|
||||
public int getNumGuardBits() {
|
||||
if (gb == -1) {
|
||||
gb = (sqcc >> SQCX_GB_SHIFT) & SQCX_GB_MSK;
|
||||
}
|
||||
return gb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display information found in this QCC marker segment
|
||||
*/
|
||||
public String toString() {
|
||||
String str = "\n --- QCC (" + lqcc + " bytes) ---\n";
|
||||
str += " Component : " + cqcc + "\n";
|
||||
str += " Quant. type : ";
|
||||
int qt = getQuantType();
|
||||
if (qt == SQCX_NO_QUANTIZATION) str += "No quantization \n";
|
||||
else if (qt == SQCX_SCALAR_DERIVED) str += "Scalar derived\n";
|
||||
else if (qt == SQCX_SCALAR_EXPOUNDED) str += "Scalar expounded\n";
|
||||
str += " Guard bits : " + getNumGuardBits() + "\n";
|
||||
if (qt == SQCX_NO_QUANTIZATION) {
|
||||
str += " Exponents :\n";
|
||||
int exp;
|
||||
for (int i = 0; i < spqcc.length; i++) {
|
||||
for (int j = 0; j < spqcc[i].length; j++) {
|
||||
if (i == 0 && j == 0) {
|
||||
exp = (spqcc[0][0] >> SQCX_EXP_SHIFT) & SQCX_EXP_MASK;
|
||||
str += "\tr=0 : " + exp + "\n";
|
||||
} else if (i != 0 && j > 0) {
|
||||
exp = (spqcc[i][j] >> SQCX_EXP_SHIFT) & SQCX_EXP_MASK;
|
||||
str += "\tr=" + i + ",s=" + j + " : " + exp + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
str += " Exp / Mantissa : \n";
|
||||
int exp;
|
||||
double mantissa;
|
||||
for (int i = 0; i < spqcc.length; i++) {
|
||||
for (int j = 0; j < spqcc[i].length; j++) {
|
||||
if (i == 0 && j == 0) {
|
||||
exp = (spqcc[0][0] >> 11) & 0x1f;
|
||||
mantissa = (-1f - ((float) (spqcc[0][0] & 0x07ff)) /
|
||||
(1 << 11)) / (-1 << exp);
|
||||
str += "\tr=0 : " + exp + " / " + mantissa + "\n";
|
||||
} else if (i != 0 && j > 0) {
|
||||
exp = (spqcc[i][j] >> 11) & 0x1f;
|
||||
mantissa = (-1f - ((float) (spqcc[i][j] & 0x07ff)) /
|
||||
(1 << 11)) / (-1 << exp);
|
||||
str += "\tr=" + i + ",s=" + j + " : " + exp + " / " +
|
||||
mantissa + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
str += "\n";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class holding information found in the POC marker segments
|
||||
*/
|
||||
public class POC {
|
||||
public int lpoc;
|
||||
public int[] rspoc;
|
||||
public int[] cspoc;
|
||||
public int[] lyepoc;
|
||||
public int[] repoc;
|
||||
public int[] cepoc;
|
||||
public int[] ppoc;
|
||||
|
||||
/**
|
||||
* Display information found in this POC marker segment
|
||||
*/
|
||||
public String toString() {
|
||||
String str = "\n --- POC (" + lpoc + " bytes) ---\n";
|
||||
str += " Chg_idx RSpoc CSpoc LYEpoc REpoc CEpoc Ppoc\n";
|
||||
for (int chg = 0; chg < rspoc.length; chg++) {
|
||||
str += " " + chg
|
||||
+ " " + rspoc[chg]
|
||||
+ " " + cspoc[chg]
|
||||
+ " " + lyepoc[chg]
|
||||
+ " " + repoc[chg]
|
||||
+ " " + cepoc[chg];
|
||||
switch (ppoc[chg]) {
|
||||
case ProgressionType.LY_RES_COMP_POS_PROG:
|
||||
str += " LY_RES_COMP_POS_PROG\n";
|
||||
break;
|
||||
case ProgressionType.RES_LY_COMP_POS_PROG:
|
||||
str += " RES_LY_COMP_POS_PROG\n";
|
||||
break;
|
||||
case ProgressionType.RES_POS_COMP_LY_PROG:
|
||||
str += " RES_POS_COMP_LY_PROG\n";
|
||||
break;
|
||||
case ProgressionType.POS_COMP_RES_LY_PROG:
|
||||
str += " POS_COMP_RES_LY_PROG\n";
|
||||
break;
|
||||
case ProgressionType.COMP_POS_RES_LY_PROG:
|
||||
str += " COMP_POS_RES_LY_PROG\n";
|
||||
break;
|
||||
}
|
||||
}
|
||||
str += "\n";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class holding information found in the CRG marker segment
|
||||
*/
|
||||
public class CRG {
|
||||
public int lcrg;
|
||||
public int[] xcrg;
|
||||
public int[] ycrg;
|
||||
|
||||
/**
|
||||
* Display information found in the CRG marker segment
|
||||
*/
|
||||
public String toString() {
|
||||
String str = "\n --- CRG (" + lcrg + " bytes) ---\n";
|
||||
for (int c = 0; c < xcrg.length; c++) {
|
||||
str += " Component " + c + " offset : " + xcrg[c] + "," + ycrg[c] + "\n";
|
||||
}
|
||||
str += "\n";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class holding information found in the COM marker segments
|
||||
*/
|
||||
public class COM {
|
||||
public int lcom;
|
||||
public int rcom;
|
||||
public byte[] ccom;
|
||||
|
||||
/**
|
||||
* Display information found in the COM marker segment
|
||||
*/
|
||||
public String toString() {
|
||||
String str = "\n --- COM (" + lcom + " bytes) ---\n";
|
||||
if (rcom == 0) {
|
||||
str += " Registration : General use (binary values)\n";
|
||||
} else if (rcom == 1) {
|
||||
str += " Registration : General use (IS 8859-15:1999 " +
|
||||
"(Latin) values)\n";
|
||||
str += " Text : " + (new String(ccom)) + "\n";
|
||||
} else {
|
||||
str += " Registration : Unknown\n";
|
||||
}
|
||||
str += "\n";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
/*
|
||||
* $RCSfile: Markers.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:00 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: Markers
|
||||
*
|
||||
* Description: Defines the values of the markers in JPEG 2000 codestream
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream;
|
||||
|
||||
/**
|
||||
* This interface defines the values of the different markers in the JPEG 2000
|
||||
* codestream. They are 16 bit values, always appearing in big-endian (most
|
||||
* significant byte first) and byte-aligned in the codestream. This interface
|
||||
* also defines some other constants such as bit-masks and bit-shifts.
|
||||
*/
|
||||
public interface Markers {
|
||||
|
||||
// ----> Delimiting markers and marker segments <----
|
||||
|
||||
/**
|
||||
* Start of codestream (SOC): 0xFF4F
|
||||
*/
|
||||
short SOC = (short) 0xff4f;
|
||||
|
||||
/**
|
||||
* Start of tile-part (SOT): 0xFF90
|
||||
*/
|
||||
short SOT = (short) 0xff90;
|
||||
|
||||
/**
|
||||
* Start of data (SOD): 0xFF93
|
||||
*/
|
||||
short SOD = (short) 0xff93;
|
||||
|
||||
/**
|
||||
* End of codestream (EOC): 0xFFD9
|
||||
*/
|
||||
short EOC = (short) 0xffd9;
|
||||
|
||||
// ----> Fixed information marker segments <----
|
||||
|
||||
// ** SIZ marker **
|
||||
|
||||
/**
|
||||
* SIZ marker (Image and tile size): 0xFF51
|
||||
*/
|
||||
short SIZ = (short) 0xff51;
|
||||
|
||||
/**
|
||||
* No special capabilities (baseline) in codestream, in Rsiz field of SIZ
|
||||
* marker: 0x00. All flag bits are turned off
|
||||
*/
|
||||
int RSIZ_BASELINE = 0x00;
|
||||
/**
|
||||
* Error resilience marker flag bit in Rsiz field in SIZ marker: 0x01
|
||||
*/
|
||||
int RSIZ_ER_FLAG = 0x01;
|
||||
/**
|
||||
* ROI present marker flag bit in Rsiz field in SIZ marker: 0x02
|
||||
*/
|
||||
int RSIZ_ROI = 0x02;
|
||||
/**
|
||||
* Component bitdepth bits in Ssiz field in SIZ marker: 7
|
||||
*/
|
||||
int SSIZ_DEPTH_BITS = 7;
|
||||
/**
|
||||
* The maximum number of component bitdepth
|
||||
*/
|
||||
int MAX_COMP_BITDEPTH = 38;
|
||||
|
||||
|
||||
// ----> Functional marker segments <----
|
||||
|
||||
// ** COD/COC marker **
|
||||
|
||||
/**
|
||||
* Coding style default (COD): 0xFF52
|
||||
*/
|
||||
short COD = (short) 0xff52;
|
||||
|
||||
/**
|
||||
* Coding style component (COC): 0xFF53
|
||||
*/
|
||||
short COC = (short) 0xff53;
|
||||
|
||||
/**
|
||||
* Precinct used flag
|
||||
*/
|
||||
int SCOX_PRECINCT_PARTITION = 1;
|
||||
/**
|
||||
* Use start of packet marker
|
||||
*/
|
||||
int SCOX_USE_SOP = 2;
|
||||
/**
|
||||
* Use end of packet header marker
|
||||
*/
|
||||
int SCOX_USE_EPH = 4;
|
||||
/**
|
||||
* Horizontal code-block partition origin is at x=1
|
||||
*/
|
||||
int SCOX_HOR_CB_PART = 8;
|
||||
/**
|
||||
* Vertical code-block partition origin is at y=1
|
||||
*/
|
||||
int SCOX_VER_CB_PART = 16;
|
||||
/**
|
||||
* The default size exponent of the precincts
|
||||
*/
|
||||
int PRECINCT_PARTITION_DEF_SIZE = 0xffff;
|
||||
|
||||
// ** RGN marker segment **
|
||||
/**
|
||||
* Region-of-interest (RGN): 0xFF5E
|
||||
*/
|
||||
short RGN = (short) 0xff5e;
|
||||
|
||||
/**
|
||||
* Implicit (i.e. max-shift) ROI flag for Srgn field in RGN marker
|
||||
* segment: 0x00
|
||||
*/
|
||||
int SRGN_IMPLICIT = 0x00;
|
||||
|
||||
// ** QCD/QCC markers **
|
||||
|
||||
/**
|
||||
* Quantization default (QCD): 0xFF5C
|
||||
*/
|
||||
short QCD = (short) 0xff5c;
|
||||
|
||||
/**
|
||||
* Quantization component (QCC): 0xFF5D
|
||||
*/
|
||||
short QCC = (short) 0xff5d;
|
||||
|
||||
/**
|
||||
* Guard bits shift in SQCX field: 5
|
||||
*/
|
||||
int SQCX_GB_SHIFT = 5;
|
||||
/**
|
||||
* Guard bits mask in SQCX field: 7
|
||||
*/
|
||||
int SQCX_GB_MSK = 7;
|
||||
/**
|
||||
* No quantization (i.e. embedded reversible) flag for Sqcd or Sqcc
|
||||
* (Sqcx) fields: 0x00.
|
||||
*/
|
||||
int SQCX_NO_QUANTIZATION = 0x00;
|
||||
/**
|
||||
* Scalar derived (i.e. LL values only) quantization flag for Sqcd or
|
||||
* Sqcc (Sqcx) fields: 0x01.
|
||||
*/
|
||||
int SQCX_SCALAR_DERIVED = 0x01;
|
||||
/**
|
||||
* Scalar expounded (i.e. all values) quantization flag for Sqcd or Sqcc
|
||||
* (Sqcx) fields: 0x02.
|
||||
*/
|
||||
int SQCX_SCALAR_EXPOUNDED = 0x02;
|
||||
/**
|
||||
* Exponent shift in SPQCX when no quantization: 3
|
||||
*/
|
||||
int SQCX_EXP_SHIFT = 3;
|
||||
/**
|
||||
* Exponent bitmask in SPQCX when no quantization: 3
|
||||
*/
|
||||
int SQCX_EXP_MASK = (1 << 5) - 1;
|
||||
/**
|
||||
* The "SOP marker segments used" flag within Sers: 1
|
||||
*/
|
||||
int ERS_SOP = 1;
|
||||
/**
|
||||
* The "segmentation symbols used" flag within Sers: 2
|
||||
*/
|
||||
int ERS_SEG_SYMBOLS = 2;
|
||||
|
||||
// ** Progression order change **
|
||||
short POC = (short) 0xff5f;
|
||||
|
||||
// ----> Pointer marker segments <----
|
||||
|
||||
/**
|
||||
* Tile-part lengths (TLM): 0xFF55
|
||||
*/
|
||||
short TLM = (short) 0xff55;
|
||||
|
||||
/**
|
||||
* Packet length, main header (PLM): 0xFF57
|
||||
*/
|
||||
short PLM = (short) 0xff57;
|
||||
|
||||
/**
|
||||
* Packet length, tile-part header (PLT): 0xFF58
|
||||
*/
|
||||
short PLT = (short) 0xff58;
|
||||
|
||||
/**
|
||||
* Packed packet headers, main header (PPM): 0xFF60
|
||||
*/
|
||||
short PPM = (short) 0xff60;
|
||||
|
||||
/**
|
||||
* Packed packet headers, tile-part header (PPT): 0xFF61
|
||||
*/
|
||||
short PPT = (short) 0xff61;
|
||||
|
||||
/**
|
||||
* Maximum length of PPT marker segment
|
||||
*/
|
||||
int MAX_LPPT = 65535;
|
||||
|
||||
/**
|
||||
* Maximum length of PPM marker segment
|
||||
*/
|
||||
int MAX_LPPM = 65535;
|
||||
|
||||
|
||||
// ----> In bit stream markers and marker segments <----
|
||||
|
||||
/**
|
||||
* Start pf packet (SOP): 0xFF91
|
||||
*/
|
||||
short SOP = (short) 0xff91;
|
||||
|
||||
/**
|
||||
* Length of SOP marker (in bytes)
|
||||
*/
|
||||
short SOP_LENGTH = 6;
|
||||
|
||||
/**
|
||||
* End of packet header (EPH): 0xFF92
|
||||
*/
|
||||
short EPH = (short) 0xff92;
|
||||
|
||||
/**
|
||||
* Length of EPH marker (in bytes)
|
||||
*/
|
||||
short EPH_LENGTH = 2;
|
||||
|
||||
// ----> Informational marker segments <----
|
||||
|
||||
/**
|
||||
* Component registration (CRG): 0xFF63
|
||||
*/
|
||||
short CRG = (short) 0xff63;
|
||||
|
||||
/**
|
||||
* Comment (COM): 0xFF64
|
||||
*/
|
||||
short COM = (short) 0xff64;
|
||||
|
||||
/**
|
||||
* General use registration value (COM): 0x0001
|
||||
*/
|
||||
short RCOM_GEN_USE = (short) 0x0001;
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* $RCSfile: PrecCoordInfo.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:00 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: PrecCoordInfo
|
||||
*
|
||||
* Description: Used to store the coordinates precincts.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream;
|
||||
|
||||
/**
|
||||
* This class is used to store the coordinates of precincts.
|
||||
*/
|
||||
public class PrecCoordInfo extends CoordInfo {
|
||||
|
||||
/**
|
||||
* Horizontal upper left coordinate in the reference grid
|
||||
*/
|
||||
public int xref;
|
||||
|
||||
/**
|
||||
* Vertical upper left coordinate on the reference grid
|
||||
*/
|
||||
public int yref;
|
||||
|
||||
/**
|
||||
* Constructor. Creates a PrecCoordInfo object.
|
||||
*
|
||||
* @param ulx Horizontal upper left coordinate in the subband
|
||||
* @param uly Vertical upper left coordinate in the subband
|
||||
* @param w Precint's width
|
||||
* @param h Precinct's height
|
||||
* @param xref The horizontal coordinate on the reference grid
|
||||
* @param yref The vertical coordinate on the reference grid
|
||||
*/
|
||||
public PrecCoordInfo(int ulx, int uly, int w, int h,
|
||||
int xref, int yref) {
|
||||
super(ulx, uly, w, h);
|
||||
this.xref = xref;
|
||||
this.yref = yref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Empty Constructor. Creates an empty PrecCoordInfo object.
|
||||
*/
|
||||
public PrecCoordInfo() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns precinct's information in a String
|
||||
*
|
||||
* @return String with precinct's information
|
||||
*/
|
||||
public String toString() {
|
||||
return super.toString() + ", xref=" + xref + ", yref=" + yref;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* $RCSfile: PrecInfo.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:00 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: PrecInfo
|
||||
*
|
||||
* Description: Keeps information about a precinct
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream;
|
||||
|
||||
/**
|
||||
* Class that holds precinct coordinates and references to contained
|
||||
* code-blocks in each subband.
|
||||
*/
|
||||
public class PrecInfo {
|
||||
|
||||
/**
|
||||
* Precinct horizontal upper-left coordinate in the reference grid
|
||||
*/
|
||||
public int rgulx;
|
||||
|
||||
/**
|
||||
* Precinct vertical upper-left coordinate in the reference grid
|
||||
*/
|
||||
public int rguly;
|
||||
|
||||
/**
|
||||
* Precinct width reported in the reference grid
|
||||
*/
|
||||
public int rgw;
|
||||
|
||||
/**
|
||||
* Precinct height reported in the reference grid
|
||||
*/
|
||||
public int rgh;
|
||||
|
||||
/**
|
||||
* Precinct horizontal upper-left coordinate in the corresponding
|
||||
* resolution level
|
||||
*/
|
||||
public int ulx;
|
||||
|
||||
/**
|
||||
* Precinct vertical upper-left coordinate in the corresponding
|
||||
* resolution level
|
||||
*/
|
||||
public int uly;
|
||||
|
||||
/**
|
||||
* Precinct width in the corresponding resolution level
|
||||
*/
|
||||
public int w;
|
||||
|
||||
/**
|
||||
* Precinct height in the corresponding resolution level
|
||||
*/
|
||||
public int h;
|
||||
|
||||
/**
|
||||
* Resolution level index
|
||||
*/
|
||||
public int r;
|
||||
|
||||
/**
|
||||
* Code-blocks belonging to this precinct in each subbands of the
|
||||
* resolution level
|
||||
*/
|
||||
public CBlkCoordInfo[][][] cblk;
|
||||
|
||||
/**
|
||||
* Number of code-blocks in each subband belonging to this precinct
|
||||
*/
|
||||
public int[] nblk;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param r Resolution level index.
|
||||
* @param ulx Precinct horizontal offset.
|
||||
* @param uly Precinct vertical offset.
|
||||
* @param w Precinct width.
|
||||
* @param h Precinct height.
|
||||
* @param rgulx Precinct horizontal offset in the image reference grid.
|
||||
* @param rguly Precinct horizontal offset in the image reference grid.
|
||||
* @param rgw Precinct width in the reference grid.
|
||||
* @param rgh Precinct height in the reference grid.
|
||||
*/
|
||||
public PrecInfo(int r, int ulx, int uly, int w, int h, int rgulx, int rguly,
|
||||
int rgw, int rgh) {
|
||||
this.r = r;
|
||||
this.ulx = ulx;
|
||||
this.uly = uly;
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
this.rgulx = rgulx;
|
||||
this.rguly = rguly;
|
||||
this.rgw = rgw;
|
||||
this.rgh = rgh;
|
||||
|
||||
if (r == 0) {
|
||||
cblk = new CBlkCoordInfo[1][][];
|
||||
nblk = new int[1];
|
||||
} else {
|
||||
cblk = new CBlkCoordInfo[4][][];
|
||||
nblk = new int[4];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns PrecInfo object information in a String
|
||||
*
|
||||
* @return PrecInfo information
|
||||
*/
|
||||
public String toString() {
|
||||
return "ulx=" + ulx + ",uly=" + uly + ",w=" + w + ",h=" + h + ",rgulx=" + rgulx +
|
||||
",rguly=" + rguly + ",rgw=" + rgw + ",rgh=" + rgh;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* $RCSfile: ProgressionType.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:00 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: ProgressionType
|
||||
*
|
||||
* Description: The definition of the different bit stream
|
||||
* profiles.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream;
|
||||
|
||||
/**
|
||||
* This interface defines the identifiers for the different bit stream
|
||||
* profiles and progression types.
|
||||
*
|
||||
* <P>Each progressive type has a different number: 'PT_SNR_PROG',
|
||||
* 'PT_RES_PROG', or 'PT_ARB_PROG'. These are the same identifiers are used in
|
||||
* the codestream syntax.
|
||||
*
|
||||
* <P>Each profile identifier is a flag bit. Therefore, several
|
||||
* profiles can appear at the same time.
|
||||
*
|
||||
* <p>This interface defines the constants only. In order to use the constants
|
||||
* in any other class you can either use the fully qualified name (e.g.,
|
||||
* <tt>ProgressionType.LY_RES_COMP_POS_PROG</tt>) or declare this interface in
|
||||
* the implements clause of the class and then access the identifier
|
||||
* directly.</p>
|
||||
*/
|
||||
public interface ProgressionType {
|
||||
|
||||
/**
|
||||
* The bit stream is Layer/Resolution/Component/Position progressive : 0
|
||||
*/
|
||||
int LY_RES_COMP_POS_PROG = 0;
|
||||
|
||||
/**
|
||||
* The bit stream is Resolution/Layer/Component/Position progressive : 1
|
||||
*/
|
||||
int RES_LY_COMP_POS_PROG = 1;
|
||||
|
||||
/**
|
||||
* The bit stream is Resolution/Position/Component/Layer progressive : 2
|
||||
*/
|
||||
int RES_POS_COMP_LY_PROG = 2;
|
||||
|
||||
/**
|
||||
* The bit stream is Position/Component/Resolution/Layer progressive : 3
|
||||
*/
|
||||
int POS_COMP_RES_LY_PROG = 3;
|
||||
|
||||
/**
|
||||
* The bit stream is Component/Position/Resolution/Layer progressive : 4
|
||||
*/
|
||||
int COMP_POS_RES_LY_PROG = 4;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* $RCSfile: CBlkInfo.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:01 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: CBlkInfo
|
||||
*
|
||||
* Description: Object containing code-block informations.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream.reader;
|
||||
|
||||
|
||||
/**
|
||||
* This class contains location of code-blocks' piece of codewords
|
||||
* (there is one piece per layer) and some other information.
|
||||
*/
|
||||
public class CBlkInfo {
|
||||
|
||||
/**
|
||||
* Upper-left x-coordinate of the code-block (relative to the
|
||||
* tile)
|
||||
*/
|
||||
public int ulx;
|
||||
|
||||
/**
|
||||
* Upper-left y-coordinate of the code-block (relative to the
|
||||
* tile)
|
||||
*/
|
||||
public int uly;
|
||||
|
||||
/**
|
||||
* Width of the code-block
|
||||
*/
|
||||
public int w;
|
||||
|
||||
/**
|
||||
* Height of the code-block
|
||||
*/
|
||||
public int h;
|
||||
|
||||
/**
|
||||
* The number of most significant bits which are skipped for this
|
||||
* code-block (= Mb-1-bitDepth). See VM text
|
||||
*/
|
||||
public int msbSkipped;
|
||||
|
||||
/**
|
||||
* Length of each piece of code-block's codewords
|
||||
*/
|
||||
public int[] len;
|
||||
|
||||
/**
|
||||
* Offset of each piece of code-block's codewords in the file
|
||||
*/
|
||||
public int[] off;
|
||||
|
||||
/**
|
||||
* The number of truncation point for each layer
|
||||
*/
|
||||
public int[] ntp;
|
||||
|
||||
/**
|
||||
* The cumulative number of truncation points
|
||||
*/
|
||||
public int ctp;
|
||||
|
||||
/**
|
||||
* The length of each segment (used with regular termination or
|
||||
* in selective arithmetic bypass coding mode)
|
||||
*/
|
||||
public int[][] segLen;
|
||||
|
||||
/**
|
||||
* Index of the packet where each layer has been found
|
||||
*/
|
||||
public int[] pktIdx;
|
||||
|
||||
/**
|
||||
* Constructs a new instance with specified number of layers and
|
||||
* code-block coordinates. The number corresponds to the maximum
|
||||
* piece of codeword for one code-block.
|
||||
*
|
||||
* @param ulx The uper-left x-coordinate
|
||||
* @param uly The uper-left y-coordinate
|
||||
* @param w Width of the code-block
|
||||
* @param h Height of the code-block
|
||||
* @param nl The number of layers
|
||||
*/
|
||||
public CBlkInfo(int ulx, int uly, int w, int h, int nl) {
|
||||
this.ulx = ulx;
|
||||
this.uly = uly;
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
off = new int[nl];
|
||||
len = new int[nl];
|
||||
ntp = new int[nl];
|
||||
segLen = new int[nl][];
|
||||
pktIdx = new int[nl];
|
||||
for (int i = nl - 1; i >= 0; i--)
|
||||
pktIdx[i] = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the number of new truncation for specified layer.
|
||||
*
|
||||
* @param l layer index
|
||||
* @param newtp Number of new truncation points
|
||||
*/
|
||||
public void addNTP(int l, int newtp) {
|
||||
ntp[l] = newtp;
|
||||
ctp = 0;
|
||||
for (int lIdx = 0; lIdx <= l; lIdx++) {
|
||||
ctp += ntp[lIdx];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Object information in a string.
|
||||
*
|
||||
* @return Object information
|
||||
*/
|
||||
public String toString() {
|
||||
String string = "(ulx,uly,w,h)= " + ulx + "," + uly + "," + w + "," + h;
|
||||
string += ", " + msbSkipped + " MSB bit(s) skipped\n";
|
||||
if (len != null)
|
||||
for (int i = 0; i < len.length; i++) {
|
||||
string += "\tl:" + i + ", start:" + off[i] +
|
||||
", len:" + len[i] + ", ntp:" + ntp[i] + ", pktIdx=" +
|
||||
pktIdx[i];
|
||||
if (segLen != null && segLen[i] != null) {
|
||||
string += " { ";
|
||||
for (int j = 0; j < segLen[i].length; j++)
|
||||
string += segLen[i][j] + " ";
|
||||
string += "}";
|
||||
}
|
||||
string += "\n";
|
||||
}
|
||||
string += "\tctp=" + ctp;
|
||||
return string;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* $RCSfile: PktHeaderBitReader.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:01 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: PktHeaderBitReader
|
||||
*
|
||||
* Description: Bit based reader for packet headers
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream.reader;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.io.RandomAccessIO;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class provides a bit based reading facility from a byte based one,
|
||||
* applying the bit unstuffing procedure as required by the packet headers.
|
||||
*/
|
||||
class PktHeaderBitReader {
|
||||
|
||||
/**
|
||||
* The byte based source of data
|
||||
*/
|
||||
RandomAccessIO in;
|
||||
|
||||
/**
|
||||
* The byte array that is the source of data if the PktHeaderBitReader
|
||||
* is instantiated with a buffer instead of a RandomAccessIO
|
||||
*/
|
||||
ByteArrayInputStream bais;
|
||||
|
||||
/**
|
||||
* Flag indicating whether the data should be read from the buffer
|
||||
*/
|
||||
boolean usebais;
|
||||
|
||||
/**
|
||||
* The current bit buffer
|
||||
*/
|
||||
int bbuf;
|
||||
|
||||
/**
|
||||
* The position of the next bit to read in the bit buffer (0 means
|
||||
* empty, 8 full)
|
||||
*/
|
||||
int bpos;
|
||||
|
||||
/**
|
||||
* The next bit buffer, if bit stuffing occurred (i.e. current bit
|
||||
* buffer holds 0xFF)
|
||||
*/
|
||||
int nextbbuf;
|
||||
|
||||
/**
|
||||
* Instantiates a 'PktHeaderBitReader' that gets the byte data from the
|
||||
* given source.
|
||||
*
|
||||
* @param in The source of byte data
|
||||
*/
|
||||
PktHeaderBitReader(RandomAccessIO in) {
|
||||
this.in = in;
|
||||
usebais = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a 'PktHeaderBitReader' that gets the byte data from the
|
||||
* given source.
|
||||
*
|
||||
* @param bais The source of byte data
|
||||
*/
|
||||
PktHeaderBitReader(ByteArrayInputStream bais) {
|
||||
this.bais = bais;
|
||||
usebais = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a single bit from the input.
|
||||
*
|
||||
* @return The read bit (0 or 1)
|
||||
* @throws IOException If an I/O error occurred
|
||||
* @throws EOFException If teh end of file has been reached
|
||||
*/
|
||||
final int readBit() throws IOException {
|
||||
if (bpos == 0) { // Is bit buffer empty?
|
||||
if (bbuf != 0xFF) { // No bit stuffing
|
||||
bbuf = usebais ? bais.read() : in.read();
|
||||
bpos = 8;
|
||||
if (bbuf == 0xFF) { // If new bit stuffing get next byte
|
||||
nextbbuf = usebais ? bais.read() : in.read();
|
||||
}
|
||||
} else { // We had bit stuffing, nextbuf can not be 0xFF
|
||||
bbuf = nextbbuf;
|
||||
bpos = 7;
|
||||
}
|
||||
if (bbuf < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
}
|
||||
return (bbuf >> --bpos) & 0x01;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a specified number of bits and returns them in a single
|
||||
* integer. The bits are returned in the 'n' least significant bits of the
|
||||
* returned integer. The maximum number of bits that can be read is 31.
|
||||
*
|
||||
* @param n The number of bits to read
|
||||
* @return The read bits, packed in the 'n' LSBs.
|
||||
* @throws IOException If an I/O error occurred
|
||||
* @throws EOFException If teh end of file has been reached
|
||||
*/
|
||||
final int readBits(int n) throws IOException {
|
||||
int bits; // The read bits
|
||||
|
||||
// Can we get all bits from the bit buffer?
|
||||
if (n <= bpos) {
|
||||
return (bbuf >> (bpos -= n)) & ((1 << n) - 1);
|
||||
} else {
|
||||
// NOTE: The implementation need not be recursive but the not
|
||||
// recursive one exploits a bug in the IBM x86 JIT and caused
|
||||
// incorrect decoding (Diego Santa Cruz).
|
||||
bits = 0;
|
||||
do {
|
||||
// Get all the bits we can from the bit buffer
|
||||
bits <<= bpos;
|
||||
n -= bpos;
|
||||
bits |= readBits(bpos);
|
||||
// Get an extra bit to load next byte (here bpos is 0)
|
||||
if (bbuf != 0xFF) { // No bit stuffing
|
||||
bbuf = usebais ? bais.read() : in.read();
|
||||
bpos = 8;
|
||||
if (bbuf == 0xFF) { // If new bit stuffing get next byte
|
||||
nextbbuf = usebais ? bais.read() : in.read();
|
||||
}
|
||||
} else { // We had bit stuffing, nextbuf can not be 0xFF
|
||||
bbuf = nextbbuf;
|
||||
bpos = 7;
|
||||
}
|
||||
if (bbuf < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
} while (n > bpos);
|
||||
// Get the last bits, if any
|
||||
bits <<= n;
|
||||
bits |= (bbuf >> (bpos -= n)) & ((1 << n) - 1);
|
||||
// Return result
|
||||
return bits;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes this object with the underlying byte based input. It
|
||||
* discards and buffered bits and gets ready to read bits from the current
|
||||
* position in the underlying byte based input.
|
||||
*
|
||||
* <P>This method should always be called when some data has been read
|
||||
* directly from the underlying byte based input since the last call to
|
||||
* 'readBits()' or 'readBit()' before a new call to any of those methods.
|
||||
*/
|
||||
void sync() {
|
||||
bbuf = 0;
|
||||
bpos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the underlying byte based input to the given object. This method
|
||||
* discards any currently buffered bits and gets ready to start reading
|
||||
* bits from 'in'.
|
||||
*
|
||||
* <P>This method is equivalent to creating a new 'PktHeaderBitReader'
|
||||
* object.
|
||||
*
|
||||
* @param in The source of byte data
|
||||
*/
|
||||
void setInput(RandomAccessIO in) {
|
||||
this.in = in;
|
||||
bbuf = 0;
|
||||
bpos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the underlying byte based input to the given object. This method
|
||||
* discards any currently buffered bits and gets ready to start reading
|
||||
* bits from 'in'.
|
||||
*
|
||||
* <P>This method is equivalent to creating a new 'PktHeaderBitReader'
|
||||
* object.
|
||||
*
|
||||
* @param bais The source of byte data
|
||||
*/
|
||||
void setInput(ByteArrayInputStream bais) {
|
||||
this.bais = bais;
|
||||
bbuf = 0;
|
||||
bpos = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* $RCSfile: PktInfo.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:02 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: PktInfo
|
||||
*
|
||||
* Description: Object containing packet informations.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream.reader;
|
||||
|
||||
|
||||
/**
|
||||
* This class defines an object used to countain informations about a packet
|
||||
* to which the current code-block belongs.
|
||||
*
|
||||
* @see CBlkInfo
|
||||
*/
|
||||
public class PktInfo {
|
||||
|
||||
/**
|
||||
* Index of the packet
|
||||
*/
|
||||
public int packetIdx;
|
||||
|
||||
/**
|
||||
* The layer associated with the current code-block in this packet.
|
||||
*/
|
||||
public int layerIdx;
|
||||
|
||||
/**
|
||||
* The code-block offset in the codestream (for this packet)
|
||||
*/
|
||||
public int cbOff = 0;
|
||||
|
||||
/**
|
||||
* The length of the code-block in this packet (in bytes)
|
||||
*/
|
||||
public int cbLength;
|
||||
|
||||
/**
|
||||
* The length of each terminated segment in the packet. The total is the
|
||||
* same as 'cbLength'. It can be null if there is only one terminated
|
||||
* segment, in which case 'cbLength' holds the legth of that segment
|
||||
*/
|
||||
public int[] segLengths;
|
||||
|
||||
/**
|
||||
* The number of truncation points that appear in this packet, and all
|
||||
* previous packets, for this code-block. This is the number of passes
|
||||
* that can be decoded with the information in this packet and all
|
||||
* previous ones.
|
||||
*/
|
||||
public int numTruncPnts;
|
||||
|
||||
/**
|
||||
* Classe's constructor.
|
||||
*
|
||||
* @param lyIdx The layer index for the code-block in this packet
|
||||
* @param pckIdx The packet index
|
||||
*/
|
||||
public PktInfo(int lyIdx, int pckIdx) {
|
||||
layerIdx = lyIdx;
|
||||
packetIdx = pckIdx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Object information in a string.
|
||||
*
|
||||
* @return Object information
|
||||
*/
|
||||
public String toString() {
|
||||
return "packet " + packetIdx + " (lay:" + layerIdx + ", off:" + cbOff + ", len:" +
|
||||
cbLength + ", numTruncPnts:" + numTruncPnts + ")\n";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* $RCSfile: TagTreeDecoder.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:02 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: TagTreeDecoder
|
||||
*
|
||||
* Description: Decoder of tag trees
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream.reader;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.util.ArrayUtil;
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.writer.TagTreeEncoder;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This class implements the tag tree decoder. A tag tree codes a 2D
|
||||
* matrix of integer elements in an efficient way. The decoding
|
||||
* procedure 'update()' updates a value of the matrix from a stream of
|
||||
* coded data, given a threshold. This procedure decodes enough
|
||||
* information to identify whether or not the value is greater than
|
||||
* or equal to the threshold, and updates the value accordingly.
|
||||
*
|
||||
* <P>In general the decoding procedure must follow the same sequence
|
||||
* of elements and thresholds as the encoding one. The encoder is
|
||||
* implemented by the TagTreeEncoder class.
|
||||
*
|
||||
* <P>Tag trees that have one dimension, or both, as 0 are allowed for
|
||||
* convenience. Of course no values can be set or coded in such cases.
|
||||
*
|
||||
* @see TagTreeEncoder
|
||||
*/
|
||||
public class TagTreeDecoder {
|
||||
|
||||
/**
|
||||
* The horizontal dimension of the base level
|
||||
*/
|
||||
protected int w;
|
||||
|
||||
/**
|
||||
* The vertical dimensions of the base level
|
||||
*/
|
||||
protected int h;
|
||||
|
||||
/**
|
||||
* The number of levels in the tag tree
|
||||
*/
|
||||
protected int lvls;
|
||||
|
||||
/**
|
||||
* The tag tree values. The first index is the level,
|
||||
* starting at level 0 (leafs). The second index is the element
|
||||
* within the level, in lexicographical order.
|
||||
*/
|
||||
protected int[][] treeV;
|
||||
|
||||
/**
|
||||
* The tag tree state. The first index is the level, starting at
|
||||
* level 0 (leafs). The second index is the element within the
|
||||
* level, in lexicographical order.
|
||||
*/
|
||||
protected int[][] treeS;
|
||||
|
||||
/**
|
||||
* Creates a tag tree decoder with 'w' elements along the
|
||||
* horizontal dimension and 'h' elements along the vertical
|
||||
* direction. The total number of elements is thus 'vdim' x
|
||||
* 'hdim'.
|
||||
*
|
||||
* <P>The values of all elements are initialized to
|
||||
* Integer.MAX_VALUE (i.e. no information decoded so far). The
|
||||
* states are initialized all to 0.
|
||||
*
|
||||
* @param h The number of elements along the vertical direction.
|
||||
* @param w The number of elements along the horizontal direction.
|
||||
*/
|
||||
public TagTreeDecoder(int h, int w) {
|
||||
int i;
|
||||
|
||||
// Check arguments
|
||||
if (w < 0 || h < 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
// Initialize dimensions
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
// Calculate the number of levels
|
||||
if (w == 0 || h == 0) {
|
||||
lvls = 0; // Empty tree
|
||||
} else {
|
||||
lvls = 1;
|
||||
while (h != 1 || w != 1) { // Loop until we reach root
|
||||
w = (w + 1) >> 1;
|
||||
h = (h + 1) >> 1;
|
||||
lvls++;
|
||||
}
|
||||
}
|
||||
// Allocate tree values and states
|
||||
treeV = new int[lvls][];
|
||||
treeS = new int[lvls][];
|
||||
w = this.w;
|
||||
h = this.h;
|
||||
for (i = 0; i < lvls; i++) {
|
||||
treeV[i] = new int[h * w];
|
||||
// Initialize to infinite value
|
||||
ArrayUtil.intArraySet(treeV[i], Integer.MAX_VALUE);
|
||||
|
||||
// (no need to initialize to 0 since it's the default)
|
||||
treeS[i] = new int[h * w];
|
||||
w = (w + 1) >> 1;
|
||||
h = (h + 1) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of leafs along the horizontal direction.
|
||||
*
|
||||
* @return The number of leafs along the horizontal direction.
|
||||
*/
|
||||
public final int getWidth() {
|
||||
return w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of leafs along the vertical direction.
|
||||
*
|
||||
* @return The number of leafs along the vertical direction.
|
||||
*/
|
||||
public final int getHeight() {
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes information for the specified element of the tree,
|
||||
* given the threshold, and updates its value. The information
|
||||
* that can be decoded is whether or not the value of the element
|
||||
* is greater than, or equal to, the value of the
|
||||
* threshold.
|
||||
*
|
||||
* @param m The vertical index of the element.
|
||||
* @param n The horizontal index of the element.
|
||||
* @param t The threshold to use in decoding. It must be non-negative.
|
||||
* @param in The stream from where to read the coded information.
|
||||
* @return The updated value at position (m,n).
|
||||
* @throws IOException If an I/O error occurs while reading
|
||||
* from 'in'.
|
||||
* @throws EOFException If the ned of the 'in' stream is
|
||||
* reached before getting all the necessary data.
|
||||
*/
|
||||
public int update(int m, int n, int t, PktHeaderBitReader in)
|
||||
throws IOException {
|
||||
int k, tmin;
|
||||
int idx, ts, tv;
|
||||
|
||||
// Check arguments
|
||||
if (m >= h || n >= w || t < 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
// Initialize
|
||||
k = lvls - 1;
|
||||
tmin = treeS[k][0];
|
||||
|
||||
// Loop on levels
|
||||
idx = (m >> k) * ((w + (1 << k) - 1) >> k) + (n >> k);
|
||||
while (true) {
|
||||
// Cache state and value
|
||||
ts = treeS[k][idx];
|
||||
tv = treeV[k][idx];
|
||||
if (ts < tmin) {
|
||||
ts = tmin;
|
||||
}
|
||||
while (t > ts) {
|
||||
if (tv >= ts) { // We are not done yet
|
||||
if (in.readBit() == 0) { // '0' bit
|
||||
// We know that 'value' > treeS[k][idx]
|
||||
ts++;
|
||||
} else { // '1' bit
|
||||
// We know that 'value' = treeS[k][idx]
|
||||
tv = ts++;
|
||||
}
|
||||
// Increment of treeS[k][idx] done above
|
||||
} else { // We are done, we can set ts and get out
|
||||
ts = t;
|
||||
break; // get out of this while
|
||||
}
|
||||
}
|
||||
// Update state and value
|
||||
treeS[k][idx] = ts;
|
||||
treeV[k][idx] = tv;
|
||||
// Update tmin or terminate
|
||||
if (k > 0) {
|
||||
tmin = ts < tv ? ts : tv;
|
||||
k--;
|
||||
// Index of element for next iteration
|
||||
idx = (m >> k) * ((w + (1 << k) - 1) >> k) + (n >> k);
|
||||
} else {
|
||||
// Return the updated value
|
||||
return tv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current value of the specified element in the tag
|
||||
* tree. This is the value as last updated by the update() method.
|
||||
*
|
||||
* @param m The vertical index of the element.
|
||||
* @param n The horizontal index of the element.
|
||||
* @return The current value of the element.
|
||||
* @see #update
|
||||
*/
|
||||
public int getValue(int m, int n) {
|
||||
// Check arguments
|
||||
if (m >= h || n >= w) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
// Return value
|
||||
return treeV[0][m * w + n];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* $RCSfile: BitOutputBuffer.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:02 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: BitOutputBuffer
|
||||
*
|
||||
* Description: <short description of class>
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream.writer;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.util.ArrayUtil;
|
||||
|
||||
/**
|
||||
* This class implements a buffer for writing bits, with the required bit
|
||||
* stuffing policy for the packet headers. The bits are stored in a byte array
|
||||
* in the order in which they are written. The byte array is automatically
|
||||
* reallocated and enlarged whenever necessary. A BitOutputBuffer object may
|
||||
* be reused by calling its 'reset()' method.
|
||||
*
|
||||
* <P>NOTE: The methods implemented in this class are intended to be used only
|
||||
* in writing packet heads, since a special bit stuffing procedure is used, as
|
||||
* required for the packet heads.
|
||||
*/
|
||||
public class BitOutputBuffer {
|
||||
|
||||
/**
|
||||
* The increment size for the buffer, 16 bytes. This is the
|
||||
* number of bytes that are added to the buffer each time it is
|
||||
* needed to enlarge it.
|
||||
*/
|
||||
// This must be always 6 or larger.
|
||||
public final static int SZ_INCR = 16;
|
||||
/**
|
||||
* The initial size for the buffer, 32 bytes.
|
||||
*/
|
||||
public final static int SZ_INIT = 32;
|
||||
/**
|
||||
* The buffer where we store the data
|
||||
*/
|
||||
byte[] buf;
|
||||
/**
|
||||
* The position of the current byte to write
|
||||
*/
|
||||
int curbyte;
|
||||
/**
|
||||
* The number of available bits in the current byte
|
||||
*/
|
||||
int avbits = 8;
|
||||
|
||||
/**
|
||||
* Creates a new BitOutputBuffer width a buffer of length
|
||||
* 'SZ_INIT'.
|
||||
*/
|
||||
public BitOutputBuffer() {
|
||||
buf = new byte[SZ_INIT];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the buffer. This rewinds the current position to the start of
|
||||
* the buffer and sets all tha data to 0. Note that no new buffer is
|
||||
* allocated, so this will affect any data that was returned by the
|
||||
* 'getBuffer()' method.
|
||||
*/
|
||||
public void reset() {
|
||||
int i;
|
||||
// Reinit pointers
|
||||
curbyte = 0;
|
||||
avbits = 8;
|
||||
ArrayUtil.byteArraySet(buf, (byte) 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a bit to the buffer at the current position. The value 'bit'
|
||||
* must be either 0 or 1, otherwise it corrupts the bits that have been
|
||||
* already written. The buffer is enlarged, by 'SZ_INCR' bytes, if
|
||||
* necessary.
|
||||
*
|
||||
* <P>This method is declared final to increase performance.
|
||||
*
|
||||
* @param bit The bit to write, 0 or 1.
|
||||
*/
|
||||
public final void writeBit(int bit) {
|
||||
buf[curbyte] |= bit << --avbits;
|
||||
if (avbits > 0) {
|
||||
// There is still place in current byte for next bit
|
||||
} else { // End of current byte => goto next
|
||||
if (buf[curbyte] != (byte) 0xFF) { // We don't need bit stuffing
|
||||
avbits = 8;
|
||||
} else { // We need to stuff a bit (next MSBit is 0)
|
||||
avbits = 7;
|
||||
}
|
||||
curbyte++;
|
||||
if (curbyte == buf.length) {
|
||||
// We are at end of 'buf' => extend it
|
||||
byte[] oldbuf = buf;
|
||||
buf = new byte[oldbuf.length + SZ_INCR];
|
||||
System.arraycopy(oldbuf, 0, buf, 0, oldbuf.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the n least significant bits of 'bits' to the buffer at the
|
||||
* current position. The least significant bit is written last. The 32-n
|
||||
* most significant bits of 'bits' must be 0, otherwise corruption of the
|
||||
* buffer will result. The buffer is enlarged, by 'SZ_INCR' bytes, if
|
||||
* necessary.
|
||||
*
|
||||
* <P>This method is declared final to increase performance.
|
||||
*
|
||||
* @param bits The bits to write.
|
||||
* @param n The number of LSBs in 'bits' to write.
|
||||
*/
|
||||
public final void writeBits(int bits, int n) {
|
||||
// Check that we have enough place in 'buf' for n bits, and that we do
|
||||
// not fill last byte, taking into account possibly stuffed bits (max
|
||||
// 2)
|
||||
if (((buf.length - curbyte) << 3) - 8 + avbits <= n + 2) {
|
||||
// Not enough place, extend it
|
||||
byte[] oldbuf = buf;
|
||||
buf = new byte[oldbuf.length + SZ_INCR];
|
||||
System.arraycopy(oldbuf, 0, buf, 0, oldbuf.length);
|
||||
// SZ_INCR is always 6 or more, so it is enough to hold all the
|
||||
// new bits plus the ones to come after
|
||||
}
|
||||
// Now write the bits
|
||||
if (n >= avbits) {
|
||||
// Complete the current byte
|
||||
n -= avbits;
|
||||
buf[curbyte] |= bits >> n;
|
||||
if (buf[curbyte] != (byte) 0xFF) { // We don't need bit stuffing
|
||||
avbits = 8;
|
||||
} else { // We need to stuff a bit (next MSBit is 0)
|
||||
avbits = 7;
|
||||
}
|
||||
curbyte++;
|
||||
// Write whole bytes
|
||||
while (n >= avbits) {
|
||||
n -= avbits;
|
||||
buf[curbyte] |= (bits >> n) & (~(1 << avbits));
|
||||
if (buf[curbyte] != (byte) 0xFF) { // We don't need bit
|
||||
// stuffing
|
||||
avbits = 8;
|
||||
} else { // We need to stuff a bit (next MSBit is 0)
|
||||
avbits = 7;
|
||||
}
|
||||
curbyte++;
|
||||
}
|
||||
}
|
||||
// Finish last byte (we know that now n < avbits)
|
||||
if (n > 0) {
|
||||
avbits -= n;
|
||||
buf[curbyte] |= (bits & ((1 << n) - 1)) << avbits;
|
||||
}
|
||||
if (avbits == 0) { // Last byte is full
|
||||
if (buf[curbyte] != (byte) 0xFF) { // We don't need bit stuffing
|
||||
avbits = 8;
|
||||
} else { // We need to stuff a bit (next MSBit is 0)
|
||||
avbits = 7;
|
||||
}
|
||||
curbyte++; // We already ensured that we have enough place
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current length of the buffer, in bytes.
|
||||
*
|
||||
* <P>This method is declared final to increase performance.
|
||||
*
|
||||
* @return The currebt length of the buffer in bytes.
|
||||
*/
|
||||
public final int getLength() {
|
||||
if (avbits == 8) { // A integral number of bytes
|
||||
return curbyte;
|
||||
} else { // Some bits in last byte
|
||||
return curbyte + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte buffer. This is the internal byte buffer so it should
|
||||
* not be modified. Only the first N elements have valid data, where N is
|
||||
* the value returned by 'getLength()'
|
||||
*
|
||||
* <P>This method is declared final to increase performance.
|
||||
*
|
||||
* @return The internal byte buffer.
|
||||
*/
|
||||
public final byte[] getBuffer() {
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte buffer data in a new array. This is a copy of the
|
||||
* internal byte buffer. If 'data' is non-null it is used to return the
|
||||
* data. This array should be large enough to contain all the data,
|
||||
* otherwise a IndexOutOfBoundsException is thrown by the Java system. The
|
||||
* number of elements returned is what 'getLength()' returns.
|
||||
*
|
||||
* @param data If non-null this array is used to return the data, which
|
||||
* mus be large enough. Otherwise a new one is created and returned.
|
||||
* @return The byte buffer data.
|
||||
*/
|
||||
public byte[] toByteArray(byte[] data) {
|
||||
if (data == null) {
|
||||
data = new byte[(avbits == 8) ? curbyte : curbyte + 1];
|
||||
}
|
||||
System.arraycopy(buf, 0, data, 0, (avbits == 8) ? curbyte : curbyte + 1);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints information about this object for debugging purposes
|
||||
*
|
||||
* @return Information about the object.
|
||||
*/
|
||||
public String toString() {
|
||||
return "bits written = " + (curbyte * 8 + (8 - avbits)) +
|
||||
", curbyte = " + curbyte + ", avbits = " + avbits;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* $RCSfile: CodestreamWriter.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:02 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: CodestreamWriter
|
||||
*
|
||||
* Description: Interface for writing bit streams
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream.writer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This is the abstract class for writing to a bit stream. Data is
|
||||
* written in packets, each packet having a head and a body. The
|
||||
* bit stream always has a maximum number of bytes that can be written
|
||||
* to it. After that many number of bytes no more data is written to
|
||||
* the bit stream but the number of bytes is counted so that the value
|
||||
* returned by getMaxAvailableBytes() is negative. If the number of
|
||||
* bytes is unlimited a ridicoulosly large value, such as
|
||||
* Integer.MAX_VALUE, is equivalent.
|
||||
*
|
||||
* <P>Data may be written to the bit stream in sumulation mode. When in
|
||||
* simulation mode no data is written to the bit stream but the
|
||||
* resulting number of bytes is calculated and returned (although it
|
||||
* is not accounted in the bit stream). This can be used in rate
|
||||
* control loops.
|
||||
*
|
||||
* <P>Implementing classes should write the header of the bit stream
|
||||
* before writing any packets. The bit stream header should be written
|
||||
* with the aid of the HeaderEncoder class.
|
||||
*
|
||||
* @see HeaderEncoder
|
||||
*/
|
||||
public abstract class CodestreamWriter {
|
||||
|
||||
/**
|
||||
* The number of bytes already written to the bit stream
|
||||
*/
|
||||
protected int ndata = 0;
|
||||
|
||||
/**
|
||||
* The maximum number of bytes that can be written to the
|
||||
* bit stream
|
||||
*/
|
||||
protected int maxBytes;
|
||||
|
||||
/**
|
||||
* Allocates this object and initializes the maximum numner of
|
||||
* bytes.
|
||||
*
|
||||
* @param mb The maximum number of bytes that can be written to
|
||||
* the bit stream.
|
||||
*/
|
||||
protected CodestreamWriter(int mb) {
|
||||
maxBytes = mb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes remaining available in the bit stream. This
|
||||
* is the maximum allowed number of bytes minus the number of bytes that
|
||||
* have already been written to the bit stream. If more bytes have been
|
||||
* written to the bit stream than the maximum number of allowed bytes,
|
||||
* then a negative value is returned.
|
||||
*
|
||||
* @return The number of bytes remaining available in the bit stream.
|
||||
*/
|
||||
public abstract int getMaxAvailableBytes();
|
||||
|
||||
/**
|
||||
* Returns the current length of the entire bit stream.
|
||||
*
|
||||
* @return the current length of the bit stream
|
||||
*/
|
||||
public abstract int getLength();
|
||||
|
||||
/**
|
||||
* Writes a packet head to the bit stream and returns the number of bytes
|
||||
* used by this header. It returns the total number of bytes that the
|
||||
* packet head takes in the bit stream. If in simulation mode then no data
|
||||
* is written to the bit stream but the number of bytes is
|
||||
* calculated. This can be used for iterative rate allocation.
|
||||
*
|
||||
* <P>If the length of the data that is to be written to the bit stream is
|
||||
* more than the space left (as returned by getMaxAvailableBytes()) only
|
||||
* the data that does not exceed the allowed length is written, the rest
|
||||
* is discarded. However the value returned by the method is the total
|
||||
* length of the packet, as if all of it was written to the bit stream.
|
||||
*
|
||||
* <P>If the bit stream header has not been commited yet and 'sim' is
|
||||
* false, then the bit stream header is automatically commited (see
|
||||
* commitBitstreamHeader() method) before writting the packet.
|
||||
*
|
||||
* @param head The packet head data.
|
||||
* @param hlen The number of bytes in the packet head.
|
||||
* @param sim Simulation mode flag. If true nothing is written to the bit
|
||||
* stream, but the number of bytes that would be written is returned.
|
||||
* @param sop Start of packet header marker flag. This flag indicates
|
||||
* whether or not SOP markers should be written. If true, SOP markers
|
||||
* should be written, if false, they should not.
|
||||
* @param eph End of Packet Header marker flag. This flag indicates
|
||||
* whether or not EPH markers should be written. If true, EPH markers
|
||||
* should be written, if false, they should not.
|
||||
* @return The number of bytes spent by the packet head.
|
||||
* @throws IOException If an I/O error occurs while writing to the
|
||||
* output stream.
|
||||
* @see #commitBitstreamHeader
|
||||
*/
|
||||
public abstract int writePacketHead(byte[] head, int hlen, boolean sim,
|
||||
boolean sop, boolean eph)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a packet body to the bit stream and returns the number of bytes
|
||||
* used by this body .If in simulation mode then no data is written to the
|
||||
* bit stream but the number of bytes is calculated. This can be used for
|
||||
* iterative rate allocation.
|
||||
*
|
||||
* <P>If the length of the data that is to be written to the bit stream is
|
||||
* more than the space left (as returned by getMaxAvailableBytes()) only
|
||||
* the data that does not exceed the allowed length is written, the rest
|
||||
* is discarded. However the value returned by the method is the total
|
||||
* length of the packet body , as if all of it was written to the bit
|
||||
* stream.
|
||||
*
|
||||
* @param body The packet body data.
|
||||
* @param blen The number of bytes in the packet body.
|
||||
* @param sim Simulation mode flag. If true nothing is written to the bit
|
||||
* stream, but the number of bytes that would be written is returned.
|
||||
* @param roiInPkt Whether or not there is ROI information in this packet
|
||||
* @param roiLen Number of byte to read in packet body to get all the ROI
|
||||
* information
|
||||
* @return The number of bytes spent by the packet body.
|
||||
* @throws IOException If an I/O error occurs while writing to
|
||||
* the output stream.
|
||||
* @see #commitBitstreamHeader
|
||||
*/
|
||||
public abstract int writePacketBody(byte[] body, int blen, boolean sim,
|
||||
boolean roiInPkt, int roiLen)
|
||||
throws IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Closes the underlying resource (file, stream, network connection,
|
||||
* etc.). After a CodestreamWriter is closed no more data can be written
|
||||
* to it.
|
||||
*
|
||||
* @throws IOException If an I/O error occurs while closing the
|
||||
* resource.
|
||||
*/
|
||||
public abstract void close() throws IOException;
|
||||
|
||||
/**
|
||||
* Writes the header data to the bit stream, if it has not been already
|
||||
* done. In some implementations this method can be called only once, and
|
||||
* an IllegalArgumentException is thrown if called more than once.
|
||||
*
|
||||
* @throws IOException If an I/O error occurs while writing the data.
|
||||
* @throws IllegalArgumentException If this method has already been
|
||||
* called.
|
||||
*/
|
||||
public abstract void commitBitstreamHeader(HeaderEncoder he)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Gives the offset of the end of last packet containing ROI information
|
||||
*
|
||||
* @return End of last ROI packet
|
||||
*/
|
||||
public abstract int getOffLastROIPkt();
|
||||
}
|
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
* $RCSfile: FileCodestreamWriter.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:02 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: FileCodestreamWriter
|
||||
*
|
||||
* Description: Implementation of the bit stream writer for streams.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream.writer;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.Markers;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* This class implements a CodestreamWriter for Java streams. The streams can
|
||||
* be files or network connections, or any other resource that presents itself
|
||||
* as a OutputStream. See the CodestreamWriter abstract class for more details
|
||||
* on the implementation of the CodestreamWriter abstract class.
|
||||
*
|
||||
* <P>Before any packet data is written to the bit stream (even in simulation
|
||||
* mode) the complete header should be written to the HeaderEncoder object
|
||||
* supplied to the constructor, following the procedure explained in the
|
||||
* HeaderEncoder class. Otherwise incorrect estimates are given by
|
||||
* getMaxAvailableBytes() for rate allocation.
|
||||
*
|
||||
* @see CodestreamWriter
|
||||
* @see HeaderEncoder
|
||||
*/
|
||||
public class FileCodestreamWriter extends CodestreamWriter
|
||||
implements Markers {
|
||||
|
||||
/**
|
||||
* The upper limit for the value of the Nsop field of the SOP marker
|
||||
*/
|
||||
private final static int SOP_MARKER_LIMIT = 65535;
|
||||
/**
|
||||
* The default buffer length, 1024 bytes
|
||||
*/
|
||||
public static int DEF_BUF_LEN = 1024;
|
||||
/**
|
||||
* The number of bytes already written to the bit stream, excluding the
|
||||
* header length, magic number and header length info.
|
||||
*/
|
||||
int ndata = 0;
|
||||
/**
|
||||
* Array used to store the SOP markers values
|
||||
*/
|
||||
byte[] sopMarker;
|
||||
/**
|
||||
* Array used to store the EPH markers values
|
||||
*/
|
||||
byte[] ephMarker;
|
||||
/**
|
||||
* The packet index (when start of packet markers i.e. SOP markers) are
|
||||
* used.
|
||||
*/
|
||||
int packetIdx = 0;
|
||||
/**
|
||||
* Index of the current tile
|
||||
*/
|
||||
private final int tileIdx = 0;
|
||||
/**
|
||||
* The file to write
|
||||
*/
|
||||
private final OutputStream out;
|
||||
/**
|
||||
* Offset of end of last packet containing ROI information
|
||||
*/
|
||||
private int offLastROIPkt = 0;
|
||||
|
||||
/**
|
||||
* Length of last packets containing no ROI information
|
||||
*/
|
||||
private int lenLastNoROI = 0;
|
||||
|
||||
/**
|
||||
* Opens the file 'file' for writing the bit stream, using the 'he' header
|
||||
* encoder. The magic number is written to the bit stream. Normally, the
|
||||
* header encoder must be empty (i.e. no data has been written to it
|
||||
* yet). A BufferedOutputStream is used on top of the file to increase
|
||||
* throughput, the length of the buffer is DEF_BUF_LEN.
|
||||
*
|
||||
* @param file The file where to write the bit stream
|
||||
* @param mb The maximum number of bytes that can be written to the bit
|
||||
* stream.
|
||||
* @throws IOException If an error occurs while trying to open the file
|
||||
* for writing or while writing the magic number.
|
||||
*/
|
||||
public FileCodestreamWriter(File file, int mb)
|
||||
throws IOException {
|
||||
|
||||
super(mb);
|
||||
out = new BufferedOutputStream(new FileOutputStream(file), DEF_BUF_LEN);
|
||||
initSOP_EPHArrays();
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the file named 'fname' for writing the bit stream, using the 'he'
|
||||
* header encoder. The magic number is written to the bit
|
||||
* stream. Normally, the header encoder must be empty (i.e. no data has
|
||||
* been written to it yet). A BufferedOutputStream is used on top of the
|
||||
* file to increase throughput, the length of the buffer is DEF_BUF_LEN.
|
||||
*
|
||||
* @param fname The name of file where to write the bit stream
|
||||
* @param mb The maximum number of bytes that can be written to the bit
|
||||
* stream.
|
||||
* @throws IOException If an error occurs while trying to open the file
|
||||
* for writing or while writing the magic number.
|
||||
*/
|
||||
public FileCodestreamWriter(String fname, int mb)
|
||||
throws IOException {
|
||||
|
||||
super(mb);
|
||||
out = new BufferedOutputStream(new FileOutputStream(fname),
|
||||
DEF_BUF_LEN);
|
||||
initSOP_EPHArrays();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the output stream 'os' for writing the bit stream, using the 'he'
|
||||
* header encoder. The magic number is written to the bit
|
||||
* stream. Normally, the header encoder must be empty (i.e. no data has
|
||||
* been written to it yet). No BufferedOutputStream is used on top of the
|
||||
* output stream 'os'.
|
||||
*
|
||||
* @param os The output stream where to write the bit stream.
|
||||
* @param mb The maximum number of bytes that can be written to the bit
|
||||
* stream.
|
||||
* @throws IOException If an error occurs while writing the magic
|
||||
* number to the 'os' output stream.
|
||||
*/
|
||||
public FileCodestreamWriter(OutputStream os, int mb)
|
||||
throws IOException {
|
||||
|
||||
super(mb);
|
||||
out = os;
|
||||
initSOP_EPHArrays();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes remaining available in the bit stream. This
|
||||
* is the maximum allowed number of bytes minus the number of bytes that
|
||||
* have already been written to the bit stream. If more bytes have been
|
||||
* written to the bit stream than the maximum number of allowed bytes,
|
||||
* then a negative value is returned.
|
||||
*
|
||||
* @return The number of bytes remaining available in the bit stream.
|
||||
*/
|
||||
public final int getMaxAvailableBytes() {
|
||||
return maxBytes - ndata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current length of the entire bit stream.
|
||||
*
|
||||
* @return the current length of the bit stream
|
||||
*/
|
||||
public int getLength() {
|
||||
if (getMaxAvailableBytes() >= 0) {
|
||||
return ndata;
|
||||
} else {
|
||||
return maxBytes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a packet head to the bit stream and returns the number of bytes
|
||||
* used by this header. It returns the total number of bytes that the
|
||||
* packet head takes in the bit stream. If in simulation mode then no data
|
||||
* is written to the bit stream but the number of bytes is
|
||||
* calculated. This can be used for iterative rate allocation.
|
||||
*
|
||||
* <P>If the length of the data that is to be written to the bit stream is
|
||||
* more than the space left (as returned by getMaxAvailableBytes()) only
|
||||
* the data that does not exceed the allowed length is written, the rest
|
||||
* is discarded. However the value returned by the method is the total
|
||||
* length of the packet, as if all of it was written to the bit stream.
|
||||
*
|
||||
* <P>If the bit stream header has not been commited yet and 'sim' is
|
||||
* false, then the bit stream header is automatically commited (see
|
||||
* commitBitstreamHeader() method) before writting the packet.
|
||||
*
|
||||
* @param head The packet head data.
|
||||
* @param hlen The number of bytes in the packet head.
|
||||
* @param sim Simulation mode flag. If true nothing is written to the bit
|
||||
* stream, but the number of bytes that would be written is returned.
|
||||
* @param sop Start of packet header marker flag. This flag indicates
|
||||
* whether or not SOP markers should be written. If true, SOP markers
|
||||
* should be written, if false, they should not.
|
||||
* @param eph End of Packet Header marker flag. This flag indicates
|
||||
* whether or not EPH markers should be written. If true, EPH markers
|
||||
* should be written, if false, they should not.
|
||||
* @return The number of bytes spent by the packet head.
|
||||
* @throws IOException If an I/O error occurs while writing to the
|
||||
* output stream.
|
||||
* @see #commitBitstreamHeader
|
||||
*/
|
||||
public int writePacketHead(byte[] head, int hlen, boolean sim,
|
||||
boolean sop, boolean eph) throws IOException {
|
||||
int len = hlen
|
||||
+ (sop ? Markers.SOP_LENGTH : 0)
|
||||
+ (eph ? Markers.EPH_LENGTH : 0);
|
||||
|
||||
// If not in simulation mode write the data
|
||||
if (!sim) {
|
||||
// Write the head bytes
|
||||
if (getMaxAvailableBytes() < len) {
|
||||
len = getMaxAvailableBytes();
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
// Write Start Of Packet header markers if necessary
|
||||
if (sop) {
|
||||
// The first 4 bytes of the array have been filled in the
|
||||
// classe's constructor.
|
||||
sopMarker[4] = (byte) (packetIdx >> 8);
|
||||
sopMarker[5] = (byte) (packetIdx);
|
||||
out.write(sopMarker, 0, Markers.SOP_LENGTH);
|
||||
packetIdx++;
|
||||
if (packetIdx > SOP_MARKER_LIMIT) {
|
||||
// Reset SOP value as we have reached its upper limit
|
||||
packetIdx = 0;
|
||||
}
|
||||
}
|
||||
out.write(head, 0, hlen);
|
||||
// Update data length
|
||||
ndata += len;
|
||||
|
||||
// Write End of Packet Header markers if necessary
|
||||
if (eph) {
|
||||
out.write(ephMarker, 0, Markers.EPH_LENGTH);
|
||||
}
|
||||
|
||||
// Deal with ROI Information
|
||||
lenLastNoROI += len;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a packet body to the bit stream and returns the number of bytes
|
||||
* used by this body .If in simulation mode then no data is written to the
|
||||
* bit stream but the number of bytes is calculated. This can be used for
|
||||
* iterative rate allocation.
|
||||
*
|
||||
* <P>If the length of the data that is to be written to the bit stream is
|
||||
* more than the space left (as returned by getMaxAvailableBytes()) only
|
||||
* the data that does not exceed the allowed length is written, the rest
|
||||
* is discarded. However the value returned by the method is the total
|
||||
* length of the packet body , as if all of it was written to the bit
|
||||
* stream.
|
||||
*
|
||||
* @param body The packet body data.
|
||||
* @param blen The number of bytes in the packet body.
|
||||
* @param sim Simulation mode flag. If true nothing is written to the bit
|
||||
* stream, but the number of bytes that would be written is returned.
|
||||
* @param roiInPkt Whether or not this packet contains ROI information
|
||||
* @param roiLen Number of byte to read in packet body to get all the ROI
|
||||
* information
|
||||
* @return The number of bytes spent by the packet body.
|
||||
* @throws IOException If an I/O error occurs while writing to the
|
||||
* output stream.
|
||||
* @see #commitBitstreamHeader
|
||||
*/
|
||||
public int writePacketBody(byte[] body, int blen, boolean sim,
|
||||
boolean roiInPkt, int roiLen)
|
||||
throws IOException {
|
||||
|
||||
int len = blen;
|
||||
|
||||
// If not in simulation mode write the data
|
||||
if (!sim) {
|
||||
// Write the body bytes
|
||||
len = blen;
|
||||
if (getMaxAvailableBytes() < len) {
|
||||
len = getMaxAvailableBytes();
|
||||
}
|
||||
if (blen > 0) {
|
||||
out.write(body, 0, len);
|
||||
}
|
||||
// Update data length
|
||||
ndata += len;
|
||||
|
||||
// Deal with ROI information
|
||||
if (roiInPkt) {
|
||||
offLastROIPkt += lenLastNoROI + roiLen;
|
||||
lenLastNoROI = len - roiLen;
|
||||
} else {
|
||||
lenLastNoROI += len;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the EOC marker and closes the underlying stream.
|
||||
*
|
||||
* @throws IOException If an error occurs while closing the underlying
|
||||
* stream.
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
|
||||
// Write the EOC marker and close the codestream.
|
||||
out.write(EOC >> 8);
|
||||
out.write(EOC);
|
||||
|
||||
ndata += 2; // Add two to length of codestream for EOC marker
|
||||
|
||||
out.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives the offset of the end of last packet containing ROI information
|
||||
*
|
||||
* @return End of last ROI packet
|
||||
*/
|
||||
public int getOffLastROIPkt() {
|
||||
return offLastROIPkt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the header data in the codestream and actualize ndata with the
|
||||
* header length. The header is either a MainHeaderEncoder or a
|
||||
* TileHeaderEncoder.
|
||||
*
|
||||
* @param he The current header encoder.
|
||||
* @throws IOException If an I/O error occurs while writing the data.
|
||||
*/
|
||||
public void commitBitstreamHeader(HeaderEncoder he) throws IOException {
|
||||
// Actualize ndata
|
||||
ndata += he.getLength();
|
||||
he.writeTo(out); // Write the header
|
||||
// Reset packet index used for SOP markers
|
||||
packetIdx = 0;
|
||||
|
||||
// Deal with ROI information
|
||||
lenLastNoROI += he.getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the initialisation of the arrays that are used to store the
|
||||
* values used to write SOP and EPH markers
|
||||
*/
|
||||
private void initSOP_EPHArrays() {
|
||||
|
||||
// Allocate and set first values of SOP marker as they will not be
|
||||
// modified
|
||||
sopMarker = new byte[Markers.SOP_LENGTH];
|
||||
sopMarker[0] = (byte) (Markers.SOP >> 8);
|
||||
sopMarker[1] = (byte) Markers.SOP;
|
||||
sopMarker[2] = (byte) 0x00;
|
||||
sopMarker[3] = (byte) 0x04;
|
||||
|
||||
// Allocate and set values of EPH marker as they will not be
|
||||
// modified
|
||||
ephMarker = new byte[Markers.EPH_LENGTH];
|
||||
ephMarker[0] = (byte) (Markers.EPH >> 8);
|
||||
ephMarker[1] = (byte) Markers.EPH;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,518 @@
|
|||
/*
|
||||
* $RCSfile: TagTreeEncoder.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:03 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: TagTreeEncoder
|
||||
*
|
||||
* Description: Encoder of tag trees
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.xbib.graphics.jpeg2000.j2k.codestream.writer;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.util.ArrayUtil;
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.reader.TagTreeDecoder;
|
||||
|
||||
/**
|
||||
* This class implements the tag tree encoder. A tag tree codes a 2D
|
||||
* matrix of integer elements in an efficient way. The encoding
|
||||
* procedure 'encode()' codes information about a value of the matrix,
|
||||
* given a threshold. The procedure encodes the sufficient information
|
||||
* to identify whether or not the value is greater than or equal to
|
||||
* the threshold.
|
||||
*
|
||||
* <P>The tag tree saves encoded information to a BitOutputBuffer.
|
||||
*
|
||||
* <P>A particular and useful property of tag trees is that it is
|
||||
* possible to change a value of the matrix, provided both new and old
|
||||
* values of the element are both greater than or equal to the largest
|
||||
* threshold which has yet been supplied to the coding procedure
|
||||
* 'encode()'. This property can be exploited through the 'setValue()'
|
||||
* method.
|
||||
*
|
||||
* <P>This class allows saving the state of the tree at any point and
|
||||
* restoring it at a later time, by calling save() and restore().
|
||||
*
|
||||
* <P>A tag tree can also be reused, or restarted, if one of the
|
||||
* reset() methods is called.
|
||||
*
|
||||
* <P>The TagTreeDecoder class implements the tag tree decoder.
|
||||
*
|
||||
* <P>Tag trees that have one dimension, or both, as 0 are allowed for
|
||||
* convenience. Of course no values can be set or coded in such cases.
|
||||
*
|
||||
* @see BitOutputBuffer
|
||||
* @see TagTreeDecoder
|
||||
*/
|
||||
public class TagTreeEncoder {
|
||||
|
||||
/**
|
||||
* The horizontal dimension of the base level
|
||||
*/
|
||||
protected int w;
|
||||
|
||||
/**
|
||||
* The vertical dimensions of the base level
|
||||
*/
|
||||
protected int h;
|
||||
|
||||
/**
|
||||
* The number of levels in the tag tree
|
||||
*/
|
||||
protected int lvls;
|
||||
|
||||
/**
|
||||
* The tag tree values. The first index is the level, starting at
|
||||
* level 0 (leafs). The second index is the element within the
|
||||
* level, in lexicographical order.
|
||||
*/
|
||||
protected int[][] treeV;
|
||||
|
||||
/**
|
||||
* The tag tree state. The first index is the level, starting at
|
||||
* level 0 (leafs). The second index is the element within the
|
||||
* level, in lexicographical order.
|
||||
*/
|
||||
protected int[][] treeS;
|
||||
|
||||
/**
|
||||
* The saved tag tree values. The first index is the level,
|
||||
* starting at level 0 (leafs). The second index is the element
|
||||
* within the level, in lexicographical order.
|
||||
*/
|
||||
protected int[][] treeVbak;
|
||||
|
||||
/**
|
||||
* The saved tag tree state. The first index is the level, starting at
|
||||
* level 0 (leafs). The second index is the element within the
|
||||
* level, in lexicographical order.
|
||||
*/
|
||||
protected int[][] treeSbak;
|
||||
|
||||
/**
|
||||
* The saved state. If true the values and states of the tree
|
||||
* have been saved since the creation or last reset.
|
||||
*/
|
||||
protected boolean saved;
|
||||
|
||||
/**
|
||||
* Creates a tag tree encoder with 'w' elements along the
|
||||
* horizontal dimension and 'h' elements along the vertical
|
||||
* direction. The total number of elements is thus 'vdim' x
|
||||
* 'hdim'.
|
||||
*
|
||||
* <P>The values of all elements are initialized to Integer.MAX_VALUE.
|
||||
*
|
||||
* @param h The number of elements along the horizontal direction.
|
||||
* @param w The number of elements along the vertical direction.
|
||||
*/
|
||||
public TagTreeEncoder(int h, int w) {
|
||||
int k;
|
||||
// Check arguments
|
||||
if (w < 0 || h < 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
// Initialize elements
|
||||
init(w, h);
|
||||
// Set values to max
|
||||
for (k = treeV.length - 1; k >= 0; k--) {
|
||||
ArrayUtil.intArraySet(treeV[k], Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a tag tree encoder with 'w' elements along the
|
||||
* horizontal dimension and 'h' elements along the vertical
|
||||
* direction. The total number of elements is thus 'vdim' x
|
||||
* 'hdim'. The values of the leafs in the tag tree are initialized
|
||||
* to the values of the 'val' array.
|
||||
*
|
||||
* <P>The values in the 'val' array are supposed to appear in
|
||||
* lexicographical order, starting at index 0.
|
||||
*
|
||||
* @param h The number of elements along the horizontal direction.
|
||||
* @param w The number of elements along the vertical direction.
|
||||
* @param val The values with which initialize the leafs of the
|
||||
* tag tree.
|
||||
*/
|
||||
public TagTreeEncoder(int h, int w, int[] val) {
|
||||
int k;
|
||||
// Check arguments
|
||||
if (w < 0 || h < 0 || val.length < w * h) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
// Initialize elements
|
||||
init(w, h);
|
||||
// Update leaf values
|
||||
for (k = w * h - 1; k >= 0; k--) {
|
||||
treeV[0][k] = val[k];
|
||||
}
|
||||
// Calculate values at other levels
|
||||
recalcTreeV();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of leafs along the horizontal direction.
|
||||
*
|
||||
* @return The number of leafs along the horizontal direction.
|
||||
*/
|
||||
public final int getWidth() {
|
||||
return w;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of leafs along the vertical direction.
|
||||
*
|
||||
* @return The number of leafs along the vertical direction.
|
||||
*/
|
||||
public final int getHeight() {
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the variables of this class, given the dimensions
|
||||
* at the base level (leaf level). All the state ('treeS' array)
|
||||
* and values ('treeV' array) are intialized to 0. This method is
|
||||
* called by the constructors.
|
||||
*
|
||||
* @param w The number of elements along the vertical direction.
|
||||
* @param h The number of elements along the horizontal direction.
|
||||
*/
|
||||
private void init(int w, int h) {
|
||||
int i;
|
||||
// Initialize dimensions
|
||||
this.w = w;
|
||||
this.h = h;
|
||||
// Calculate the number of levels
|
||||
if (w == 0 || h == 0) {
|
||||
lvls = 0;
|
||||
} else {
|
||||
lvls = 1;
|
||||
while (h != 1 || w != 1) { // Loop until we reach root
|
||||
w = (w + 1) >> 1;
|
||||
h = (h + 1) >> 1;
|
||||
lvls++;
|
||||
}
|
||||
}
|
||||
// Allocate tree values and states
|
||||
// (no need to initialize to 0 since it's the default)
|
||||
treeV = new int[lvls][];
|
||||
treeS = new int[lvls][];
|
||||
w = this.w;
|
||||
h = this.h;
|
||||
for (i = 0; i < lvls; i++) {
|
||||
treeV[i] = new int[h * w];
|
||||
treeS[i] = new int[h * w];
|
||||
w = (w + 1) >> 1;
|
||||
h = (h + 1) >> 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculates the values of the elements in the tag tree, in
|
||||
* levels 1 and up, based on the values of the leafs (level 0).
|
||||
*/
|
||||
private void recalcTreeV() {
|
||||
int m, n, bi, lw, tm1, tm2, lh, k;
|
||||
// Loop on all other levels, updating minimum
|
||||
for (k = 0; k < lvls - 1; k++) {
|
||||
// Visit all elements in level
|
||||
lw = (w + (1 << k) - 1) >> k;
|
||||
lh = (h + (1 << k) - 1) >> k;
|
||||
for (m = ((lh >> 1) << 1) - 2; m >= 0; m -= 2) { // All quads with 2 lines
|
||||
for (n = ((lw >> 1) << 1) - 2; n >= 0; n -= 2) { // All quads with 2 columns
|
||||
// Take minimum of 4 elements and put it in higher
|
||||
// level
|
||||
bi = m * lw + n;
|
||||
tm1 = (treeV[k][bi] < treeV[k][bi + 1]) ?
|
||||
treeV[k][bi] : treeV[k][bi + 1];
|
||||
tm2 = (treeV[k][bi + lw] < treeV[k][bi + lw + 1]) ?
|
||||
treeV[k][bi + lw] : treeV[k][bi + lw + 1];
|
||||
treeV[k + 1][(m >> 1) * ((lw + 1) >> 1) + (n >> 1)] =
|
||||
tm1 < tm2 ? tm1 : tm2;
|
||||
}
|
||||
// Now we may have quad with 1 column, 2 lines
|
||||
if (lw % 2 != 0) {
|
||||
n = ((lw >> 1) << 1);
|
||||
// Take minimum of 2 elements and put it in higher
|
||||
// level
|
||||
bi = m * lw + n;
|
||||
treeV[k + 1][(m >> 1) * ((lw + 1) >> 1) + (n >> 1)] =
|
||||
(treeV[k][bi] < treeV[k][bi + lw]) ?
|
||||
treeV[k][bi] : treeV[k][bi + lw];
|
||||
}
|
||||
}
|
||||
// Now we may have quads with 1 line, 2 or 1 columns
|
||||
if (lh % 2 != 0) {
|
||||
m = ((lh >> 1) << 1);
|
||||
for (n = ((lw >> 1) << 1) - 2; n >= 0; n -= 2) { // All quads with 2 columns
|
||||
// Take minimum of 2 elements and put it in higher
|
||||
// level
|
||||
bi = m * lw + n;
|
||||
treeV[k + 1][(m >> 1) * ((lw + 1) >> 1) + (n >> 1)] =
|
||||
(treeV[k][bi] < treeV[k][bi + 1]) ?
|
||||
treeV[k][bi] : treeV[k][bi + 1];
|
||||
}
|
||||
// Now we may have quad with 1 column, 1 line
|
||||
if (lw % 2 != 0) {
|
||||
// Just copy the value
|
||||
n = ((lw >> 1) << 1);
|
||||
treeV[k + 1][(m >> 1) * ((lw + 1) >> 1) + (n >> 1)] =
|
||||
treeV[k][m * lw + n];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the value of a leaf in the tag tree. The new and old
|
||||
* values of the element must be not smaller than the largest
|
||||
* threshold which has yet been supplied to 'encode()'.
|
||||
*
|
||||
* @param m The vertical index of the element.
|
||||
* @param n The horizontal index of the element.
|
||||
* @param v The new value of the element.
|
||||
*/
|
||||
public void setValue(int m, int n, int v) {
|
||||
int k, idx;
|
||||
// Check arguments
|
||||
if (lvls == 0 || n < 0 || n >= w || v < treeS[lvls - 1][0] ||
|
||||
treeV[0][m * w + n] < treeS[lvls - 1][0]) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
// Update the leaf value
|
||||
treeV[0][m * w + n] = v;
|
||||
// Update all parents
|
||||
for (k = 1; k < lvls; k++) {
|
||||
idx = (m >> k) * ((w + (1 << k) - 1) >> k) + (n >> k);
|
||||
if (v < treeV[k][idx]) {
|
||||
// We need to update minimum and continue checking
|
||||
// in higher levels
|
||||
treeV[k][idx] = v;
|
||||
} else {
|
||||
// We are done: v is equal or less to minimum
|
||||
// in this level, no other minimums to update.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the values of the leafs to the new set of values and
|
||||
* updates the tag tree accordingly. No leaf can change its value
|
||||
* if either the new or old value is smaller than largest
|
||||
* threshold which has yet been supplied to 'encode()'. However
|
||||
* such a leaf can keep its old value (i.e. new and old value must
|
||||
* be identical.
|
||||
*
|
||||
* <P>This method is more efficient than the setValue() method if
|
||||
* a large proportion of the leafs change their value. Note that
|
||||
* for leafs which don't have their value defined yet the value
|
||||
* should be Integer.MAX_VALUE (which is the default
|
||||
* initialization value).
|
||||
*
|
||||
* @param val The new values for the leafs, in lexicographical order.
|
||||
* @see #setValue
|
||||
*/
|
||||
public void setValues(int[] val) {
|
||||
int i, maxt;
|
||||
if (lvls == 0) { // Can't set values on empty tree
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
// Check the values
|
||||
maxt = treeS[lvls - 1][0];
|
||||
for (i = w * h - 1; i >= 0; i--) {
|
||||
if ((treeV[0][i] < maxt || val[i] < maxt) &&
|
||||
treeV[0][i] != val[i]) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
// Update leaf value
|
||||
treeV[0][i] = val[i];
|
||||
}
|
||||
// Recalculate tree at other levels
|
||||
recalcTreeV();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes information for the specified element of the tree,
|
||||
* given the threshold and sends it to the 'out' stream. The
|
||||
* information that is coded is whether or not the value of the
|
||||
* element is greater than or equal to the value of the threshold.
|
||||
*
|
||||
* @param m The vertical index of the element.
|
||||
* @param n The horizontal index of the element.
|
||||
* @param t The threshold to use for encoding. It must be non-negative.
|
||||
* @param out The stream where to write the coded information.
|
||||
*/
|
||||
public void encode(int m, int n, int t, BitOutputBuffer out) {
|
||||
int k, ts, idx, tmin;
|
||||
|
||||
// Check arguments
|
||||
if (m >= h || n >= w || t < 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
// Initialize
|
||||
k = lvls - 1;
|
||||
tmin = treeS[k][0];
|
||||
|
||||
// Loop on levels
|
||||
while (true) {
|
||||
// Index of element in level 'k'
|
||||
idx = (m >> k) * ((w + (1 << k) - 1) >> k) + (n >> k);
|
||||
// Cache state
|
||||
ts = treeS[k][idx];
|
||||
if (ts < tmin) {
|
||||
ts = tmin;
|
||||
}
|
||||
while (t > ts) {
|
||||
if (treeV[k][idx] > ts) {
|
||||
out.writeBit(0); // Send '0' bit
|
||||
} else if (treeV[k][idx] == ts) {
|
||||
out.writeBit(1); // Send '1' bit
|
||||
} else { // we are done: set ts and get out of this while
|
||||
ts = t;
|
||||
break;
|
||||
}
|
||||
// Increment of treeS[k][idx]
|
||||
ts++;
|
||||
}
|
||||
// Update state
|
||||
treeS[k][idx] = ts;
|
||||
// Update tmin or terminate
|
||||
if (k > 0) {
|
||||
tmin = ts < treeV[k][idx] ? ts : treeV[k][idx];
|
||||
k--;
|
||||
} else {
|
||||
// Terminate
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current values and state of the tree. Calling
|
||||
* restore() restores the tag tree the saved state.
|
||||
*
|
||||
* @see #restore
|
||||
*/
|
||||
public void save() {
|
||||
int k, i;
|
||||
|
||||
if (treeVbak == null) { // Nothing saved yet
|
||||
// Allocate saved arrays
|
||||
// treeV and treeS have the same dimensions
|
||||
treeVbak = new int[lvls][];
|
||||
treeSbak = new int[lvls][];
|
||||
for (k = lvls - 1; k >= 0; k--) {
|
||||
treeVbak[k] = new int[treeV[k].length];
|
||||
treeSbak[k] = new int[treeV[k].length];
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the arrays
|
||||
for (k = treeV.length - 1; k >= 0; k--) {
|
||||
System.arraycopy(treeV[k], 0, treeVbak[k], 0, treeV[k].length);
|
||||
System.arraycopy(treeS[k], 0, treeSbak[k], 0, treeS[k].length);
|
||||
}
|
||||
|
||||
// Set saved state
|
||||
saved = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the saved values and state of the tree. An
|
||||
* IllegalArgumentException is thrown if the tree values and state
|
||||
* have not been saved yet.
|
||||
*
|
||||
* @see #save
|
||||
*/
|
||||
public void restore() {
|
||||
int k, i;
|
||||
|
||||
if (!saved) { // Nothing saved yet
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
// Copy the arrays
|
||||
for (k = lvls - 1; k >= 0; k--) {
|
||||
System.arraycopy(treeVbak[k], 0, treeV[k], 0, treeV[k].length);
|
||||
System.arraycopy(treeSbak[k], 0, treeS[k], 0, treeS[k].length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the tree values and state. All the values are set to
|
||||
* Integer.MAX_VALUE and the states to 0.
|
||||
*/
|
||||
public void reset() {
|
||||
int k;
|
||||
// Set all values to Integer.MAX_VALUE
|
||||
// and states to 0
|
||||
for (k = lvls - 1; k >= 0; k--) {
|
||||
ArrayUtil.intArraySet(treeV[k], Integer.MAX_VALUE);
|
||||
ArrayUtil.intArraySet(treeS[k], 0);
|
||||
}
|
||||
// Invalidate saved tree
|
||||
saved = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the tree values and state. The values are set to the
|
||||
* values in 'val'. The states are all set to 0.
|
||||
*
|
||||
* @param val The new values for the leafs, in lexicographical order.
|
||||
*/
|
||||
public void reset(int[] val) {
|
||||
int k;
|
||||
// Set values for leaf level
|
||||
for (k = w * h - 1; k >= 0; k--) {
|
||||
treeV[0][k] = val[k];
|
||||
}
|
||||
// Calculate values at other levels
|
||||
recalcTreeV();
|
||||
// Set all states to 0
|
||||
for (k = lvls - 1; k >= 0; k--) {
|
||||
ArrayUtil.intArraySet(treeS[k], 0);
|
||||
}
|
||||
// Invalidate saved tree
|
||||
saved = false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* $RCSfile: DecoderSpecs.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:03 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: DecoderSpecs
|
||||
*
|
||||
* Description: Hold all decoder specifications
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.decoder;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.IntegerSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.ModuleSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.CBlkSizeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.PrecinctSizeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.image.CompTransfSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.GuardBitsSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.QuantStepSizeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.QuantTypeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.roi.MaxShiftSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.synthesis.SynWTFilterSpec;
|
||||
|
||||
/**
|
||||
* This class holds references to each module specifications used in the
|
||||
* decoding chain. This avoid big amount of arguments in method calls. A
|
||||
* specification contains values of each tile-component for one module. All
|
||||
* members must be instance of ModuleSpec class (or its children).
|
||||
*
|
||||
* @see ModuleSpec
|
||||
*/
|
||||
public class DecoderSpecs implements Cloneable {
|
||||
|
||||
/**
|
||||
* ICC Profiling specifications
|
||||
*/
|
||||
public ModuleSpec iccs;
|
||||
|
||||
/**
|
||||
* ROI maxshift value specifications
|
||||
*/
|
||||
public MaxShiftSpec rois;
|
||||
|
||||
/**
|
||||
* Quantization type specifications
|
||||
*/
|
||||
public QuantTypeSpec qts;
|
||||
|
||||
/**
|
||||
* Quantization normalized base step size specifications
|
||||
*/
|
||||
public QuantStepSizeSpec qsss;
|
||||
|
||||
/**
|
||||
* Number of guard bits specifications
|
||||
*/
|
||||
public GuardBitsSpec gbs;
|
||||
|
||||
/**
|
||||
* Analysis wavelet filters specifications
|
||||
*/
|
||||
public SynWTFilterSpec wfs;
|
||||
|
||||
/**
|
||||
* Number of decomposition levels specifications
|
||||
*/
|
||||
public IntegerSpec dls;
|
||||
|
||||
/**
|
||||
* Number of layers specifications
|
||||
*/
|
||||
public IntegerSpec nls;
|
||||
|
||||
/**
|
||||
* Progression order specifications
|
||||
*/
|
||||
public IntegerSpec pos;
|
||||
|
||||
/**
|
||||
* The Entropy decoder options specifications
|
||||
*/
|
||||
public ModuleSpec ecopts;
|
||||
|
||||
/**
|
||||
* The component transformation specifications
|
||||
*/
|
||||
public CompTransfSpec cts;
|
||||
|
||||
/**
|
||||
* The progression changes specifications
|
||||
*/
|
||||
public ModuleSpec pcs;
|
||||
|
||||
/**
|
||||
* The error resilience specifications concerning the entropy
|
||||
* decoder
|
||||
*/
|
||||
public ModuleSpec ers;
|
||||
|
||||
/**
|
||||
* Precinct partition specifications
|
||||
*/
|
||||
public PrecinctSizeSpec pss;
|
||||
|
||||
/**
|
||||
* The Start Of Packet (SOP) markers specifications
|
||||
*/
|
||||
public ModuleSpec sops;
|
||||
|
||||
/**
|
||||
* The End of Packet Headers (EPH) markers specifications
|
||||
*/
|
||||
public ModuleSpec ephs;
|
||||
|
||||
/**
|
||||
* Code-blocks sizes specification
|
||||
*/
|
||||
public CBlkSizeSpec cblks;
|
||||
|
||||
/**
|
||||
* Packed packet header specifications
|
||||
*/
|
||||
public ModuleSpec pphs;
|
||||
|
||||
/**
|
||||
* Initialize all members with the given number of tiles and components.
|
||||
*
|
||||
* @param nt Number of tiles
|
||||
* @param nc Number of components
|
||||
*/
|
||||
public DecoderSpecs(int nt, int nc) {
|
||||
// Quantization
|
||||
qts = new QuantTypeSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE_COMP);
|
||||
qsss = new QuantStepSizeSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE_COMP);
|
||||
gbs = new GuardBitsSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE_COMP);
|
||||
|
||||
// Wavelet transform
|
||||
wfs = new SynWTFilterSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE_COMP);
|
||||
dls = new IntegerSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE_COMP);
|
||||
|
||||
// Component transformation
|
||||
cts = new CompTransfSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE_COMP);
|
||||
|
||||
// Entropy decoder
|
||||
ecopts = new ModuleSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE_COMP);
|
||||
ers = new ModuleSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE_COMP);
|
||||
cblks = new CBlkSizeSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE_COMP);
|
||||
|
||||
// Precinct partition
|
||||
pss = new PrecinctSizeSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE_COMP, dls);
|
||||
|
||||
// Codestream
|
||||
nls = new IntegerSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE);
|
||||
pos = new IntegerSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE);
|
||||
pcs = new ModuleSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE);
|
||||
sops = new ModuleSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE);
|
||||
ephs = new ModuleSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE);
|
||||
pphs = new ModuleSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE);
|
||||
iccs = new ModuleSpec(nt, nc, ModuleSpec.SPEC_TYPE_TILE);
|
||||
pphs.setDefault(Boolean.FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the current object.
|
||||
*/
|
||||
public DecoderSpecs getCopy() {
|
||||
DecoderSpecs decSpec2;
|
||||
try {
|
||||
decSpec2 = (DecoderSpecs) this.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new Error("Cannot clone the DecoderSpecs instance");
|
||||
}
|
||||
// Quantization
|
||||
decSpec2.qts = (QuantTypeSpec) qts.getCopy();
|
||||
decSpec2.qsss = (QuantStepSizeSpec) qsss.getCopy();
|
||||
decSpec2.gbs = (GuardBitsSpec) gbs.getCopy();
|
||||
// Wavelet transform
|
||||
decSpec2.wfs = (SynWTFilterSpec) wfs.getCopy();
|
||||
decSpec2.dls = (IntegerSpec) dls.getCopy();
|
||||
// Component transformation
|
||||
decSpec2.cts = (CompTransfSpec) cts.getCopy();
|
||||
// ROI
|
||||
if (rois != null) {
|
||||
decSpec2.rois = (MaxShiftSpec) rois.getCopy();
|
||||
}
|
||||
return decSpec2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,454 @@
|
|||
/*
|
||||
* $RCSfile: CBlkSizeSpec.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:04 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: CBlkSizeSpec
|
||||
*
|
||||
* Description: Specification of the code-blocks size
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.J2KWriteParam;
|
||||
import org.xbib.graphics.jpeg2000.j2k.ModuleSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.util.MathUtil;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
/**
|
||||
* This class extends ModuleSpec class for code-blocks sizes holding purposes.
|
||||
*
|
||||
* <P>It stores the size a of code-block.
|
||||
*/
|
||||
public class CBlkSizeSpec extends ModuleSpec {
|
||||
|
||||
/**
|
||||
* Name of the option
|
||||
*/
|
||||
private static final String optName = "Cblksiz";
|
||||
private final String defaultValue = "64 64";
|
||||
/**
|
||||
* The maximum code-block width
|
||||
*/
|
||||
private int maxCBlkWidth = 0;
|
||||
|
||||
/**
|
||||
* The maximum code-block height
|
||||
*/
|
||||
private int maxCBlkHeight = 0;
|
||||
|
||||
/**
|
||||
* Creates a new CBlkSizeSpec object for the specified number of tiles and
|
||||
* components.
|
||||
*
|
||||
* @param nt The number of tiles
|
||||
* @param nc The number of components
|
||||
* @param type the type of the specification module i.e. tile specific,
|
||||
* component specific or both.
|
||||
*/
|
||||
public CBlkSizeSpec(int nt, int nc, byte type) {
|
||||
super(nt, nc, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new CBlkSizeSpec object for the specified number of tiles and
|
||||
* components and the ParameterList instance.
|
||||
*
|
||||
* @param nt The number of tiles
|
||||
* @param nc The number of components
|
||||
* @param type the type of the specification module i.e. tile specific,
|
||||
* component specific or both.
|
||||
* @param wp the write params
|
||||
* @param values the values
|
||||
*/
|
||||
public CBlkSizeSpec(int nt, int nc, byte type, J2KWriteParam wp, String values) {
|
||||
super(nt, nc, type);
|
||||
|
||||
boolean firstVal = true;
|
||||
specified = values;
|
||||
|
||||
String param = values; //"64 64";
|
||||
if (param == null)
|
||||
param = defaultValue; // the default
|
||||
//pl.getParameter(optName);
|
||||
|
||||
// Precinct partition is used : parse arguments
|
||||
StringTokenizer stk = new StringTokenizer(param);
|
||||
byte curSpecType = SPEC_DEF; // Specification type of the
|
||||
// current parameter
|
||||
boolean[] tileSpec = null; // Tiles concerned by the specification
|
||||
boolean[] compSpec = null; // Components concerned by the specification
|
||||
int i, xIdx, ci, ti;
|
||||
String word = null; // current word
|
||||
String errMsg = null;
|
||||
|
||||
while (stk.hasMoreTokens()) {
|
||||
word = stk.nextToken();
|
||||
|
||||
switch (word.charAt(0)) {
|
||||
|
||||
case 't': // Tiles specification
|
||||
tileSpec = parseIdx(word, nTiles);
|
||||
if (curSpecType == SPEC_COMP_DEF) {
|
||||
curSpecType = SPEC_TILE_COMP;
|
||||
} else {
|
||||
curSpecType = SPEC_TILE_DEF;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c': // Components specification
|
||||
compSpec = parseIdx(word, nComp);
|
||||
if (curSpecType == SPEC_TILE_DEF) {
|
||||
curSpecType = SPEC_TILE_COMP;
|
||||
} else {
|
||||
curSpecType = SPEC_COMP_DEF;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!Character.isDigit(word.charAt(0))) {
|
||||
errMsg = "Bad construction for parameter: " + word;
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
Integer[] dim = new Integer[2];
|
||||
// Get code-block's width
|
||||
try {
|
||||
dim[0] = Integer.valueOf(word);
|
||||
// Check that width is not >
|
||||
// StdEntropyCoderOptions.MAX_CB_DIM
|
||||
if (dim[0].intValue() > StdEntropyCoderOptions.MAX_CB_DIM) {
|
||||
errMsg = "'" + optName + "' option : the code-block's " +
|
||||
"width cannot be greater than " +
|
||||
StdEntropyCoderOptions.MAX_CB_DIM;
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
// Check that width is not <
|
||||
// StdEntropyCoderOptions.MIN_CB_DIM
|
||||
if (dim[0].intValue() < StdEntropyCoderOptions.MIN_CB_DIM) {
|
||||
errMsg = "'" + optName + "' option : the code-block's " +
|
||||
"width cannot be less than " +
|
||||
StdEntropyCoderOptions.MIN_CB_DIM;
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
// Check that width is a power of 2
|
||||
if (dim[0].intValue() !=
|
||||
(1 << MathUtil.log2(dim[0].intValue()))) {
|
||||
errMsg = "'" + optName + "' option : the code-block's " +
|
||||
"width must be a power of 2";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
errMsg = "'" + optName + "' option : the code-block's " +
|
||||
"width could not be parsed.";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
// Get the next word in option
|
||||
try {
|
||||
word = stk.nextToken();
|
||||
} catch (NoSuchElementException e) {
|
||||
errMsg = "'" + optName + "' option : could not parse the " +
|
||||
"code-block's height";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
|
||||
}
|
||||
// Get the code-block's height
|
||||
try {
|
||||
dim[1] = Integer.valueOf(word);
|
||||
// Check that height is not >
|
||||
// StdEntropyCoderOptions.MAX_CB_DIM
|
||||
if (dim[1].intValue() > StdEntropyCoderOptions.MAX_CB_DIM) {
|
||||
errMsg = "'" + optName + "' option : the code-block's " +
|
||||
"height cannot be greater than " +
|
||||
StdEntropyCoderOptions.MAX_CB_DIM;
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
// Check that height is not <
|
||||
// StdEntropyCoderOptions.MIN_CB_DIM
|
||||
if (dim[1].intValue() < StdEntropyCoderOptions.MIN_CB_DIM) {
|
||||
errMsg = "'" + optName + "' option : the code-block's " +
|
||||
"height cannot be less than " +
|
||||
StdEntropyCoderOptions.MIN_CB_DIM;
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
// Check that height is a power of 2
|
||||
if (dim[1].intValue() !=
|
||||
(1 << MathUtil.log2(dim[1].intValue()))) {
|
||||
errMsg = "'" + optName + "' option : the code-block's " +
|
||||
"height must be a power of 2";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
// Check that the code-block 'area' (i.e. width*height) is
|
||||
// not greater than StdEntropyCoderOptions.MAX_CB_AREA
|
||||
if (dim[0].intValue() * dim[1].intValue() >
|
||||
StdEntropyCoderOptions.MAX_CB_AREA) {
|
||||
errMsg = "'" + optName + "' option : The " +
|
||||
"code-block's area (i.e. width*height) " +
|
||||
"cannot be greater than " +
|
||||
StdEntropyCoderOptions.MAX_CB_AREA;
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
errMsg = "'" + optName + "' option : the code-block's height " +
|
||||
"could not be parsed.";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
|
||||
// Store the maximum dimensions if necessary
|
||||
if (dim[0].intValue() > maxCBlkWidth) {
|
||||
maxCBlkWidth = dim[0].intValue();
|
||||
}
|
||||
|
||||
if (dim[1].intValue() > maxCBlkHeight) {
|
||||
maxCBlkHeight = dim[1].intValue();
|
||||
}
|
||||
|
||||
if (firstVal) {
|
||||
// This is the first time a value is given so we set it as
|
||||
// the default one
|
||||
setDefault(dim);
|
||||
firstVal = false;
|
||||
}
|
||||
|
||||
switch (curSpecType) {
|
||||
case SPEC_DEF:
|
||||
setDefault(dim);
|
||||
break;
|
||||
case SPEC_TILE_DEF:
|
||||
for (ti = tileSpec.length - 1; ti >= 0; ti--) {
|
||||
if (tileSpec[ti]) {
|
||||
setTileDef(ti, dim);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SPEC_COMP_DEF:
|
||||
for (ci = compSpec.length - 1; ci >= 0; ci--) {
|
||||
if (compSpec[ci]) {
|
||||
setCompDef(ci, dim);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (ti = tileSpec.length - 1; ti >= 0; ti--) {
|
||||
for (ci = compSpec.length - 1; ci >= 0; ci--) {
|
||||
if (tileSpec[ti] && compSpec[ci]) {
|
||||
setTileCompVal(ti, ci, dim);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // end switch
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum code-block's width
|
||||
*/
|
||||
public int getMaxCBlkWidth() {
|
||||
return maxCBlkWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum code-block's height
|
||||
*/
|
||||
public int getMaxCBlkHeight() {
|
||||
return maxCBlkHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code-block width :
|
||||
*
|
||||
* <ul>
|
||||
* <li>for the specified tile/component</li>
|
||||
* <li>for the specified tile</li>
|
||||
* <li>for the specified component</li>
|
||||
* <li>default value</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The value returned depends on the value of the variable 'type' which
|
||||
* can take the following values :<br>
|
||||
*
|
||||
* <ul>
|
||||
* <li>SPEC_DEF -> Default value is returned. t and c values are
|
||||
* ignored</li>
|
||||
* <li>SPEC_COMP_DEF -> Component default value is returned. t value is
|
||||
* ignored</li>
|
||||
* <li>SPEC_TILE_DEF -> Tile default value is returned. c value is
|
||||
* ignored</li>
|
||||
* <li>SPEC_TILE_COMP -> Tile/Component value is returned.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param type The type of the value we want to be returned
|
||||
* @param t The tile index
|
||||
* @param c the component index
|
||||
* @return The code-block width for the specified tile and component
|
||||
*/
|
||||
public int getCBlkWidth(byte type, int t, int c) {
|
||||
Integer[] dim = null;
|
||||
switch (type) {
|
||||
case SPEC_DEF:
|
||||
dim = (Integer[]) getDefault();
|
||||
break;
|
||||
case SPEC_COMP_DEF:
|
||||
dim = (Integer[]) getCompDef(c);
|
||||
break;
|
||||
case SPEC_TILE_DEF:
|
||||
dim = (Integer[]) getTileDef(t);
|
||||
break;
|
||||
case SPEC_TILE_COMP:
|
||||
dim = (Integer[]) getTileCompVal(t, c);
|
||||
}
|
||||
return dim[0].intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code-block height:
|
||||
*
|
||||
* <ul>
|
||||
* <li>for the specified tile/component</li>
|
||||
* <li>for the specified tile</li>
|
||||
* <li>for the specified component</li>
|
||||
* <li>default value</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* The value returned depends on the value of the variable 'type' which
|
||||
* can take the following values :
|
||||
*
|
||||
* <ul>
|
||||
* <li>SPEC_DEF -> Default value is returned. t and c values are
|
||||
* ignored</li>
|
||||
* <li>SPEC_COMP_DEF -> Component default value is returned. t value is
|
||||
* ignored</li>
|
||||
* <li>SPEC_TILE_DEF -> Tile default value is returned. c value is
|
||||
* ignored</li>
|
||||
* <li>SPEC_TILE_COMP -> Tile/Component value is returned.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param type The type of the value we want to be returned
|
||||
* @param t The tile index
|
||||
* @param c the component index
|
||||
* @return The code-block height for the specified tile and component
|
||||
*/
|
||||
public int getCBlkHeight(byte type, int t, int c) {
|
||||
Integer[] dim = null;
|
||||
switch (type) {
|
||||
case SPEC_DEF:
|
||||
dim = (Integer[]) getDefault();
|
||||
break;
|
||||
case SPEC_COMP_DEF:
|
||||
dim = (Integer[]) getCompDef(c);
|
||||
break;
|
||||
case SPEC_TILE_DEF:
|
||||
dim = (Integer[]) getTileDef(t);
|
||||
break;
|
||||
case SPEC_TILE_COMP:
|
||||
dim = (Integer[]) getTileCompVal(t, c);
|
||||
}
|
||||
return dim[1].intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default value for this module
|
||||
*
|
||||
* @param value Default value
|
||||
*/
|
||||
public void setDefault(Object value) {
|
||||
super.setDefault(value);
|
||||
|
||||
// Store the biggest code-block dimensions
|
||||
storeHighestDims((Integer[]) value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default value for specified tile and specValType tag if allowed by
|
||||
* its priority.
|
||||
*
|
||||
* @param t Tile index.
|
||||
* @param value Tile's default value
|
||||
*/
|
||||
public void setTileDef(int t, Object value) {
|
||||
super.setTileDef(t, value);
|
||||
|
||||
// Store the biggest code-block dimensions
|
||||
storeHighestDims((Integer[]) value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets default value for specified component and specValType tag if
|
||||
* allowed by its priority.
|
||||
*
|
||||
* @param c Component index
|
||||
* @param value Component's default value
|
||||
*/
|
||||
public void setCompDef(int c, Object value) {
|
||||
super.setCompDef(c, value);
|
||||
|
||||
// Store the biggest code-block dimensions
|
||||
storeHighestDims((Integer[]) value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets value for specified tile-component.
|
||||
*
|
||||
* @param t Tie index
|
||||
* @param c Component index
|
||||
* @param value Tile-component's value
|
||||
*/
|
||||
public void setTileCompVal(int t, int c, Object value) {
|
||||
super.setTileCompVal(t, c, value);
|
||||
|
||||
// Store the biggest code-block dimensions
|
||||
storeHighestDims((Integer[]) value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the highest code-block width and height
|
||||
*
|
||||
* @param dim The 2 elements array that contains the code-block width and
|
||||
* height.
|
||||
*/
|
||||
private void storeHighestDims(Integer[] dim) {
|
||||
// Store the biggest code-block dimensions
|
||||
if (dim[0].intValue() > maxCBlkWidth) {
|
||||
maxCBlkWidth = dim[0].intValue();
|
||||
}
|
||||
if (dim[1].intValue() > maxCBlkHeight) {
|
||||
maxCBlkHeight = dim[1].intValue();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* $RCSfile: CodedCBlk.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:04 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: CodedCBlk
|
||||
*
|
||||
* Description: The generic coded (compressed) code-block
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.decoder.DecLyrdCBlk;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.encoder.CBlkRateDistStats;
|
||||
|
||||
/**
|
||||
* This is the generic class to store coded (compressed) code-block. It stores
|
||||
* the compressed data as well as the necessary side-information.
|
||||
*
|
||||
* <P>This class is normally not used. Instead the EncRDCBlk, EncLyrdCBlk and
|
||||
* the DecLyrdCBlk subclasses are used.
|
||||
*
|
||||
* @see CBlkRateDistStats
|
||||
* @see DecLyrdCBlk
|
||||
*/
|
||||
public class CodedCBlk {
|
||||
|
||||
/**
|
||||
* The horizontal index of the code-block, within the subband.
|
||||
*/
|
||||
public int n;
|
||||
|
||||
/**
|
||||
* The vertical index of the code-block, within the subband.
|
||||
*/
|
||||
public int m;
|
||||
|
||||
/**
|
||||
* The number of skipped most significant bit-planes.
|
||||
*/
|
||||
public int skipMSBP;
|
||||
|
||||
/**
|
||||
* The compressed data
|
||||
*/
|
||||
public byte[] data;
|
||||
|
||||
/**
|
||||
* Creates a new CodedCBlk object wit the default values and without
|
||||
* allocating any space for its members.
|
||||
*/
|
||||
public CodedCBlk() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new CodedCBlk object with the specified values.
|
||||
*
|
||||
* @param m The horizontal index of the code-block, within the subband.
|
||||
* @param n The vertical index of the code-block, within the subband.
|
||||
* @param skipMSBP The number of skipped most significant bit-planes for
|
||||
* this code-block.
|
||||
* @param data The compressed data. This array is referenced by this
|
||||
* object so it should not be modified after.
|
||||
*/
|
||||
public CodedCBlk(int m, int n, int skipMSBP, byte[] data) {
|
||||
this.m = m;
|
||||
this.n = n;
|
||||
this.skipMSBP = skipMSBP;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contents of the object in a string. The string contains the
|
||||
* following data: 'm', 'n', 'skipMSBP' and 'data.length. This is used for
|
||||
* debugging.
|
||||
*
|
||||
* @return A string with the contents of the object
|
||||
*/
|
||||
public String toString() {
|
||||
return "m= " + m + ", n= " + n + ", skipMSBP= " + skipMSBP +
|
||||
", data.length= " + ((data != null) ? "" + data.length : "(null)");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* $RCSfile: PrecinctSizeSpec.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:04 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: PrecinctSizeSpec
|
||||
*
|
||||
* Description: Specification of the precinct sizes
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.J2KWriteParam;
|
||||
import org.xbib.graphics.jpeg2000.j2k.IntegerSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.ModuleSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.Markers;
|
||||
import org.xbib.graphics.jpeg2000.j2k.image.BlkImgDataSrc;
|
||||
import org.xbib.graphics.jpeg2000.j2k.util.MathUtil;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* This class extends ModuleSpec class for precinct partition sizes holding
|
||||
* purposes.
|
||||
*
|
||||
* <p>It stores the size a of precinct when precinct partition is used or not.
|
||||
* If precinct partition is used, we can have several packets for a given
|
||||
* resolution level whereas there is only one packet per resolution level if
|
||||
* no precinct partition is used.
|
||||
*/
|
||||
public class PrecinctSizeSpec extends ModuleSpec {
|
||||
|
||||
/**
|
||||
* Name of the option
|
||||
*/
|
||||
private static final String optName = "Cpp";
|
||||
|
||||
/**
|
||||
* Reference to wavelet number of decomposition levels for each
|
||||
* tile-component.
|
||||
*/
|
||||
private final IntegerSpec dls;
|
||||
|
||||
/**
|
||||
* Creates a new PrecinctSizeSpec object for the specified number of tiles
|
||||
* and components.
|
||||
*
|
||||
* @param nt The number of tiles
|
||||
* @param nc The number of components
|
||||
* @param type the type of the specification module i.e. tile specific,
|
||||
* component specific or both.
|
||||
* @param dls Reference to the number of decomposition levels
|
||||
* specification
|
||||
*/
|
||||
public PrecinctSizeSpec(int nt, int nc, byte type, IntegerSpec dls) {
|
||||
super(nt, nc, type);
|
||||
this.dls = dls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new PrecinctSizeSpec object for the specified number of tiles
|
||||
* and components and the J2KWriteParam instance.
|
||||
*
|
||||
* @param nt The number of tiles
|
||||
* @param nc The number of components
|
||||
* @param type the type of the specification module i.e. tile specific,
|
||||
* component specific or both.
|
||||
* @param imgsrc The image source (used to get the image size)
|
||||
* @param wp The J2KWriteParam instance
|
||||
*/
|
||||
public PrecinctSizeSpec(int nt, int nc, byte type, BlkImgDataSrc imgsrc,
|
||||
IntegerSpec dls, J2KWriteParam wp, String values) {
|
||||
super(nt, nc, type);
|
||||
|
||||
this.dls = dls;
|
||||
|
||||
// The precinct sizes are stored in a 2 elements vector array, the
|
||||
// first element containing a vector for the precincts width for each
|
||||
// resolution level and the second element containing a vector for the
|
||||
// precincts height for each resolution level. The precincts sizes are
|
||||
// specified from the highest resolution level to the lowest one
|
||||
// (i.e. 0). If there are less elements than the number of
|
||||
// decomposition levels, the last element is used for all remaining
|
||||
// resolution levels (i.e. if the precincts sizes are specified only
|
||||
// for resolutions levels 5, 4 and 3, then the precincts size for
|
||||
// resolution levels 2, 1 and 0 will be the same as the size used for
|
||||
// resolution level 3).
|
||||
|
||||
// Boolean used to know if we were previously reading a precinct's
|
||||
// size or if we were reading something else.
|
||||
boolean wasReadingPrecinctSize = false;
|
||||
|
||||
String param = values;
|
||||
/*
|
||||
if (values == null)
|
||||
param = defaultValue; // the default is null
|
||||
*/
|
||||
// Set precinct sizes to default i.e. 2^15 =
|
||||
// Markers.PRECINCT_PARTITION_DEF_SIZE
|
||||
Vector[] tmpv = new Vector[2];
|
||||
tmpv[0] = new Vector(); // ppx
|
||||
tmpv[0].addElement(Integer.valueOf(Markers.PRECINCT_PARTITION_DEF_SIZE));
|
||||
tmpv[1] = new Vector(); // ppy
|
||||
tmpv[1].addElement(Integer.valueOf(Markers.PRECINCT_PARTITION_DEF_SIZE));
|
||||
setDefault(tmpv);
|
||||
|
||||
if (param == null) {
|
||||
// No precinct size specified in the command line so we do not try
|
||||
// to parse it.
|
||||
return;
|
||||
}
|
||||
|
||||
// Precinct partition is used : parse arguments
|
||||
StringTokenizer stk = new StringTokenizer(param);
|
||||
byte curSpecType = SPEC_DEF; // Specification type of the
|
||||
// current parameter
|
||||
boolean[] tileSpec = null; // Tiles concerned by the specification
|
||||
boolean[] compSpec = null; // Components concerned by the specification
|
||||
int i, xIdx, ci, ti;
|
||||
|
||||
boolean endOfParamList = false;
|
||||
String word = null; // current word
|
||||
Integer w, h;
|
||||
String errMsg = null;
|
||||
|
||||
while ((stk.hasMoreTokens() || wasReadingPrecinctSize) &&
|
||||
!endOfParamList) {
|
||||
|
||||
Vector[] v = new Vector[2]; // v[0] : ppx, v[1] : ppy
|
||||
|
||||
// We do not read the next token if we were reading a precinct's
|
||||
// size argument as we have already read the next token into word.
|
||||
if (!wasReadingPrecinctSize) {
|
||||
word = stk.nextToken();
|
||||
}
|
||||
|
||||
wasReadingPrecinctSize = false;
|
||||
|
||||
switch (word.charAt(0)) {
|
||||
|
||||
case 't': // Tiles specification
|
||||
tileSpec = parseIdx(word, nTiles);
|
||||
if (curSpecType == SPEC_COMP_DEF) {
|
||||
curSpecType = SPEC_TILE_COMP;
|
||||
} else {
|
||||
curSpecType = SPEC_TILE_DEF;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c': // Components specification
|
||||
compSpec = parseIdx(word, nComp);
|
||||
if (curSpecType == SPEC_TILE_DEF) {
|
||||
curSpecType = SPEC_TILE_COMP;
|
||||
} else {
|
||||
curSpecType = SPEC_COMP_DEF;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!Character.isDigit(word.charAt(0))) {
|
||||
errMsg = "Bad construction for parameter: " + word;
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
|
||||
// Initialises Vector objects
|
||||
v[0] = new Vector(); // ppx
|
||||
v[1] = new Vector(); // ppy
|
||||
|
||||
while (true) {
|
||||
|
||||
// Now get the precinct dimensions
|
||||
try {
|
||||
// Get precinct width
|
||||
w = Integer.valueOf(word);
|
||||
|
||||
// Get next word in argument list
|
||||
try {
|
||||
word = stk.nextToken();
|
||||
} catch (NoSuchElementException e) {
|
||||
errMsg = "'" + optName + "' option : could not " +
|
||||
"parse the precinct's width";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
|
||||
}
|
||||
// Get precinct height
|
||||
h = Integer.valueOf(word);
|
||||
if (w.intValue() != (1 << MathUtil.log2(w.intValue()))
|
||||
|| h.intValue() !=
|
||||
(1 << MathUtil.log2(h.intValue()))) {
|
||||
errMsg = "Precinct dimensions must be powers of 2";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
errMsg = "'" + optName + "' option : the argument '" + word +
|
||||
"' could not be parsed.";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
// Store packet's dimensions in Vector arrays
|
||||
v[0].addElement(w);
|
||||
v[1].addElement(h);
|
||||
|
||||
// Try to get the next token
|
||||
if (stk.hasMoreTokens()) {
|
||||
word = stk.nextToken();
|
||||
if (!Character.isDigit(word.charAt(0))) {
|
||||
// The next token does not start with a digit so
|
||||
// it is not a precinct's size argument. We set
|
||||
// the wasReadingPrecinctSize booleen such that we
|
||||
// know that we don't have to read another token
|
||||
// and check for the end of the parameters list.
|
||||
wasReadingPrecinctSize = true;
|
||||
|
||||
if (curSpecType == SPEC_DEF) {
|
||||
setDefault(v);
|
||||
} else if (curSpecType == SPEC_TILE_DEF) {
|
||||
for (ti = tileSpec.length - 1; ti >= 0; ti--) {
|
||||
if (tileSpec[ti]) {
|
||||
setTileDef(ti, v);
|
||||
}
|
||||
}
|
||||
} else if (curSpecType == SPEC_COMP_DEF) {
|
||||
for (ci = compSpec.length - 1; ci >= 0; ci--) {
|
||||
if (compSpec[ci]) {
|
||||
setCompDef(ci, v);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (ti = tileSpec.length - 1; ti >= 0; ti--) {
|
||||
for (ci = compSpec.length - 1; ci >= 0; ci--) {
|
||||
if (tileSpec[ti] && compSpec[ci]) {
|
||||
setTileCompVal(ti, ci, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Re-initialize
|
||||
curSpecType = SPEC_DEF;
|
||||
tileSpec = null;
|
||||
compSpec = null;
|
||||
|
||||
// Go back to 'normal' parsing
|
||||
break;
|
||||
} else {
|
||||
// Next token starts with a digit so read it
|
||||
}
|
||||
} else {
|
||||
// We have reached the end of the parameters list so
|
||||
// we store the last precinct's sizes and we stop
|
||||
if (curSpecType == SPEC_DEF) {
|
||||
setDefault(v);
|
||||
} else if (curSpecType == SPEC_TILE_DEF) {
|
||||
for (ti = tileSpec.length - 1; ti >= 0; ti--) {
|
||||
if (tileSpec[ti]) {
|
||||
setTileDef(ti, v);
|
||||
}
|
||||
}
|
||||
} else if (curSpecType == SPEC_COMP_DEF) {
|
||||
for (ci = compSpec.length - 1; ci >= 0; ci--) {
|
||||
if (compSpec[ci]) {
|
||||
setCompDef(ci, v);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (ti = tileSpec.length - 1; ti >= 0; ti--) {
|
||||
for (ci = compSpec.length - 1; ci >= 0; ci--) {
|
||||
if (tileSpec[ti] && compSpec[ci]) {
|
||||
setTileCompVal(ti, ci, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
endOfParamList = true;
|
||||
break;
|
||||
}
|
||||
} // while (true)
|
||||
break;
|
||||
} // switch
|
||||
} // while
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the precinct partition width in component 'n' and tile 't' at
|
||||
* resolution level 'rl'. If the tile index is equal to -1 or if the
|
||||
* component index is equal to -1 it means that those should not be taken
|
||||
* into account.
|
||||
*
|
||||
* @param t The tile index, in raster scan order. Specify -1 if it is not
|
||||
* a specific tile.
|
||||
* @param c The component index. Specify -1 if it is not a specific
|
||||
* component.
|
||||
* @param rl The resolution level
|
||||
* @return The precinct partition width in component 'c' and tile 't' at
|
||||
* resolution level 'rl'.
|
||||
*/
|
||||
public int getPPX(int t, int c, int rl) {
|
||||
int mrl, idx;
|
||||
Vector[] v = null;
|
||||
boolean tileSpecified = (t != -1);
|
||||
boolean compSpecified = (c != -1);
|
||||
|
||||
// Get the maximum number of decomposition levels and the object
|
||||
// (Vector array) containing the precinct dimensions (width and
|
||||
// height) for the specified (or not) tile/component
|
||||
if (tileSpecified && compSpecified) {
|
||||
mrl = ((Integer) dls.getTileCompVal(t, c)).intValue();
|
||||
v = (Vector[]) getTileCompVal(t, c);
|
||||
} else if (tileSpecified && !compSpecified) {
|
||||
mrl = ((Integer) dls.getTileDef(t)).intValue();
|
||||
v = (Vector[]) getTileDef(t);
|
||||
} else if (!tileSpecified && compSpecified) {
|
||||
mrl = ((Integer) dls.getCompDef(c)).intValue();
|
||||
v = (Vector[]) getCompDef(c);
|
||||
} else {
|
||||
mrl = ((Integer) dls.getDefault()).intValue();
|
||||
v = (Vector[]) getDefault();
|
||||
}
|
||||
idx = mrl - rl;
|
||||
if (v[0].size() > idx) {
|
||||
return ((Integer) v[0].elementAt(idx)).intValue();
|
||||
} else {
|
||||
return ((Integer) v[0].elementAt(v[0].size() - 1)).intValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the precinct partition height in component 'n' and tile 't' at
|
||||
* resolution level 'rl'. If the tile index is equal to -1 or if the
|
||||
* component index is equal to -1 it means that those should not be taken
|
||||
* into account.
|
||||
*
|
||||
* @param t The tile index, in raster scan order. Specify -1 if it is not
|
||||
* a specific tile.
|
||||
* @param c The component index. Specify -1 if it is not a specific
|
||||
* component.
|
||||
* @param rl The resolution level.
|
||||
* @return The precinct partition width in component 'n' and tile 't' at
|
||||
* resolution level 'rl'.
|
||||
*/
|
||||
public int getPPY(int t, int c, int rl) {
|
||||
int mrl, idx;
|
||||
Vector[] v = null;
|
||||
boolean tileSpecified = (t != -1);
|
||||
boolean compSpecified = (c != -1);
|
||||
|
||||
// Get the maximum number of decomposition levels and the object
|
||||
// (Vector array) containing the precinct dimensions (width and
|
||||
// height) for the specified (or not) tile/component
|
||||
if (tileSpecified && compSpecified) {
|
||||
mrl = ((Integer) dls.getTileCompVal(t, c)).intValue();
|
||||
v = (Vector[]) getTileCompVal(t, c);
|
||||
} else if (tileSpecified && !compSpecified) {
|
||||
mrl = ((Integer) dls.getTileDef(t)).intValue();
|
||||
v = (Vector[]) getTileDef(t);
|
||||
} else if (!tileSpecified && compSpecified) {
|
||||
mrl = ((Integer) dls.getCompDef(c)).intValue();
|
||||
v = (Vector[]) getCompDef(c);
|
||||
} else {
|
||||
mrl = ((Integer) dls.getDefault()).intValue();
|
||||
v = (Vector[]) getDefault();
|
||||
}
|
||||
idx = mrl - rl;
|
||||
if (v[1].size() > idx) {
|
||||
return ((Integer) v[1].elementAt(idx)).intValue();
|
||||
} else {
|
||||
return ((Integer) v[1].elementAt(v[1].size() - 1)).intValue();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* $RCSfile: Progression.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:05 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: Progression
|
||||
*
|
||||
* Description: Holds the type(s) of progression
|
||||
*
|
||||
*
|
||||
* Modified by:
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.ProgressionType;
|
||||
|
||||
/**
|
||||
* This class holds one of the different progression orders defined in
|
||||
* the bit stream. The type(s) of progression order are defined in the
|
||||
* ProgressionType interface. A Progression object is totally defined
|
||||
* by its component start and end, resolution level start and end and
|
||||
* layer start and end indexes. If no progression order change is
|
||||
* defined, there is only Progression instance.
|
||||
*
|
||||
* @see ProgressionType
|
||||
*/
|
||||
public class Progression implements ProgressionType {
|
||||
|
||||
/**
|
||||
* Progression type as defined in ProgressionType interface
|
||||
*/
|
||||
public int type;
|
||||
|
||||
/**
|
||||
* Component index for the start of a progression
|
||||
*/
|
||||
public int cs;
|
||||
|
||||
/**
|
||||
* Component index for the end of a progression.
|
||||
*/
|
||||
public int ce;
|
||||
|
||||
/**
|
||||
* Resolution index for the start of a progression
|
||||
*/
|
||||
public int rs;
|
||||
|
||||
/**
|
||||
* Resolution index for the end of a progression.
|
||||
*/
|
||||
public int re;
|
||||
|
||||
/**
|
||||
* The index of the last layer.
|
||||
*/
|
||||
public int lye;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* <p>
|
||||
* Builds a new Progression object with specified type and bounds
|
||||
* of progression.
|
||||
*
|
||||
* @param type The progression type
|
||||
* @param cs The component index start
|
||||
* @param ce The component index end
|
||||
* @param rs The resolution level index start
|
||||
* @param re The resolution level index end
|
||||
* @param lye The layer index end
|
||||
*/
|
||||
public Progression(int type, int cs, int ce, int rs, int re, int lye) {
|
||||
this.type = type;
|
||||
this.cs = cs;
|
||||
this.ce = ce;
|
||||
this.rs = rs;
|
||||
this.re = re;
|
||||
this.lye = lye;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
String str = "type= ";
|
||||
switch (type) {
|
||||
case LY_RES_COMP_POS_PROG:
|
||||
str += "layer, ";
|
||||
break;
|
||||
case RES_LY_COMP_POS_PROG:
|
||||
str += "res, ";
|
||||
break;
|
||||
case RES_POS_COMP_LY_PROG:
|
||||
str += "res-pos, ";
|
||||
break;
|
||||
case POS_COMP_RES_LY_PROG:
|
||||
str += "pos-comp, ";
|
||||
break;
|
||||
case COMP_POS_RES_LY_PROG:
|
||||
str += "pos-comp, ";
|
||||
break;
|
||||
default:
|
||||
str += "Unknown progression type=" + type;
|
||||
}
|
||||
str += "comp.: " + cs + "-" + ce + ", ";
|
||||
str += "res.: " + rs + "-" + re + ", ";
|
||||
str += "layer: up to " + lye;
|
||||
return str;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,378 @@
|
|||
/*
|
||||
* $RCSfile: ProgressionSpec.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:05 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: ProgressionSpec
|
||||
*
|
||||
* Description: Specification of the progression(s) type(s) and
|
||||
* changes of progression.
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.J2KWriteParam;
|
||||
import org.xbib.graphics.jpeg2000.j2k.IntegerSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.ModuleSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.ProgressionType;
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* This class extends ModuleSpec class for progression type(s) and progression
|
||||
* order changes holding purposes.
|
||||
*
|
||||
* <P>It stores the progression type(s) used in the codestream. There can be
|
||||
* only one progression type or several ones if progression order changes are
|
||||
* used (POC markers).
|
||||
*/
|
||||
public class ProgressionSpec extends ModuleSpec {
|
||||
|
||||
/**
|
||||
* Creates a new ProgressionSpec object for the specified number of tiles
|
||||
* and components.
|
||||
*
|
||||
* @param nt The number of tiles
|
||||
* @param nc The number of components
|
||||
* @param type the type of the specification module i.e. tile specific,
|
||||
* component specific or both. The ProgressionSpec class should only be
|
||||
* used only with the type ModuleSpec.SPEC_TYPE_TILE.
|
||||
*/
|
||||
public ProgressionSpec(int nt, int nc, byte type) {
|
||||
super(nt, nc, type);
|
||||
if (type != ModuleSpec.SPEC_TYPE_TILE) {
|
||||
throw new IllegalArgumentException("Illegal use of class ProgressionSpec !");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ProgressionSpec object for the specified number of
|
||||
* tiles, components and the J2KWriteParam instance.
|
||||
*
|
||||
* @param nt The number of tiles
|
||||
* @param nc The number of components
|
||||
* @param nl The number of layer
|
||||
* @param dls The number of decomposition levels specifications
|
||||
* @param type the type of the specification module. The ProgressionSpec
|
||||
* class should only be used only with the type ModuleSpec.SPEC_TYPE_TILE.
|
||||
* @param wp The J2KWriteParam instance
|
||||
*/
|
||||
public ProgressionSpec(int nt, int nc, int nl, IntegerSpec dls, byte type,
|
||||
J2KWriteParam wp, String values) {
|
||||
super(nt, nc, type);
|
||||
|
||||
specified = values;
|
||||
|
||||
String param = values;
|
||||
Progression[] prog;
|
||||
int mode = -1;
|
||||
|
||||
if (values == null) { // No parameter specified
|
||||
if (wp.getROIs() == null) {
|
||||
mode = checkProgMode("res");
|
||||
} else {
|
||||
mode = checkProgMode("layer");
|
||||
}
|
||||
|
||||
if (mode == -1) {
|
||||
String errMsg = "Unknown progression type : '" + param + "'";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
prog = new Progression[1];
|
||||
prog[0] = new Progression(mode, 0, nc, 0, dls.getMax() + 1, nl);
|
||||
setDefault(prog);
|
||||
return;
|
||||
}
|
||||
|
||||
StringTokenizer stk = new StringTokenizer(param);
|
||||
byte curSpecType = SPEC_DEF; // Specification type of the
|
||||
// current parameter
|
||||
boolean[] tileSpec = null; // Tiles concerned by the specification
|
||||
String word = null; // current word
|
||||
String errMsg = null; // Error message
|
||||
boolean needInteger = false; // True if an integer value is expected
|
||||
int intType = 0; // Type of read integer value (0=index of first
|
||||
// component, 1= index of first resolution level, 2=index of last
|
||||
// layer, 3= index of last component, 4= index of last resolution
|
||||
// level)
|
||||
Vector progression = new Vector();
|
||||
int tmp = 0;
|
||||
Progression curProg = null;
|
||||
|
||||
while (stk.hasMoreTokens()) {
|
||||
word = stk.nextToken();
|
||||
|
||||
switch (word.charAt(0)) {
|
||||
case 't':
|
||||
// If progression were previously found, store them
|
||||
if (progression.size() > 0) {
|
||||
// Ensure that all information has been taken
|
||||
curProg.ce = nc;
|
||||
curProg.lye = nl;
|
||||
curProg.re = dls.getMax() + 1;
|
||||
prog = new Progression[progression.size()];
|
||||
progression.copyInto(prog);
|
||||
if (curSpecType == SPEC_DEF) {
|
||||
setDefault(prog);
|
||||
} else if (curSpecType == SPEC_TILE_DEF) {
|
||||
for (int i = tileSpec.length - 1; i >= 0; i--)
|
||||
if (tileSpec[i]) {
|
||||
setTileDef(i, prog);
|
||||
}
|
||||
}
|
||||
}
|
||||
progression.removeAllElements();
|
||||
intType = -1;
|
||||
needInteger = false;
|
||||
|
||||
// Tiles specification
|
||||
tileSpec = parseIdx(word, nTiles);
|
||||
curSpecType = SPEC_TILE_DEF;
|
||||
break;
|
||||
default:
|
||||
// Here, words is either a Integer (progression bound
|
||||
// index) or a String (progression order type). This
|
||||
// is determined by the value of needInteger.
|
||||
if (needInteger) { // Progression bound info
|
||||
try {
|
||||
tmp = (Integer.valueOf(word)).intValue();
|
||||
} catch (NumberFormatException e) {
|
||||
// Progression has missing parameters
|
||||
throw new IllegalArgumentException("Progression " +
|
||||
"order" +
|
||||
" specification " +
|
||||
"has missing " +
|
||||
"parameters: " +
|
||||
param);
|
||||
}
|
||||
|
||||
switch (intType) {
|
||||
case 0: // cs
|
||||
if (tmp < 0 || tmp > dls.getMax() + 1)
|
||||
throw new
|
||||
IllegalArgumentException("Invalid comp_start " +
|
||||
"in '-Aptype' option");
|
||||
curProg.cs = tmp;
|
||||
break;
|
||||
case 1: // rs
|
||||
if (tmp < 0 || tmp > nc)
|
||||
throw new
|
||||
IllegalArgumentException("Invalid res_start " +
|
||||
"in '-Aptype' option");
|
||||
|
||||
curProg.rs = tmp;
|
||||
break;
|
||||
case 2: // lye
|
||||
if (tmp < 0)
|
||||
throw new
|
||||
IllegalArgumentException("Invalid layer_end " +
|
||||
"in '-Aptype' option");
|
||||
if (tmp > nl) {
|
||||
tmp = nl;
|
||||
}
|
||||
curProg.lye = tmp;
|
||||
break;
|
||||
case 3: // ce
|
||||
if (tmp < 0)
|
||||
throw new
|
||||
IllegalArgumentException("Invalid comp_end " +
|
||||
"in '-Aptype' option");
|
||||
if (tmp > (dls.getMax() + 1)) {
|
||||
tmp = dls.getMax() + 1;
|
||||
}
|
||||
curProg.ce = tmp;
|
||||
break;
|
||||
case 4: // re
|
||||
if (tmp < 0)
|
||||
throw new
|
||||
IllegalArgumentException("Invalid res_end " +
|
||||
"in '-Aptype' option");
|
||||
if (tmp > nc) {
|
||||
tmp = nc;
|
||||
}
|
||||
curProg.re = tmp;
|
||||
break;
|
||||
}
|
||||
|
||||
if (intType < 4) {
|
||||
intType++;
|
||||
needInteger = true;
|
||||
break;
|
||||
} else if (intType == 4) {
|
||||
intType = 0;
|
||||
needInteger = false;
|
||||
break;
|
||||
} else {
|
||||
throw new IllegalStateException("Error in usage of 'Aptype' " +
|
||||
"option: " + param);
|
||||
}
|
||||
}
|
||||
|
||||
if (!needInteger) { // Progression type info
|
||||
mode = checkProgMode(word);
|
||||
if (mode == -1) {
|
||||
errMsg = "Unknown progression type : '" + word + "'";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
needInteger = true;
|
||||
intType = 0;
|
||||
if (progression.size() == 0)
|
||||
curProg = new Progression(mode, 0, nc, 0, dls.getMax() + 1,
|
||||
nl);
|
||||
else {
|
||||
curProg = new Progression(mode, 0, nc, 0, dls.getMax() + 1,
|
||||
nl);
|
||||
}
|
||||
progression.addElement(curProg);
|
||||
}
|
||||
} // switch
|
||||
} // while
|
||||
|
||||
if (progression.size() == 0) { // No progression defined
|
||||
// Set it arbitrarily to layer progressive
|
||||
if (wp.getROIs() == null) {
|
||||
mode = checkProgMode("res");
|
||||
} else {
|
||||
mode = checkProgMode("layer");
|
||||
}
|
||||
|
||||
if (mode == -1) {
|
||||
errMsg = "Unknown progression type : '" + param + "'";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
prog = new Progression[1];
|
||||
prog[0] = new Progression(mode, 0, nc, 0, dls.getMax() + 1, nl);
|
||||
setDefault(prog);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure that all information has been taken
|
||||
curProg.ce = nc;
|
||||
curProg.lye = nl;
|
||||
curProg.re = dls.getMax() + 1;
|
||||
|
||||
// Store found progression
|
||||
prog = new Progression[progression.size()];
|
||||
progression.copyInto(prog);
|
||||
|
||||
if (curSpecType == SPEC_DEF) {
|
||||
setDefault(prog);
|
||||
} else if (curSpecType == SPEC_TILE_DEF) {
|
||||
for (int i = tileSpec.length - 1; i >= 0; i--)
|
||||
if (tileSpec[i]) {
|
||||
setTileDef(i, prog);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that default value has been specified
|
||||
if (getDefault() == null) {
|
||||
int ndefspec = 0;
|
||||
for (int t = nt - 1; t >= 0; t--) {
|
||||
for (int c = nc - 1; c >= 0; c--) {
|
||||
if (specValType[t][c] == SPEC_DEF) {
|
||||
ndefspec++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If some tile-component have received no specification, they are
|
||||
// arbitrarily set to 'layer' progressive.
|
||||
if (ndefspec != 0) {
|
||||
if (wp.getROIs() == null) {
|
||||
mode = checkProgMode("res");
|
||||
} else {
|
||||
mode = checkProgMode("layer");
|
||||
}
|
||||
if (mode == -1) {
|
||||
errMsg = "Unknown progression type : '" + param + "'";
|
||||
throw new IllegalArgumentException(errMsg);
|
||||
}
|
||||
prog = new Progression[1];
|
||||
prog[0] = new Progression(mode, 0, nc, 0, dls.getMax() + 1, nl);
|
||||
setDefault(prog);
|
||||
} else {
|
||||
// All tile-component have been specified, takes the first
|
||||
// tile-component value as default.
|
||||
setDefault(getTileCompVal(0, 0));
|
||||
switch (specValType[0][0]) {
|
||||
case SPEC_TILE_DEF:
|
||||
for (int c = nc - 1; c >= 0; c--) {
|
||||
if (specValType[0][c] == SPEC_TILE_DEF)
|
||||
specValType[0][c] = SPEC_DEF;
|
||||
}
|
||||
tileDef[0] = null;
|
||||
break;
|
||||
case SPEC_COMP_DEF:
|
||||
for (int t = nt - 1; t >= 0; t--) {
|
||||
if (specValType[t][0] == SPEC_COMP_DEF)
|
||||
specValType[t][0] = SPEC_DEF;
|
||||
}
|
||||
compDef[0] = null;
|
||||
break;
|
||||
case SPEC_TILE_COMP:
|
||||
specValType[0][0] = SPEC_DEF;
|
||||
tileCompVal.put("t0c0", null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the progression mode exists and if so, return its integer
|
||||
* value. It returns -1 otherwise.
|
||||
*
|
||||
* @param mode The progression mode stored in a string
|
||||
* @return The integer value of the progression mode or -1 if the
|
||||
* progression mode does not exist.
|
||||
* @see ProgressionType
|
||||
*/
|
||||
private int checkProgMode(String mode) {
|
||||
if (mode.equals("res")) {
|
||||
return ProgressionType.RES_LY_COMP_POS_PROG;
|
||||
} else if (mode.equals("layer")) {
|
||||
return ProgressionType.LY_RES_COMP_POS_PROG;
|
||||
} else if (mode.equals("pos-comp")) {
|
||||
return ProgressionType.POS_COMP_RES_LY_PROG;
|
||||
} else if (mode.equals("comp-pos")) {
|
||||
return ProgressionType.COMP_POS_RES_LY_PROG;
|
||||
} else if (mode.equals("res-pos")) {
|
||||
return ProgressionType.RES_POS_COMP_LY_PROG;
|
||||
} else {
|
||||
// No corresponding progression mode, we return -1.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* $RCSfile: StdEntropyCoderOptions.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:05 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: StdEntropyCoderOptions
|
||||
*
|
||||
* Description: Entropy coding engine of stripes in
|
||||
* code-blocks options
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy;
|
||||
|
||||
/**
|
||||
* This interface define the constants that identify the possible options for
|
||||
* the entropy coder, as well some fixed parameters of the JPEG 2000 entropy
|
||||
* coder.
|
||||
*/
|
||||
public interface StdEntropyCoderOptions {
|
||||
|
||||
/**
|
||||
* The flag bit to indicate that selective arithmetic coding bypass
|
||||
* should be used. In this mode some of the coding passes bypass the
|
||||
* arithmetic coder and raw bits are output. If this flag is turned on and
|
||||
* the 'OPT_TERM_PASS' one is turned off then the any non-bypass coding
|
||||
* pass before a bypass coding pass must use MQ termination.
|
||||
*/
|
||||
int OPT_BYPASS = 1;
|
||||
|
||||
/**
|
||||
* The flag bit to indicate that the MQ states for all contexts should be
|
||||
* reset at the end of each non-bypass coding pass.
|
||||
*/
|
||||
int OPT_RESET_MQ = 1 << 1;
|
||||
|
||||
/**
|
||||
* The flag bit to indicate that regular termination should be used. When
|
||||
* this is specified termination is performed after each coding
|
||||
* pass. Termination is applied to both arithmetically coded and bypass
|
||||
* (i.e. raw) passes .
|
||||
*/
|
||||
int OPT_TERM_PASS = 1 << 2;
|
||||
|
||||
/**
|
||||
* The flag bit to indicate the vertically stripe-causal context
|
||||
* formation should be used.
|
||||
*/
|
||||
int OPT_VERT_STR_CAUSAL = 1 << 3;
|
||||
|
||||
/**
|
||||
* The flag bit to indicate that error resilience info is embedded on MQ
|
||||
* termination. The predictable error-resilient MQ termination at the
|
||||
* encoder is necessary in this case.
|
||||
*/
|
||||
int OPT_PRED_TERM = 1 << 4;
|
||||
|
||||
/**
|
||||
* The flag bit to indicate that a segmentation marker is to be
|
||||
* inserted at the end of each normalization coding pass. The segment
|
||||
* marker is the four symbol sequence 1010 that are sent through the MQ
|
||||
* coder using the UNIFORM context.
|
||||
*/
|
||||
int OPT_SEG_SYMBOLS = 1 << 5;
|
||||
|
||||
/**
|
||||
* The minimum code-block dimension. The nominal width or height of a
|
||||
* code-block must never be less than this. It is 4.
|
||||
*/
|
||||
int MIN_CB_DIM = 4;
|
||||
|
||||
/**
|
||||
* The maximum code-block dimension. No code-block should be larger,
|
||||
* either in width or height, than this value. It is 1024.
|
||||
*/
|
||||
int MAX_CB_DIM = 1024;
|
||||
|
||||
/**
|
||||
* The maximum code-block area (width x height). The surface covered by
|
||||
* a nominal size block should never be larger than this. It is 4096
|
||||
*/
|
||||
int MAX_CB_AREA = 4096;
|
||||
|
||||
/**
|
||||
* The stripe height. This is the nominal value of the stripe height. It
|
||||
* is 4.
|
||||
*/
|
||||
int STRIPE_HEIGHT = 4;
|
||||
|
||||
/**
|
||||
* The number of coding passes per bit-plane. This is the number of
|
||||
* passes per bit-plane. It is 3.
|
||||
*/
|
||||
int NUM_PASSES = 3;
|
||||
|
||||
/**
|
||||
* The number of most significant bit-planes where bypass mode is not to
|
||||
* be used, even if bypass mode is on: 4.
|
||||
*/
|
||||
int NUM_NON_BYPASS_MS_BP = 4;
|
||||
|
||||
/**
|
||||
* The number of empty passes in the most significant bit-plane. It is
|
||||
* 2.
|
||||
*/
|
||||
int NUM_EMPTY_PASSES_IN_MS_BP = 2;
|
||||
|
||||
/**
|
||||
* The index of the first "raw" pass, if bypass mode is on.
|
||||
*/
|
||||
int FIRST_BYPASS_PASS_IDX =
|
||||
NUM_PASSES * NUM_NON_BYPASS_MS_BP - NUM_EMPTY_PASSES_IN_MS_BP;
|
||||
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* $RCSfile: ByteInputBuffer.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:05 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: ByteInputBuffer
|
||||
*
|
||||
* Description: Provides buffering for byte based input, similar
|
||||
* to the standard class ByteArrayInputStream
|
||||
*
|
||||
* the old jj2000.j2k.io.ByteArrayInput class by
|
||||
* Diego SANTA CRUZ, Apr-26-1999
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.decoder;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* This class provides a byte input facility from byte buffers. It is similar
|
||||
* to the ByteArrayInputStream class, but adds the possibility to add data to
|
||||
* the stream after the creation of the object.
|
||||
*
|
||||
* <P>Unlike the ByteArrayInputStream this class is not thread safe (i.e. no
|
||||
* two threads can use the same object at the same time, but different objects
|
||||
* may be used in different threads).
|
||||
*
|
||||
* <P>This class can modify the contents of the buffer given to the
|
||||
* constructor, when the addByteArray() method is called.
|
||||
*
|
||||
* @see InputStream
|
||||
*/
|
||||
public class ByteInputBuffer {
|
||||
|
||||
/**
|
||||
* The byte array containing the data
|
||||
*/
|
||||
private byte[] buf;
|
||||
|
||||
/**
|
||||
* The index one greater than the last valid character in the input
|
||||
* stream buffer
|
||||
*/
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* The index of the next character to read from the input stream buffer
|
||||
*/
|
||||
private int pos;
|
||||
|
||||
/**
|
||||
* Creates a new byte array input stream that reads data from the
|
||||
* specified byte array. The byte array is not copied.
|
||||
*
|
||||
* @param buf the input buffer.
|
||||
*/
|
||||
public ByteInputBuffer(byte[] buf) {
|
||||
this.buf = buf;
|
||||
count = buf.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new byte array input stream that reads data from the
|
||||
* specified byte array. Up to length characters are to be read
|
||||
* from the byte array, starting at the indicated offset.
|
||||
*
|
||||
* <P>The byte array is not copied.
|
||||
*
|
||||
* @param buf the input buffer.
|
||||
* @param offset the offset in the buffer of the first byte to
|
||||
* read.
|
||||
* @param length the maximum number of bytes to read from the
|
||||
* buffer.
|
||||
*/
|
||||
public ByteInputBuffer(byte[] buf, int offset, int length) {
|
||||
this.buf = buf;
|
||||
pos = offset;
|
||||
count = offset + length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the underlying buffer byte array to the given one, with the given
|
||||
* offset and length. If 'buf' is null then the current byte buffer is
|
||||
* assumed. If 'offset' is negative, then it will be assumed to be
|
||||
* 'off+len', where 'off' and 'len' are the offset and length of the
|
||||
* current byte buffer.
|
||||
*
|
||||
* <P>The byte array is not copied.
|
||||
*
|
||||
* @param buf the input buffer. If null it is the current input buffer.
|
||||
* @param offset the offset in the buffer of the first byte to read. If
|
||||
* negative it is assumed to be the byte just after the end of the current
|
||||
* input buffer, only permitted if 'buf' is null.
|
||||
* @param length the maximum number of bytes to read frmo the buffer.
|
||||
*/
|
||||
public void setByteArray(byte[] buf, int offset, int length) {
|
||||
// In same buffer?
|
||||
if (buf == null) {
|
||||
if (length < 0 || count + length > this.buf.length) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (offset < 0) {
|
||||
pos = count;
|
||||
count += length;
|
||||
} else {
|
||||
count = offset + length;
|
||||
pos = offset;
|
||||
}
|
||||
} else { // New input buffer
|
||||
if (offset < 0 || length < 0 || offset + length > buf.length) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.buf = buf;
|
||||
count = offset + length;
|
||||
pos = offset;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified data to the end of the byte array stream. This
|
||||
* method modifies the byte array buffer. It can also discard the already
|
||||
* read input.
|
||||
*
|
||||
* @param data The data to add. The data is copied.
|
||||
* @param off The index, in data, of the first element to add to
|
||||
* the stream.
|
||||
* @param len The number of elements to add to the array.
|
||||
*/
|
||||
public synchronized void addByteArray(byte[] data, int off, int len) {
|
||||
// Check integrity
|
||||
if (len < 0 || off < 0 || len + off > buf.length) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
// Copy new data
|
||||
if (count + len <= buf.length) { // Enough place in 'buf'
|
||||
System.arraycopy(data, off, buf, count, len);
|
||||
count += len;
|
||||
} else {
|
||||
if (count - pos + len <= buf.length) {
|
||||
// Enough place in 'buf' if we move input data
|
||||
// Move buffer
|
||||
System.arraycopy(buf, pos, buf, 0, count - pos);
|
||||
} else { // Not enough place in 'buf', use new buffer
|
||||
byte[] oldbuf = buf;
|
||||
buf = new byte[count - pos + len];
|
||||
// Copy buffer
|
||||
System.arraycopy(oldbuf, count, buf, 0, count - pos);
|
||||
}
|
||||
count -= pos;
|
||||
pos = 0;
|
||||
// Copy new data
|
||||
System.arraycopy(data, off, buf, count, len);
|
||||
count += len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next byte of data from this input stream. The value
|
||||
* byte is returned as an int in the range 0 to 255. If no byte is
|
||||
* available because the end of the stream has been reached, the
|
||||
* EOFException exception is thrown.
|
||||
*
|
||||
* <P>This method is not synchronized, so it is not thread safe.
|
||||
*
|
||||
* @return The byte read in the range 0-255.
|
||||
* @throws EOFException If the end of the stream is reached.
|
||||
*/
|
||||
public int readChecked() throws IOException {
|
||||
if (pos < count) {
|
||||
return (int) buf[pos++] & 0xFF;
|
||||
} else {
|
||||
throw new EOFException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next byte of data from this input stream. The value byte is
|
||||
* returned as an int in the range 0 to 255. If no byte is available
|
||||
* because the end of the stream has been reached, -1 is returned.
|
||||
*
|
||||
* <P>This method is not synchronized, so it is not thread safe.
|
||||
*
|
||||
* @return The byte read in the range 0-255, or -1 if the end of stream
|
||||
* has been reached.
|
||||
*/
|
||||
public int read() {
|
||||
if (pos < count) {
|
||||
return (int) buf[pos++] & 0xFF;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* $RCSfile: ByteToBitInput.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:06 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: ByteToBitInput
|
||||
*
|
||||
* Description: Adapter to perform bit based input from a byte
|
||||
* based one.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.decoder;
|
||||
|
||||
|
||||
/**
|
||||
* This class provides an adapter to perform bit based input on byte based
|
||||
* output obejcts that inherit from a 'ByteInputBuffer' class. This class also
|
||||
* performs the bit unstuffing procedure specified for the 'selective
|
||||
* arithmetic coding bypass' mode of the JPEG 2000 entropy coder.
|
||||
*/
|
||||
class ByteToBitInput {
|
||||
|
||||
/**
|
||||
* The byte based input
|
||||
*/
|
||||
ByteInputBuffer in;
|
||||
|
||||
/**
|
||||
* The bit buffer
|
||||
*/
|
||||
int bbuf;
|
||||
|
||||
/**
|
||||
* The position of the next bit to get from the byte buffer. When it is
|
||||
* -1 the bit buffer is empty.
|
||||
*/
|
||||
int bpos = -1;
|
||||
|
||||
/**
|
||||
* Instantiates a new 'ByteToBitInput' object that uses 'in' as the
|
||||
* underlying byte based input.
|
||||
*
|
||||
* @param in The underlying byte based input.
|
||||
*/
|
||||
ByteToBitInput(ByteInputBuffer in) {
|
||||
this.in = in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from the bit stream one bit. If 'bpos' is -1 then a byte is read
|
||||
* and loaded into the bit buffer, from where the bit is read. If
|
||||
* necessary the bit unstuffing will be applied.
|
||||
*
|
||||
* @return The read bit (0 or 1).
|
||||
*/
|
||||
final int readBit() {
|
||||
if (bpos < 0) {
|
||||
if ((bbuf & 0xFF) != 0xFF) { // Normal byte to read
|
||||
bbuf = in.read();
|
||||
bpos = 7;
|
||||
} else { // Previous byte is 0xFF => there was bit stuffing
|
||||
bbuf = in.read();
|
||||
bpos = 6;
|
||||
}
|
||||
}
|
||||
return (bbuf >> bpos--) & 0x01;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for past errors in the decoding process by verifying the byte
|
||||
* padding with an alternating sequence of 0's and 1's. If an error is
|
||||
* detected it means that the raw bit stream has been wrongly decoded or
|
||||
* that the raw terminated segment length is too long. If no errors are
|
||||
* detected it does not necessarily mean that the raw bit stream has been
|
||||
* correctly decoded.
|
||||
*
|
||||
* @return True if errors are found, false otherwise.
|
||||
*/
|
||||
public boolean checkBytePadding() {
|
||||
int seq; // Byte padding sequence in last byte
|
||||
|
||||
// If there are no spare bits and bbuf is 0xFF (not EOF), then there
|
||||
// is a next byte with bit stuffing that we must load.
|
||||
if (bpos < 0 && (bbuf & 0xFF) == 0xFF) {
|
||||
bbuf = in.read();
|
||||
bpos = 6;
|
||||
}
|
||||
|
||||
// 1) Not yet read bits in the last byte must be an alternating
|
||||
// sequence of 0s and 1s, starting with 0.
|
||||
if (bpos >= 0) {
|
||||
seq = bbuf & ((1 << (bpos + 1)) - 1);
|
||||
if (seq != (0x55 >> (7 - bpos))) return true;
|
||||
}
|
||||
|
||||
// 2) We must have already reached the last byte in the terminated
|
||||
// segment, unless last bit read is LSB of FF in which case an encoder
|
||||
// can output an extra byte which is smaller than 0x80.
|
||||
if (bbuf != -1) {
|
||||
if (bbuf == 0xFF && bpos == 0) {
|
||||
return (in.read() & 0xFF) >= 0x80;
|
||||
} else {
|
||||
return in.read() != -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing detected
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes (i.e. empties) the bit buffer, without loading any new
|
||||
* bytes. This realigns the input at the next byte boundary, if not
|
||||
* already at one.
|
||||
*/
|
||||
final void flush() {
|
||||
bbuf = 0; // reset any bit stuffing state
|
||||
bpos = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the underlying byte input to start a new segment. The bit buffer
|
||||
* is flushed.
|
||||
*
|
||||
* @param buf The byte array containing the byte data. If null the
|
||||
* current byte array is assumed.
|
||||
* @param off The index of the first element in 'buf' to be decoded. If
|
||||
* negative the byte just after the previous segment is assumed, only
|
||||
* valid if 'buf' is null.
|
||||
* @param len The number of bytes in 'buf' to be decoded. Any subsequent
|
||||
* bytes are taken to be 0xFF.
|
||||
*/
|
||||
final void setByteArray(byte[] buf, int off, int len) {
|
||||
in.setByteArray(buf, off, len);
|
||||
bbuf = 0; // reset any bit stuffing state
|
||||
bpos = -1;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* $RCSfile: CodedCBlkDataSrcDec.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:06 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: CodedCBlkDataSrcDec
|
||||
*
|
||||
* Description: Interface that defines a source of entropy coded
|
||||
* data that is transferred in a code-block by
|
||||
* code-block basis (decoder side).
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.decoder;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.synthesis.InvWTData;
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.synthesis.SubbandSyn;
|
||||
import org.xbib.graphics.jpeg2000.j2k.codestream.reader.BitstreamReaderAgent;
|
||||
|
||||
/**
|
||||
* This interface defines a source of entropy coded data and methods to
|
||||
* transfer it in a code-block by code-block basis. In each call to
|
||||
* 'geCodeBlock()' a specified coded code-block is returned.
|
||||
*
|
||||
* <P>This interface is the source of data for the entropy decoder. See the
|
||||
* 'EntropyDecoder' class.
|
||||
*
|
||||
* <P>For each coded-code-block the entropy-coded data is returned along with
|
||||
* its truncation point information in a 'DecLyrdCBlk' object.
|
||||
*
|
||||
* @see EntropyDecoder
|
||||
* @see DecLyrdCBlk
|
||||
* @see BitstreamReaderAgent
|
||||
*/
|
||||
public interface CodedCBlkDataSrcDec extends InvWTData {
|
||||
|
||||
/**
|
||||
* Returns the specified coded code-block, for the specified component, in
|
||||
* the current tile. The first layer to return is indicated by 'fl'. The
|
||||
* number of layers that is returned depends on 'nl' and the amount of
|
||||
* data available.
|
||||
*
|
||||
* <P>The argument 'fl' is to be used by subsequent calls to this method
|
||||
* for the same code-block. In this way supplamental data can be retrieved
|
||||
* at a later time. The fact that data from more than one layer can be
|
||||
* returned means that several packets from the same code-block, of the
|
||||
* same component, and the same tile, have been concatenated.
|
||||
*
|
||||
* <P>The returned compressed code-block can have its progressive
|
||||
* attribute set. If this attribute is set it means that more data can be
|
||||
* obtained by subsequent calls to this method (subject to transmission
|
||||
* delays, etc). If the progressive attribute is not set it means that the
|
||||
* returned data is all the data that can be obtained for the specified
|
||||
* subblock.
|
||||
*
|
||||
* <P>The compressed code-block is uniquely specified by the current tile,
|
||||
* the component (identified by 'c'), the subband (indentified by 'sb')
|
||||
* and the code-bock vertical and horizontal indexes 'm' and 'n'.
|
||||
*
|
||||
* <P>The 'ulx' and 'uly' members of the returned 'DecLyrdCBlk' object
|
||||
* contain the coordinates of the top-left corner of the block, with
|
||||
* respect to the tile, not the subband.
|
||||
*
|
||||
* @param c The index of the component, from 0 to N-1.
|
||||
* @param m The vertical index of the code-block to return, in the
|
||||
* specified subband.
|
||||
* @param n The horizontal index of the code-block to return, in the
|
||||
* specified subband.
|
||||
* @param sb The subband in whic the requested code-block is.
|
||||
* @param fl The first layer to return.
|
||||
* @param nl The number of layers to return, if negative all available
|
||||
* layers are returned, starting at 'fl'.
|
||||
* @param ccb If not null this object is used to return the compressed
|
||||
* code-block. If null a new object is created and returned. If the data
|
||||
* array in ccb is not null then it can be reused to return the compressed
|
||||
* data.
|
||||
* @return The compressed code-block, with a certain number of layers
|
||||
* determined by the available data and 'nl'.
|
||||
*/
|
||||
DecLyrdCBlk getCodeBlock(int c, int m, int n,
|
||||
SubbandSyn sb, int fl, int nl,
|
||||
DecLyrdCBlk ccb);
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* $RCSfile: DecLyrdCBlk.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:06 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: DecLyrdCBlk
|
||||
*
|
||||
* Description: The coded (compressed) code-block
|
||||
* with layered organization for the decoder.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.decoder;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.CodedCBlk;
|
||||
|
||||
/**
|
||||
* This class stores coded (compressed) code-blocks that are organized
|
||||
* in layers. This object can contain either all the data of the
|
||||
* code-block (i.e. all layers), or a subset of all the layers that
|
||||
* make up the whole compressed-code-block. It is applicable to the
|
||||
* decoder engine only. Some data of the coded-block is stored
|
||||
* in the super class, see CodedCBlk.
|
||||
*
|
||||
* <P>A code-block may have its progressive attribute set (i.e. the
|
||||
* 'prog' flag is true). If a code-block is progressive then it means
|
||||
* that more data for it may be obtained for an improved quality. If
|
||||
* the progressive flag is false then no more data is available from
|
||||
* the source for this code-block.
|
||||
*
|
||||
* @see CodedCBlk
|
||||
*/
|
||||
public class DecLyrdCBlk extends CodedCBlk {
|
||||
|
||||
/**
|
||||
* The horizontal coordinate of the upper-left corner of the code-block
|
||||
*/
|
||||
public int ulx;
|
||||
|
||||
/**
|
||||
* The vertical coordinate of the upper left corner of the code-block
|
||||
*/
|
||||
public int uly;
|
||||
|
||||
/**
|
||||
* The width of the code-block
|
||||
*/
|
||||
public int w;
|
||||
|
||||
/**
|
||||
* The height of the code-block
|
||||
*/
|
||||
public int h;
|
||||
|
||||
/**
|
||||
* The coded (compressed) data length. The data is stored in the
|
||||
* 'data' array (see super class).
|
||||
*/
|
||||
public int dl;
|
||||
|
||||
/**
|
||||
* The progressive flag, false by default (see above).
|
||||
*/
|
||||
public boolean prog;
|
||||
|
||||
/**
|
||||
* The number of layers in the coded data.
|
||||
*/
|
||||
public int nl;
|
||||
|
||||
/**
|
||||
* The index of the first truncation point returned
|
||||
*/
|
||||
public int ftpIdx;
|
||||
|
||||
/**
|
||||
* The total number of truncation points from layer 1 to the last one in
|
||||
* this object. The number of truncation points in 'data' is
|
||||
* 'nTrunc-ftpIdx'.
|
||||
*/
|
||||
public int nTrunc;
|
||||
|
||||
/**
|
||||
* The length of each terminated segment. If null then there is only one
|
||||
* terminated segment, and its length is 'dl'. The number of terminated
|
||||
* segments is to be deduced from 'ftpIdx', 'nTrunc' and the coding
|
||||
* options. This array contains all terminated segments from the 'ftpIdx'
|
||||
* truncation point, upto, and including, the 'nTrunc-1' truncation
|
||||
* point. Any data after 'nTrunc-1' is not included in any length.
|
||||
*/
|
||||
public int[] tsLengths;
|
||||
|
||||
/**
|
||||
* Object information in a string
|
||||
*
|
||||
* @return Information in a string
|
||||
*/
|
||||
public String toString() {
|
||||
String str =
|
||||
"Coded code-block (" + m + "," + n + "): " + skipMSBP + " MSB skipped, " +
|
||||
dl + " bytes, " + nTrunc + " truncation points, " + nl + " layers, " +
|
||||
"progressive= " + prog + ", ulx= " + ulx + ", uly= " + uly +
|
||||
", w= " + w + ", h= " + h + ", ftpIdx=" + ftpIdx;
|
||||
if (tsLengths != null) {
|
||||
str += " {";
|
||||
for (int i = 0; i < tsLengths.length; i++)
|
||||
str += " " + tsLengths[i];
|
||||
str += " }";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* $RCSfile: EntropyDecoder.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:06 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: EntropyDecoder
|
||||
*
|
||||
* Description: The abstract class for all entropy decoders.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.decoder;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.dequantizer.CBlkQuantDataSrcDec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.synthesis.MultiResImgData;
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.synthesis.MultiResImgDataAdapter;
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.synthesis.SubbandSyn;
|
||||
|
||||
/**
|
||||
* This is the abstract class from which all entropy decoders must
|
||||
* inherit. This class implements the 'MultiResImgData', therefore it has the
|
||||
* concept of a current tile and all operations are performed on the current
|
||||
* tile.
|
||||
*
|
||||
* <P>Default implementations of the methods in 'MultiResImgData' are provided
|
||||
* through the 'MultiResImgDataAdapter' abstract class.
|
||||
*
|
||||
* <P>Sign magnitude representation is used (instead of two's complement) for
|
||||
* the output data. The most significant bit is used for the sign (0 if
|
||||
* positive, 1 if negative). Then the magnitude of the quantized coefficient
|
||||
* is stored in the next most significat bits. The most significant magnitude
|
||||
* bit corresponds to the most significant bit-plane and so on.
|
||||
*
|
||||
* @see MultiResImgData
|
||||
* @see MultiResImgDataAdapter
|
||||
*/
|
||||
public abstract class EntropyDecoder extends MultiResImgDataAdapter
|
||||
implements CBlkQuantDataSrcDec {
|
||||
|
||||
/**
|
||||
* The prefix for entropy decoder optiojns: 'C'
|
||||
*/
|
||||
public final static char OPT_PREFIX = 'C';
|
||||
|
||||
/**
|
||||
* The list of parameters that is accepted by the entropy
|
||||
* decoders. They start with 'C'.
|
||||
*/
|
||||
private final static String[][] pinfo = {
|
||||
{"Cverber", "[true|false]",
|
||||
"Specifies if the entropy decoder should be verbose about detected " +
|
||||
"errors. If 'true' a message is printed whenever an error is detected.",
|
||||
"true"},
|
||||
{"Cer", "[true|false]",
|
||||
"Specifies if error detection should be performed by the entropy " +
|
||||
"decoder engine. If errors are detected they will be concealed and " +
|
||||
"the resulting distortion will be less important. Note that errors " +
|
||||
"can only be detected if the encoder that generated the data " +
|
||||
"included error resilience information.", "true"},
|
||||
};
|
||||
|
||||
/**
|
||||
* The bit stream transport from where to get the compressed data
|
||||
* (the source)
|
||||
*/
|
||||
protected CodedCBlkDataSrcDec src;
|
||||
|
||||
/**
|
||||
* Initializes the source of compressed data.
|
||||
*
|
||||
* @param src From where to obtain the compressed data.
|
||||
*/
|
||||
public EntropyDecoder(CodedCBlkDataSrcDec src) {
|
||||
super(src);
|
||||
this.src = src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameters that are used in this class and
|
||||
* implementing classes. It returns a 2D String array. Each of the
|
||||
* 1D arrays is for a different option, and they have 3
|
||||
* elements. The first element is the option name, the second one
|
||||
* is the synopsis and the third one is a long description of what
|
||||
* the parameter is. The synopsis or description may be 'null', in
|
||||
* which case it is assumed that there is no synopsis or
|
||||
* description of the option, respectively. Null may be returned
|
||||
* if no options are supported.
|
||||
*
|
||||
* @return the options name, their synopsis and their explanation,
|
||||
* or null if no options are supported.
|
||||
*/
|
||||
public static String[][] getParameterInfo() {
|
||||
return pinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subband tree, for the specified tile-component. This method
|
||||
* returns the root element of the subband tree structure, see Subband and
|
||||
* SubbandSyn. The tree comprises all the available resolution levels.
|
||||
*
|
||||
* <P>The number of magnitude bits ('magBits' member variable) for
|
||||
* each subband is not initialized.
|
||||
*
|
||||
* @param t The index of the tile, from 0 to T-1.
|
||||
* @param c The index of the component, from 0 to C-1.
|
||||
* @return The root of the tree structure.
|
||||
*/
|
||||
|
||||
public SubbandSyn getSynSubbandTree(int t, int c) {
|
||||
return src.getSynSubbandTree(t, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the horizontal code-block partition origin. Allowable values
|
||||
* are 0 and 1, nothing else.
|
||||
*/
|
||||
public int getCbULX() {
|
||||
return src.getCbULX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertical code-block partition origin. Allowable values are
|
||||
* 0 and 1, nothing else.
|
||||
*/
|
||||
public int getCbULY() {
|
||||
return src.getCbULY();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,714 @@
|
|||
/*
|
||||
* $RCSfile: MQDecoder.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:06 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: MQDecoder
|
||||
*
|
||||
* Description: Class that encodes a number of bits using the
|
||||
* MQ arithmetic decoder
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.decoder;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.util.ArrayUtil;
|
||||
|
||||
/**
|
||||
* This class implements the MQ arithmetic decoder. It is implemented using
|
||||
* the software conventions decoder for better performance (i.e. execution
|
||||
* time performance). The initial states for each context of the MQ-coder are
|
||||
* specified in the constructor.
|
||||
*/
|
||||
|
||||
// A trick to test for increased speed: merge the Qe and mPS into 1 thing by
|
||||
// using the sign bit of Qe to signal mPS (positive-or-0 is 0, negative is 1),
|
||||
// and doubling the Qe, nMPS and nLPS tables. This gets rid of the swicthLM
|
||||
// table since it can be integrated as special cases in the doubled nMPS and
|
||||
// nLPS tables. See the JPEG book, chapter 13. The decoded decision can be
|
||||
// calculated as (q>>>31).
|
||||
|
||||
public class MQDecoder {
|
||||
|
||||
/**
|
||||
* The data structures containing the probabilities for the LPS
|
||||
*/
|
||||
final static
|
||||
int[] qe = {0x5601, 0x3401, 0x1801, 0x0ac1, 0x0521, 0x0221, 0x5601,
|
||||
0x5401, 0x4801, 0x3801, 0x3001, 0x2401, 0x1c01, 0x1601,
|
||||
0x5601, 0x5401, 0x5101, 0x4801, 0x3801, 0x3401, 0x3001,
|
||||
0x2801, 0x2401, 0x2201, 0x1c01, 0x1801, 0x1601, 0x1401,
|
||||
0x1201, 0x1101, 0x0ac1, 0x09c1, 0x08a1, 0x0521, 0x0441,
|
||||
0x02a1, 0x0221, 0x0141, 0x0111, 0x0085, 0x0049, 0x0025,
|
||||
0x0015, 0x0009, 0x0005, 0x0001, 0x5601};
|
||||
|
||||
/**
|
||||
* The indexes of the next MPS
|
||||
*/
|
||||
final static
|
||||
int[] nMPS = {1, 2, 3, 4, 5, 38, 7, 8, 9, 10, 11, 12, 13, 29, 15, 16, 17,
|
||||
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
|
||||
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 46};
|
||||
|
||||
/**
|
||||
* The indexes of the next LPS
|
||||
*/
|
||||
final static
|
||||
int[] nLPS = {1, 6, 9, 12, 29, 33, 6, 14, 14, 14, 17, 18, 20, 21, 14, 14, 15,
|
||||
16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46};
|
||||
|
||||
/**
|
||||
* Whether LPS and MPS should be switched
|
||||
*/
|
||||
final static
|
||||
int[] switchLM = {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
/**
|
||||
* The initial state of each context
|
||||
*/
|
||||
final int[] initStates;
|
||||
/**
|
||||
* The ByteInputBuffer used to read the compressed bit stream.
|
||||
*/
|
||||
ByteInputBuffer in;
|
||||
/**
|
||||
* The current most probable signal for each context
|
||||
*/
|
||||
int[] mPS;
|
||||
/**
|
||||
* The current index of each context
|
||||
*/
|
||||
int[] I;
|
||||
/**
|
||||
* The current bit code
|
||||
*/
|
||||
int c;
|
||||
/**
|
||||
* The bit code counter
|
||||
*/
|
||||
int cT;
|
||||
/**
|
||||
* The current interval
|
||||
*/
|
||||
int a;
|
||||
/**
|
||||
* The last byte read
|
||||
*/
|
||||
int b;
|
||||
/**
|
||||
* Flag indicating if a marker has been found
|
||||
*/
|
||||
boolean markerFound;
|
||||
|
||||
/**
|
||||
* Instantiates a new MQ-decoder, with the specified number of contexts and
|
||||
* initial states. The compressed bytestream is read from the 'iStream'
|
||||
* object.
|
||||
*
|
||||
* @param iStream the stream that contains the coded bits
|
||||
* @param nrOfContexts The number of contexts used
|
||||
* @param initStates The initial state for each context. A reference is
|
||||
* kept to this array to reinitialize the contexts whenever 'reset()' or
|
||||
* 'resetCtxts()' is called.
|
||||
*/
|
||||
public MQDecoder(ByteInputBuffer iStream, int nrOfContexts,
|
||||
int[] initStates) {
|
||||
in = iStream;
|
||||
|
||||
// Default initialization of the statistics bins is MPS=0 and
|
||||
// I=0
|
||||
I = new int[nrOfContexts];
|
||||
mPS = new int[nrOfContexts];
|
||||
// Save the initial states
|
||||
this.initStates = initStates;
|
||||
|
||||
// Initialize
|
||||
init();
|
||||
|
||||
// Set the contexts
|
||||
resetCtxts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes 'n' symbols from the bit stream using the same context
|
||||
* 'ctxt'. If possible the MQ-coder speedup mode will be used to speed up
|
||||
* decoding. The speedup mode is used if Q (the LPS probability for 'ctxt'
|
||||
* is low enough) and the A and C registers permit decoding several MPS
|
||||
* symbols without renormalization.
|
||||
*
|
||||
* <P>Speedup mode should be used when decoding long runs of MPS with high
|
||||
* probability with the same context.
|
||||
*
|
||||
* <P>This methiod will return the decoded symbols differently if speedup
|
||||
* mode was used or not. If true is returned, then speedup mode was used
|
||||
* and the 'n' decoded symbols are all the same and it is returned ain
|
||||
* bits[0] only. If false is returned then speedup mode was not used, the
|
||||
* decoded symbols are probably not all the same and they are returned in
|
||||
* bits[0], bits[1], ... bits[n-1].
|
||||
*
|
||||
* @param bits The array where to put the decoded symbols. Must be of
|
||||
* length 'n' or more.
|
||||
* @param ctxt The context to use in decoding the symbols.
|
||||
* @param n The number of symbols to decode.
|
||||
* @return True if speedup mode was used, false if not. If speedup mode
|
||||
* was used then all the decoded symbols are the same and its value is
|
||||
* returned in 'bits[0]' only (not in bits[1], bits[2], etc.).
|
||||
*/
|
||||
public final boolean fastDecodeSymbols(int[] bits, int ctxt, int n) {
|
||||
int q; // LPS probability for context
|
||||
int idx; // Index of current state
|
||||
int la; // cache for A register
|
||||
int i; // counter
|
||||
|
||||
idx = I[ctxt];
|
||||
q = qe[idx];
|
||||
|
||||
// This is a first attempt to implement speedup mode, it is probably
|
||||
// not the most efficient way of doing it.
|
||||
|
||||
if ((q < 0x4000) && (n <= (a - (c >>> 16) - 1) / q) &&
|
||||
(n <= (a - 0x8000) / q + 1)) {
|
||||
// Q is small enough. There will be no modification of C that
|
||||
// affects decoding, and Q can be substracted from A several
|
||||
// times. We will decode all MPS.
|
||||
a -= n * q;
|
||||
if (a >= 0x8000) { // No renormalization needed
|
||||
bits[0] = mPS[ctxt];
|
||||
return true; // Done, used speedup mode
|
||||
} else { // renormalization needed
|
||||
I[ctxt] = nMPS[idx];
|
||||
// Renormalize (MPS: no need for while loop)
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
a <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
// End renormalization
|
||||
bits[0] = mPS[ctxt];
|
||||
return true; // Done, used speedup mode
|
||||
}
|
||||
} else { // Normal mode
|
||||
la = a; // cache A register
|
||||
for (i = 0; i < n; i++) {
|
||||
la -= q;
|
||||
if ((c >>> 16) < la) {
|
||||
if (la >= 0x8000) {
|
||||
bits[i] = mPS[ctxt];
|
||||
} else {
|
||||
// -- MPS Exchange
|
||||
if (la >= q) {
|
||||
bits[i] = mPS[ctxt];
|
||||
idx = nMPS[idx];
|
||||
q = qe[idx];
|
||||
// I[ctxt] set at end of loop
|
||||
// -- Renormalize (MPS: no need for while loop)
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
la <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
// -- End renormalization
|
||||
} else {
|
||||
bits[i] = 1 - mPS[ctxt];
|
||||
if (switchLM[idx] == 1)
|
||||
mPS[ctxt] = 1 - mPS[ctxt];
|
||||
idx = nLPS[idx];
|
||||
q = qe[idx];
|
||||
// I[ctxt] set at end of loop
|
||||
// -- Renormalize
|
||||
do {
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
la <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
} while (la < 0x8000);
|
||||
// -- End renormalization
|
||||
}
|
||||
// -- End MPS Exchange
|
||||
}
|
||||
} else {
|
||||
c -= (la << 16);
|
||||
// -- LPS Exchange
|
||||
if (la < q) {
|
||||
la = q;
|
||||
bits[i] = mPS[ctxt];
|
||||
idx = nMPS[idx];
|
||||
q = qe[idx];
|
||||
// I[ctxt] set at end of loop
|
||||
// -- Renormalize (MPS: no need for while loop)
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
la <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
// -- End renormalization
|
||||
} else {
|
||||
la = q;
|
||||
bits[i] = 1 - mPS[ctxt];
|
||||
if (switchLM[idx] == 1)
|
||||
mPS[ctxt] = 1 - mPS[ctxt];
|
||||
idx = nLPS[idx];
|
||||
q = qe[idx];
|
||||
// I[ctxt] set at end of loop
|
||||
// -- Renormalize
|
||||
do {
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
la <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
} while (la < 0x8000);
|
||||
// -- End renormalization
|
||||
}
|
||||
// -- End LPS Exchange
|
||||
}
|
||||
}
|
||||
a = la; // save cached A register
|
||||
I[ctxt] = idx; // save current index for context
|
||||
return false; // done, did not use speedup mode
|
||||
} // End normal mode
|
||||
}
|
||||
|
||||
/**
|
||||
* This function performs the arithmetic decoding. The function receives
|
||||
* an array in which to put the decoded symbols and an array of contexts
|
||||
* with which to decode them.
|
||||
*
|
||||
* <P>Each context has a current MPS and an index describing what the
|
||||
* current probability is for the LPS. Each bit is decoded and if the
|
||||
* probability of the LPS exceeds .5, the MPS and LPS are switched.
|
||||
*
|
||||
* @param bits The array where to place the decoded symbols. It should be
|
||||
* long enough to contain 'n' elements.
|
||||
* @param cX The context to use in decoding each symbol.
|
||||
* @param n The number of symbols to decode
|
||||
*/
|
||||
public final void decodeSymbols(int[] bits, int[] cX, int n) {
|
||||
int q;
|
||||
int ctxt;
|
||||
int la; // cache for A register value
|
||||
int index;
|
||||
int i;
|
||||
|
||||
// NOTE: (a < 0x8000) is equivalent to ((a & 0x8000)==0)
|
||||
// since 'a' is always less than or equal to 0xFFFF
|
||||
|
||||
// NOTE: conditional exchange guarantees that A for MPS is
|
||||
// always greater than 0x4000 (i.e. 0.375)
|
||||
// => one renormalization shift is enough for MPS
|
||||
// => no need to do a renormalization while loop for MPS
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
ctxt = cX[i];
|
||||
|
||||
index = I[ctxt];
|
||||
q = qe[index];
|
||||
|
||||
a -= q;
|
||||
if ((c >>> 16) < a) {
|
||||
if (a >= 0x8000) {
|
||||
bits[i] = mPS[ctxt];
|
||||
} else {
|
||||
la = a;
|
||||
// -- MPS Exchange
|
||||
if (la >= q) {
|
||||
bits[i] = mPS[ctxt];
|
||||
I[ctxt] = nMPS[index];
|
||||
// -- Renormalize (MPS: no need for while loop)
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
la <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
// -- End renormalization
|
||||
} else {
|
||||
bits[i] = 1 - mPS[ctxt];
|
||||
if (switchLM[index] == 1)
|
||||
mPS[ctxt] = 1 - mPS[ctxt];
|
||||
I[ctxt] = nLPS[index];
|
||||
// -- Renormalize
|
||||
do {
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
la <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
} while (la < 0x8000);
|
||||
// -- End renormalization
|
||||
}
|
||||
// -- End MPS Exchange
|
||||
a = la;
|
||||
}
|
||||
} else {
|
||||
la = a;
|
||||
c -= (la << 16);
|
||||
// -- LPS Exchange
|
||||
if (la < q) {
|
||||
la = q;
|
||||
bits[i] = mPS[ctxt];
|
||||
I[ctxt] = nMPS[index];
|
||||
// -- Renormalize (MPS: no need for while loop)
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
la <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
// -- End renormalization
|
||||
} else {
|
||||
la = q;
|
||||
bits[i] = 1 - mPS[ctxt];
|
||||
if (switchLM[index] == 1)
|
||||
mPS[ctxt] = 1 - mPS[ctxt];
|
||||
I[ctxt] = nLPS[index];
|
||||
// -- Renormalize
|
||||
do {
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
la <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
} while (la < 0x8000);
|
||||
// -- End renormalization
|
||||
}
|
||||
// -- End LPS Exchange
|
||||
|
||||
a = la;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Arithmetically decodes one symbol from the bit stream with the given
|
||||
* context and returns its decoded value.
|
||||
*
|
||||
* <P>Each context has a current MPS and an index describing what the
|
||||
* current probability is for the LPS. Each bit is encoded and if the
|
||||
* probability of the LPS exceeds .5, the MPS and LPS are switched.
|
||||
*
|
||||
* @param context The context to use in decoding the symbol
|
||||
* @return The decoded symbol, 0 or 1.
|
||||
*/
|
||||
public final int decodeSymbol(int context) {
|
||||
int q;
|
||||
int la;
|
||||
int index;
|
||||
int decision;
|
||||
|
||||
index = I[context];
|
||||
q = qe[index];
|
||||
|
||||
// NOTE: (a < 0x8000) is equivalent to ((a & 0x8000)==0)
|
||||
// since 'a' is always less than or equal to 0xFFFF
|
||||
|
||||
// NOTE: conditional exchange guarantees that A for MPS is
|
||||
// always greater than 0x4000 (i.e. 0.375)
|
||||
// => one renormalization shift is enough for MPS
|
||||
// => no need to do a renormalization while loop for MPS
|
||||
|
||||
a -= q;
|
||||
if ((c >>> 16) < a) {
|
||||
if (a >= 0x8000) {
|
||||
decision = mPS[context];
|
||||
} else {
|
||||
la = a;
|
||||
// -- MPS Exchange
|
||||
if (la >= q) {
|
||||
decision = mPS[context];
|
||||
I[context] = nMPS[index];
|
||||
// -- Renormalize (MPS: no need for while loop)
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
la <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
// -- End renormalization
|
||||
} else {
|
||||
decision = 1 - mPS[context];
|
||||
if (switchLM[index] == 1)
|
||||
mPS[context] = 1 - mPS[context];
|
||||
I[context] = nLPS[index];
|
||||
// -- Renormalize
|
||||
do {
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
la <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
} while (la < 0x8000);
|
||||
// -- End renormalization
|
||||
}
|
||||
// -- End MPS Exchange
|
||||
a = la;
|
||||
}
|
||||
} else {
|
||||
la = a;
|
||||
c -= (la << 16);
|
||||
// -- LPS Exchange
|
||||
if (la < q) {
|
||||
la = q;
|
||||
decision = mPS[context];
|
||||
I[context] = nMPS[index];
|
||||
// -- Renormalize (MPS: no need for while loop)
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
la <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
// -- End renormalization
|
||||
} else {
|
||||
la = q;
|
||||
decision = 1 - mPS[context];
|
||||
if (switchLM[index] == 1)
|
||||
mPS[context] = 1 - mPS[context];
|
||||
I[context] = nLPS[index];
|
||||
// -- Renormalize
|
||||
do {
|
||||
if (cT == 0)
|
||||
byteIn();
|
||||
la <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
} while (la < 0x8000);
|
||||
// -- End renormalization
|
||||
}
|
||||
// -- End LPS Exchange
|
||||
|
||||
a = la;
|
||||
}
|
||||
return decision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for past errors in the decoding process using the predictable
|
||||
* error resilient termination. This works only if the encoder used the
|
||||
* predictable error resilient MQ termination, otherwise it reports wrong
|
||||
* results. If an error is detected it means that the MQ bit stream has
|
||||
* been wrongly decoded or that the MQ terminated segment length is too
|
||||
* long. If no errors are detected it does not necessarily mean that the
|
||||
* MQ bit stream has been correctly decoded.
|
||||
*
|
||||
* @return True if errors are found, false otherwise.
|
||||
*/
|
||||
public boolean checkPredTerm() {
|
||||
int k; // Number of bits that where added in the termination process
|
||||
int q;
|
||||
|
||||
// 1) if everything has been OK, 'b' must be 0xFF if a terminating
|
||||
// marker has not yet been found
|
||||
if (b != 0xFF && !markerFound) return true;
|
||||
|
||||
// 2) if cT is not 0, we must have already reached the terminating
|
||||
// marker
|
||||
if (cT != 0 && !markerFound) return true;
|
||||
|
||||
// 3) If cT is 1 there where no spare bits at the encoder, this is all
|
||||
// that we can check
|
||||
if (cT == 1) return false;
|
||||
|
||||
// 4) if cT is 0, then next byte must be the second byte of a
|
||||
// terminating marker (i.e. larger than 0x8F) if the terminating
|
||||
// marker has not been reached yet
|
||||
if (cT == 0) {
|
||||
if (!markerFound) {
|
||||
// Get next byte and check
|
||||
b = in.read() & 0xFF;
|
||||
if (b <= 0x8F) return true;
|
||||
}
|
||||
// Adjust cT for last byte
|
||||
cT = 8;
|
||||
}
|
||||
|
||||
// 5) Now we can calculate the number 'k' of bits having error
|
||||
// resilience information, which is the number of bits left to
|
||||
// normalization in the C register, minus 1.
|
||||
k = cT - 1;
|
||||
|
||||
// 6) The predictable termination policy is as if an LPS interval was
|
||||
// coded that caused a renormalization of 'k' bits, before the
|
||||
// termination marker started
|
||||
|
||||
// We first check if an LPS is decoded, that causes a renormalization
|
||||
// of 'k' bits. Worst case is smallest LPS probability 'q' that causes
|
||||
// a renormalization of 'k' bits.
|
||||
q = 0x8000 >> k;
|
||||
|
||||
// Check that we can decode an LPS interval of probability 'q'
|
||||
a -= q;
|
||||
if ((c >>> 16) < a) {
|
||||
// Error: MPS interval decoded
|
||||
return true;
|
||||
}
|
||||
// OK: LPS interval decoded
|
||||
c -= (a << 16);
|
||||
// -- LPS Exchange
|
||||
// Here 'a' can not be smaller than 'q' because the minimum value
|
||||
// for 'a' is 0x8000-0x4000=0x4000 and 'q' is set to a value equal
|
||||
// to or smaller than that.
|
||||
a = q;
|
||||
// -- Renormalize
|
||||
do {
|
||||
if (cT == 0) byteIn();
|
||||
a <<= 1;
|
||||
c <<= 1;
|
||||
cT--;
|
||||
} while (a < 0x8000);
|
||||
// -- End renormalization
|
||||
// -- End LPS Exchange
|
||||
|
||||
// 7) Everything seems OK, we have checked the C register for the LPS
|
||||
// symbols and ensured that it is followed by bits synthetized by the
|
||||
// termination marker.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function gets one byte of compressed bits from the in-stream.
|
||||
* the byte is added to c. If the byte is 0xFF and the next byte is greater
|
||||
* than 0x8F, the byte after 0xFF is a marker.
|
||||
*/
|
||||
private void byteIn() {
|
||||
if (!markerFound) {
|
||||
if (b == 0xFF) {
|
||||
b = in.read() & 0xFF; // Convert EOFs (-1) to 0xFF
|
||||
|
||||
if (b > 0x8F) {
|
||||
markerFound = true;
|
||||
// software-convention decoder: c unchanged
|
||||
cT = 8;
|
||||
} else {
|
||||
c += 0xFE00 - (b << 9);
|
||||
cT = 7;
|
||||
}
|
||||
} else {
|
||||
b = in.read() & 0xFF; // Convert EOFs (-1) to 0xFF
|
||||
c += 0xFF00 - (b << 8);
|
||||
cT = 8;
|
||||
}
|
||||
} else {
|
||||
// software-convention decoder: c unchanged
|
||||
cT = 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of contexts in the arithmetic coder.
|
||||
*
|
||||
* @return The number of contexts
|
||||
**/
|
||||
public final int getNumCtxts() {
|
||||
return I.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a context to the original probability distribution.
|
||||
*
|
||||
* @param c The number of the context (it starts at 0).
|
||||
*/
|
||||
public final void resetCtxt(int c) {
|
||||
I[c] = initStates[c];
|
||||
mPS[c] = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a context to the original probability distribution. The
|
||||
* original probability distribution depends on the actual
|
||||
* implementation of the arithmetic coder or decoder.
|
||||
*
|
||||
*/
|
||||
public final void resetCtxts() {
|
||||
System.arraycopy(initStates, 0, I, 0, I.length);
|
||||
ArrayUtil.intArraySet(mPS, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the MQ decoder to start a new segment. This is like recreating a
|
||||
* new MQDecoder object with new input data.
|
||||
*
|
||||
* @param buf The byte array containing the MQ encoded data. If null the
|
||||
* current byte array is assumed.
|
||||
* @param off The index of the first element in 'buf' to be decoded. If
|
||||
* negative the byte just after the previous segment is assumed, only
|
||||
* valid if 'buf' is null.
|
||||
* @param len The number of bytes in 'buf' to be decoded. Any subsequent
|
||||
* bytes are taken to be 0xFF.
|
||||
*/
|
||||
public final void nextSegment(byte[] buf, int off, int len) {
|
||||
// Set the new input
|
||||
in.setByteArray(buf, off, len);
|
||||
// Reinitialize MQ
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying 'ByteInputBuffer' from where the MQ
|
||||
* coded input bytes are read.
|
||||
*
|
||||
* @return The underlying ByteInputBuffer.
|
||||
*/
|
||||
public ByteInputBuffer getByteInputBuffer() {
|
||||
return in;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the state of the MQ coder, without modifying the current
|
||||
* context states. It sets the registers (A,C,B) and the "marker found"
|
||||
* state to the initial state, to start the decoding of a new segment.
|
||||
*
|
||||
* <P>To have a complete reset of the MQ (as if a new MQDecoder object was
|
||||
* created) 'resetCtxts()' should be called after this method.
|
||||
*/
|
||||
private void init() {
|
||||
// --- INITDEC
|
||||
markerFound = false;
|
||||
|
||||
// Read first byte
|
||||
b = in.read() & 0xFF;
|
||||
|
||||
// Software conventions decoder
|
||||
c = (b ^ 0xFF) << 16;
|
||||
byteIn();
|
||||
c = c << 7;
|
||||
cT = cT - 7;
|
||||
a = 0x8000;
|
||||
|
||||
// End of INITDEC ---
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* $RCSfile: BitToByteOutput.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:07 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: BitToByteOutput
|
||||
*
|
||||
* Description: Adapter to perform bit based output on a byte
|
||||
* based one.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.encoder;
|
||||
|
||||
|
||||
/**
|
||||
* This class provides an adapter to perform bit based output on byte based
|
||||
* output objects that inherit from a 'ByteOutputBuffer' class. This class
|
||||
* implements the bit stuffing policy needed for the 'selective arithmetic
|
||||
* coding bypass' mode of the entropy coder. This class also delays the output
|
||||
* of a trailing 0xFF, since they are synthetized be the decoder.
|
||||
*/
|
||||
class BitToByteOutput {
|
||||
|
||||
/**
|
||||
* The alternating sequence of 0's and 1's used for byte padding
|
||||
*/
|
||||
static final int PAD_SEQ = 0x2A;
|
||||
/**
|
||||
* Flag that indicates if an FF has been delayed
|
||||
*/
|
||||
boolean delFF = false;
|
||||
/**
|
||||
* The byte based output
|
||||
*/
|
||||
ByteOutputBuffer out;
|
||||
/**
|
||||
* The bit buffer
|
||||
*/
|
||||
int bbuf;
|
||||
/**
|
||||
* The position of the next bit to put in the bit buffer. When it is 7
|
||||
* the bit buffer 'bbuf' is empty. The value should always be between 7
|
||||
* and 0 (i.e. if it gets to -1, the bit buffer should be immediately
|
||||
* written to the byte output).
|
||||
*/
|
||||
int bpos = 7;
|
||||
/**
|
||||
* The number of written bytes (excluding the bit buffer)
|
||||
*/
|
||||
int nb = 0;
|
||||
/**
|
||||
* Whether or not predictable termination is requested. This value is
|
||||
* important when the last byte before termination is an 0xFF
|
||||
*/
|
||||
private boolean isPredTerm = false;
|
||||
|
||||
/**
|
||||
* Instantiates a new 'BitToByteOutput' object that uses 'out' as the
|
||||
* underlying byte based output.
|
||||
*
|
||||
* @param out The underlying byte based output
|
||||
*/
|
||||
BitToByteOutput(ByteOutputBuffer out) {
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes to the bit stream the symbols contained in the 'symbuf'
|
||||
* buffer. The least significant bit of each element in 'symbuf'is
|
||||
* written.
|
||||
*
|
||||
* @param symbuf The symbols to write
|
||||
* @param nsym The number of symbols in symbuf
|
||||
*/
|
||||
final void writeBits(int[] symbuf, int nsym) {
|
||||
int i;
|
||||
int bbuf, bpos;
|
||||
bbuf = this.bbuf;
|
||||
bpos = this.bpos;
|
||||
// Write symbol by symbol to bit buffer
|
||||
for (i = 0; i < nsym; i++) {
|
||||
bbuf |= (symbuf[i] & 0x01) << (bpos--);
|
||||
if (bpos < 0) { // Bit buffer is full, write it
|
||||
if (bbuf != 0xFF) { // No bit-stuffing needed
|
||||
if (delFF) { // Output delayed 0xFF if any
|
||||
out.write(0xFF);
|
||||
delFF = false;
|
||||
nb++;
|
||||
}
|
||||
out.write(bbuf);
|
||||
nb++;
|
||||
bpos = 7;
|
||||
} else { // We need to do bit stuffing on next byte
|
||||
delFF = true;
|
||||
bpos = 6; // One less bit in next byte
|
||||
}
|
||||
bbuf = 0;
|
||||
}
|
||||
}
|
||||
this.bbuf = bbuf;
|
||||
this.bpos = bpos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a bit to the output. The least significant bit of 'bit' is
|
||||
* written to the output.
|
||||
*
|
||||
* @param bit
|
||||
*/
|
||||
final void writeBit(int bit) {
|
||||
bbuf |= (bit & 0x01) << (bpos--);
|
||||
if (bpos < 0) {
|
||||
if (bbuf != 0xFF) { // No bit-stuffing needed
|
||||
if (delFF) { // Output delayed 0xFF if any
|
||||
out.write(0xFF);
|
||||
delFF = false;
|
||||
nb++;
|
||||
}
|
||||
// Output the bit buffer
|
||||
out.write(bbuf);
|
||||
nb++;
|
||||
bpos = 7;
|
||||
} else { // We need to do bit stuffing on next byte
|
||||
delFF = true;
|
||||
bpos = 6; // One less bit in next byte
|
||||
}
|
||||
bbuf = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the contents of the bit buffer and byte aligns the output by
|
||||
* filling bits with an alternating sequence of 0's and 1's.
|
||||
*/
|
||||
void flush() {
|
||||
if (delFF) { // There was a bit stuffing
|
||||
if (bpos != 6) { // Bit buffer is not empty
|
||||
// Output delayed 0xFF
|
||||
out.write(0xFF);
|
||||
delFF = false;
|
||||
nb++;
|
||||
// Pad to byte boundary with an alternating sequence of 0's
|
||||
// and 1's.
|
||||
bbuf |= (PAD_SEQ >>> (6 - bpos));
|
||||
// Output the bit buffer
|
||||
out.write(bbuf);
|
||||
nb++;
|
||||
bpos = 7;
|
||||
bbuf = 0;
|
||||
} else if (isPredTerm) {
|
||||
out.write(0xFF);
|
||||
nb++;
|
||||
out.write(0x2A);
|
||||
nb++;
|
||||
bpos = 7;
|
||||
bbuf = 0;
|
||||
delFF = false;
|
||||
}
|
||||
} else { // There was no bit stuffing
|
||||
if (bpos != 7) { // Bit buffer is not empty
|
||||
// Pad to byte boundary with an alternating sequence of 0's and
|
||||
// 1's.
|
||||
bbuf |= (PAD_SEQ >>> (6 - bpos));
|
||||
// Output the bit buffer (bbuf can not be 0xFF)
|
||||
out.write(bbuf);
|
||||
nb++;
|
||||
bpos = 7;
|
||||
bbuf = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminates the bit stream by calling 'flush()' and then 'reset()'.
|
||||
*/
|
||||
public int terminate() {
|
||||
flush();
|
||||
int savedNb = nb;
|
||||
reset();
|
||||
return savedNb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the bit buffer to empty, without writing anything to the
|
||||
* underlying byte output, and resets the byte count. The underlying byte
|
||||
* output is NOT reset.
|
||||
*/
|
||||
void reset() {
|
||||
delFF = false;
|
||||
bpos = 7;
|
||||
bbuf = 0;
|
||||
nb = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length, in bytes, of the output bit stream as written by
|
||||
* this object. If the output bit stream does not have an integer number
|
||||
* of bytes in length then it is rounded to the next integer.
|
||||
*
|
||||
* @return The length, in bytes, of the output bit stream.
|
||||
*/
|
||||
int length() {
|
||||
if (delFF) {
|
||||
// If bit buffer is empty we just need 'nb' bytes. If not we need
|
||||
// the delayed FF and the padded bit buffer.
|
||||
return nb + 2;
|
||||
} else {
|
||||
// If the bit buffer is empty, we just need 'nb' bytes. If not, we
|
||||
// add length of the padded bit buffer
|
||||
return nb + ((bpos == 7) ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag according to whether or not the predictable termination is
|
||||
* requested.
|
||||
*
|
||||
* @param isPredTerm Whether or not predictable termination is requested.
|
||||
*/
|
||||
void setPredTerm(boolean isPredTerm) {
|
||||
this.isPredTerm = isPredTerm;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* $RCSfile: ByteOutputBuffer.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:07 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: ByteOutputBuffer
|
||||
*
|
||||
* Description: Provides buffering for byte based output, similar
|
||||
* to the standard class ByteArrayOutputStream
|
||||
*
|
||||
* the old jj2000.j2k.io.ByteArrayOutput class by
|
||||
* Diego SANTA CRUZ, Apr-26-1999
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.encoder;
|
||||
|
||||
|
||||
/**
|
||||
* This class provides a buffering output stream similar to
|
||||
* ByteArrayOutputStream, with some additional methods.
|
||||
*
|
||||
* <P>Once an array has been written to an output stream or to a byte
|
||||
* array, the object can be reused as a new stream if the reset()
|
||||
* method is called.
|
||||
*
|
||||
* <P>Unlike the ByteArrayOutputStream class, this class is not thread safe.
|
||||
*
|
||||
* @see #reset
|
||||
*/
|
||||
public class ByteOutputBuffer {
|
||||
|
||||
/**
|
||||
* The buffer increase size
|
||||
*/
|
||||
public final static int BUF_INC = 512;
|
||||
/**
|
||||
* The default initial buffer size
|
||||
*/
|
||||
public final static int BUF_DEF_LEN = 256;
|
||||
/**
|
||||
* The buffer where the data is stored
|
||||
*/
|
||||
byte[] buf;
|
||||
/**
|
||||
* The number of valid bytes in the buffer
|
||||
*/
|
||||
int count;
|
||||
|
||||
/**
|
||||
* Creates a new byte array output stream. The buffer capacity is
|
||||
* initially BUF_DEF_LEN bytes, though its size increases if necessary.
|
||||
*/
|
||||
public ByteOutputBuffer() {
|
||||
buf = new byte[BUF_DEF_LEN];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new byte array output stream, with a buffer capacity
|
||||
* of the specified size, in bytes.
|
||||
*
|
||||
* @param size the initial size.
|
||||
*/
|
||||
public ByteOutputBuffer(int size) {
|
||||
buf = new byte[size];
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the specified byte to this byte array output stream. The
|
||||
* functionality provided by this implementation is the same as for the
|
||||
* one in the superclass, however this method is not synchronized and
|
||||
* therefore not safe thread, but faster.
|
||||
*
|
||||
* @param b The byte to write
|
||||
*/
|
||||
public final void write(int b) {
|
||||
if (count == buf.length) { // Resize buffer
|
||||
byte[] tmpbuf = buf;
|
||||
buf = new byte[buf.length + BUF_INC];
|
||||
System.arraycopy(tmpbuf, 0, buf, 0, count);
|
||||
}
|
||||
buf[count++] = (byte) b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the specified part of the stream to the 'outbuf' byte
|
||||
* array.
|
||||
*
|
||||
* @param off The index of the first element in the stream to
|
||||
* copy.
|
||||
* @param len The number of elements of the array to copy
|
||||
* @param outbuf The destination array
|
||||
* @param outoff The index of the first element in 'outbuf' where
|
||||
* to write the data.
|
||||
*/
|
||||
public void toByteArray(int off, int len, byte[] outbuf, int outoff) {
|
||||
// Copy the data
|
||||
System.arraycopy(buf, off, outbuf, outoff, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of valid bytes in the output buffer (count class
|
||||
* variable).
|
||||
*
|
||||
* @return The number of bytes written to the buffer
|
||||
*/
|
||||
public int size() {
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Discards all the buffered data, by resetting the counter of written
|
||||
* bytes to 0.
|
||||
*/
|
||||
public void reset() {
|
||||
count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte buffered at the given position in the buffer. The
|
||||
* position in the buffer is the index of the 'write()' method call after
|
||||
* the last call to 'reset()'.
|
||||
*
|
||||
* @param pos The position of the byte to return
|
||||
* @return The value (betweeb 0-255) of the byte at position 'pos'.
|
||||
*/
|
||||
public int getByte(int pos) {
|
||||
if (pos >= count) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return buf[pos] & 0xFF;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* $RCSfile: CBlkRateDistStats.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:07 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: CBlkRateDistStats
|
||||
*
|
||||
* Description: The coded (compressed) code-block with
|
||||
* rate-distortion statistics.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.encoder;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.CodedCBlk;
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.analysis.SubbandAn;
|
||||
|
||||
/**
|
||||
* This class stores coded (compressed) code-blocks with their associated
|
||||
* rate-distortion statistics. This object should always contain all the
|
||||
* compressed data of the code-block. It is applicable to the encoder engine
|
||||
* only. Some data of the coded-block is stored in the super class, see
|
||||
* CodedCBlk.
|
||||
*
|
||||
* <P>The rate-distortion statistics (i.e. R-D slope) is stored for valid
|
||||
* points only. The set of valid points is determined by the entropy coder
|
||||
* engine itself. Normally they are selected so as to lye in a convex hull,
|
||||
* which can be achived by using the 'selectConvexHull' method of this class,
|
||||
* but some other strategies might be employed.
|
||||
*
|
||||
* <P>The rate (in bytes) for each truncation point (valid or not) is stored
|
||||
* in the 'truncRates' array. The rate of a truncation point is the total
|
||||
* number of bytes in 'data' (see super class) that have to be decoded to
|
||||
* reach the truncation point.
|
||||
*
|
||||
* <P>The slope (reduction of distortion divided by the increase in rate) at
|
||||
* each of the valid truncation points is stored in 'truncSlopes'.
|
||||
*
|
||||
* <P>The index of each valid truncation point is stored in 'truncIdxs'. The
|
||||
* index should be interpreted in the following way: a valid truncation point
|
||||
* at position 'n' has the index 'truncIdxs[n]', the rate
|
||||
* 'truncRates[truncIdxs[n]]' and the slope 'truncSlopes[n]'. The arrays
|
||||
* 'truncIdxs' and 'truncRates' have at least 'nVldTrunc' elements. The
|
||||
* 'truncRates' array has at least 'nTotTrunc' elements.
|
||||
*
|
||||
* <P>In addition the 'isTermPass' array contains a flag for each truncation
|
||||
* point (valid and non-valid ones) that tells if the pass is terminated or
|
||||
* not. If this variable is null then it means that no pass is terminated,
|
||||
* except the last one which always is.
|
||||
*
|
||||
* <P>The compressed data is stored in the 'data' member variable of the super
|
||||
* class.
|
||||
*
|
||||
* @see CodedCBlk
|
||||
*/
|
||||
public class CBlkRateDistStats extends CodedCBlk {
|
||||
|
||||
/**
|
||||
* The subband to which the code-block belongs
|
||||
*/
|
||||
public SubbandAn sb;
|
||||
|
||||
/**
|
||||
* The total number of truncation points
|
||||
*/
|
||||
public int nTotTrunc;
|
||||
|
||||
/**
|
||||
* The number of valid truncation points
|
||||
*/
|
||||
public int nVldTrunc;
|
||||
|
||||
/**
|
||||
* The rate (in bytes) for each truncation point (valid and non-valid
|
||||
* ones)
|
||||
*/
|
||||
public int[] truncRates;
|
||||
|
||||
/**
|
||||
* The distortion for each truncation point (valid and non-valid ones)
|
||||
*/
|
||||
public double[] truncDists;
|
||||
|
||||
/**
|
||||
* The negative of the rate-distortion slope for each valid truncation
|
||||
* point
|
||||
*/
|
||||
public float[] truncSlopes;
|
||||
|
||||
/**
|
||||
* The indices of the valid truncation points, in increasing
|
||||
* order.
|
||||
*/
|
||||
public int[] truncIdxs;
|
||||
|
||||
/**
|
||||
* Array of flags indicating terminated passes (valid or non-valid
|
||||
* truncation points).
|
||||
*/
|
||||
public boolean[] isTermPass;
|
||||
|
||||
/**
|
||||
* The number of ROI coefficients in the code-block
|
||||
*/
|
||||
public int nROIcoeff = 0;
|
||||
|
||||
/**
|
||||
* Number of ROI coding passes
|
||||
*/
|
||||
public int nROIcp = 0;
|
||||
|
||||
/**
|
||||
* Creates a new CBlkRateDistStats object without allocating any space for
|
||||
* 'truncRates', 'truncSlopes', 'truncDists' and 'truncIdxs' or 'data'.
|
||||
*/
|
||||
public CBlkRateDistStats() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new CBlkRateDistStats object and initializes the valid
|
||||
* truncation points, their rates and their slopes, from the 'rates' and
|
||||
* 'dist' arrays. The 'rates', 'dist' and 'termp' arrays must contain the
|
||||
* rate (in bytes), the reduction in distortion (from nothing coded) and
|
||||
* the flag indicating if termination is used, respectively, for each
|
||||
* truncation point.
|
||||
*
|
||||
* <P>The valid truncation points are selected by taking them as lying on
|
||||
* a convex hull. This is done by calling the method selectConvexHull().
|
||||
*
|
||||
* <P> Note that the arrays 'rates' and 'termp' are copied, not
|
||||
* referenced, so they can be modified after a call to this constructor.
|
||||
*
|
||||
* @param m The horizontal index of the code-block, within the subband.
|
||||
* @param n The vertical index of the code-block, within the subband.
|
||||
* @param skipMSBP The number of skipped most significant bit-planes for
|
||||
* this code-block.
|
||||
* @param data The compressed data. This array is referenced by this
|
||||
* object so it should not be modified after.
|
||||
* @param rates The rates (in bytes) for each truncation point in the
|
||||
* compressed data. This array is modified by the method but no reference
|
||||
* is kept to it.
|
||||
* @param dists The reduction in distortion (with respect to no information
|
||||
* coded) for each truncation point. This array is modified by the method
|
||||
* but no reference is kept to it.
|
||||
* @param termp An array of boolean flags indicating, for each pass, if a
|
||||
* pass is terminated or not (true if terminated). If null then it is
|
||||
* assumed that no pass is terminated except the last one which always is.
|
||||
* @param np The number of truncation points contained in 'rates', 'dist'
|
||||
* and 'termp'.
|
||||
* @param inclast If false the convex hull is constructed as for lossy
|
||||
* coding. If true it is constructed as for lossless coding, in which case
|
||||
* it is ensured that all bit-planes are sent (i.e. the last truncation
|
||||
* point is always included).
|
||||
*/
|
||||
public CBlkRateDistStats(int m, int n, int skipMSBP, byte[] data,
|
||||
int[] rates, double[] dists, boolean[] termp,
|
||||
int np, boolean inclast) {
|
||||
super(m, n, skipMSBP, data);
|
||||
selectConvexHull(rates, dists, termp, np, inclast);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the rate-distorsion slopes and selects those that lie in a
|
||||
* convex hull. It will compute the slopes, select the ones that form the
|
||||
* convex hull and initialize the 'truncIdxs' and 'truncSlopes' arrays, as
|
||||
* well as 'nVldTrunc', with the selected truncation points. It will also
|
||||
* initialize 'truncRates' and 'isTermPass' arrays, as well as
|
||||
* 'nTotTrunc', with all the truncation points (selected or not).
|
||||
*
|
||||
* <P> Note that the arrays 'rates' and 'termp' are copied, not
|
||||
* referenced, so they can be modified after a call to this method.
|
||||
*
|
||||
* @param rates The rates (in bytes) for each truncation point in the
|
||||
* compressed data. This array is modified by the method.
|
||||
* @param dists The reduction in distortion (with respect to no
|
||||
* information coded) for each truncation point. This array is modified by
|
||||
* the method.
|
||||
* @param termp An array of boolean flags indicating, for each pass, if a
|
||||
* pass is terminated or not (true if terminated). If null then it is
|
||||
* assumed that no pass is terminated except the last one which always is.
|
||||
* @param n The number of truncation points contained in 'rates', 'dist'
|
||||
* and 'termp'.
|
||||
* @param inclast If false the convex hull is constructed as for lossy
|
||||
* coding. If true it is constructed as for lossless coding, in which case
|
||||
* it is ensured that all bit-planes are sent (i.e. the last truncation
|
||||
* point is always included).
|
||||
*/
|
||||
public void selectConvexHull(int[] rates, double[] dists, boolean[] termp,
|
||||
int n, boolean inclast) {
|
||||
int first_pnt; // The first point containing some coded data
|
||||
int p; // last selected point
|
||||
int k; // current point
|
||||
int i; // current valid point
|
||||
int npnt; // number of selected (i.e. valid) points
|
||||
int delta_rate; // Rate difference
|
||||
double delta_dist; // Distortion difference
|
||||
float k_slope; // R-D slope for the current point
|
||||
float p_slope; // R-D slope for the last selected point
|
||||
int ll_rate; // Rate for "lossless" coding (i.e. all coded info)
|
||||
|
||||
// Convention: when a negative value is stored in 'rates' it meas an
|
||||
// invalid point. The absolute value is always the rate for that point.
|
||||
|
||||
// Look for first point with some coded info (rate not 0)
|
||||
first_pnt = 0;
|
||||
while (first_pnt < n && rates[first_pnt] <= 0) {
|
||||
first_pnt++;
|
||||
}
|
||||
|
||||
// Select the valid points
|
||||
npnt = n - first_pnt;
|
||||
p_slope = 0f; // To keep compiler happy
|
||||
ploop:
|
||||
do {
|
||||
p = -1;
|
||||
for (k = first_pnt; k < n; k++) {
|
||||
if (rates[k] < 0) { // Already invalidated point
|
||||
continue;
|
||||
}
|
||||
// Calculate decrease in distortion and rate
|
||||
if (p >= 0) {
|
||||
delta_rate = rates[k] - rates[p];
|
||||
delta_dist = dists[k] - dists[p];
|
||||
} else { // This is with respect to no info coded
|
||||
delta_rate = rates[k];
|
||||
delta_dist = dists[k];
|
||||
}
|
||||
// If exactly same distortion don't eliminate if the rates are
|
||||
// equal, otherwise it can lead to infinite slope in lossless
|
||||
// coding.
|
||||
if (delta_dist < 0f || (delta_dist == 0f && delta_rate > 0)) {
|
||||
// This point increases distortion => invalidate
|
||||
rates[k] = -rates[k];
|
||||
npnt--;
|
||||
continue; // Goto next point
|
||||
}
|
||||
k_slope = (float) (delta_dist / delta_rate);
|
||||
// Check that there is a decrease in distortion, slope is not
|
||||
// infinite (i.e. delta_dist is not 0) and slope is
|
||||
// decreasing.
|
||||
if (p >= 0 &&
|
||||
(delta_rate <= 0 || k_slope >= p_slope)) {
|
||||
// Last point was not good
|
||||
rates[p] = -rates[p]; // Remove p from valid points
|
||||
npnt--;
|
||||
continue ploop; // Restart from the first one
|
||||
} else {
|
||||
p_slope = k_slope;
|
||||
p = k;
|
||||
}
|
||||
}
|
||||
// If we get to last point we are done
|
||||
break;
|
||||
} while (true); // We end the loop with the break statement
|
||||
|
||||
// If in lossless mode make sure we don't eliminate any last bit-planes
|
||||
// from being sent.
|
||||
if (inclast && n > 0 && rates[n - 1] < 0) {
|
||||
rates[n - 1] = -rates[n - 1];
|
||||
// This rate can never be equal to any previous selected rate,
|
||||
// given the selection algorithm above, so no problem arises of
|
||||
// infinite slopes.
|
||||
npnt++;
|
||||
}
|
||||
|
||||
// Initialize the arrays of this object
|
||||
nTotTrunc = n;
|
||||
nVldTrunc = npnt;
|
||||
truncRates = new int[n];
|
||||
truncDists = new double[n];
|
||||
truncSlopes = new float[npnt];
|
||||
truncIdxs = new int[npnt];
|
||||
if (termp != null) {
|
||||
isTermPass = new boolean[n];
|
||||
System.arraycopy(termp, 0, isTermPass, 0, n);
|
||||
} else {
|
||||
isTermPass = null;
|
||||
}
|
||||
System.arraycopy(rates, 0, truncRates, 0, n);
|
||||
for (k = first_pnt, p = -1, i = 0; k < n; k++) {
|
||||
if (rates[k] > 0) { // A valid point
|
||||
truncDists[k] = dists[k];
|
||||
if (p < 0) { // Only arrives at first valid point
|
||||
truncSlopes[i] = (float) (dists[k] / rates[k]);
|
||||
} else {
|
||||
truncSlopes[i] = (float) ((dists[k] - dists[p]) /
|
||||
(rates[k] - rates[p]));
|
||||
}
|
||||
truncIdxs[i] = k;
|
||||
i++;
|
||||
p = k;
|
||||
} else {
|
||||
truncDists[k] = -1;
|
||||
truncRates[k] = -truncRates[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contents of the object in a string. This is used for
|
||||
* debugging.
|
||||
*
|
||||
* @return A string with the contents of the object
|
||||
*/
|
||||
public String toString() {
|
||||
return super.toString() +
|
||||
"\n nVldTrunc = " + nVldTrunc + ", nTotTrunc=" + nTotTrunc + ", num. ROI" +
|
||||
" coeff=" + nROIcoeff + ", num. ROI coding passes=" + nROIcp;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* $RCSfile: CodedCBlkDataSrcEnc.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:08 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: CodedCBlkDataSrcEnc
|
||||
*
|
||||
* Description: Interface that defines a source of entropy coded
|
||||
* data that is transferred in a code-block by
|
||||
* code-block basis.
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.encoder;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.analysis.ForwWTDataProps;
|
||||
|
||||
/**
|
||||
* This interface defines a source of entropy coded data and methods to
|
||||
* transfer it in a code-block by code-block basis. In each call to
|
||||
* 'getNextCodeBlock()' a new coded code-block is returned. The code-block are
|
||||
* retruned in no specific-order.
|
||||
*
|
||||
* <P>This interface is the source of data for the rate allocator. See the
|
||||
* 'PostCompRateAllocator' class.
|
||||
*
|
||||
* <P>For each coded-code-block the entropy-coded data is returned along with
|
||||
* the rate-distortion statistics in a 'CBlkRateDistStats' object.
|
||||
*
|
||||
* @see PostCompRateAllocator
|
||||
* @see CBlkRateDistStats
|
||||
* @see EntropyCoder
|
||||
*/
|
||||
public interface CodedCBlkDataSrcEnc extends ForwWTDataProps {
|
||||
|
||||
/**
|
||||
* Returns the next coded code-block in the current tile for the specified
|
||||
* component, as a copy (see below). The order in which code-blocks are
|
||||
* returned is not specified. However each code-block is returned only
|
||||
* once and all code-blocks will be returned if the method is called 'N'
|
||||
* times, where 'N' is the number of code-blocks in the tile. After all
|
||||
* the code-blocks have been returned for the current tile calls to this
|
||||
* method will return 'null'.
|
||||
*
|
||||
* <P>When changing the current tile (through 'setTile()' or 'nextTile()')
|
||||
* this method will always return the first code-block, as if this method
|
||||
* was never called before for the new current tile.
|
||||
*
|
||||
* <P>The data returned by this method is always a copy of the internal
|
||||
* data of this object, if any, and it can be modified "in place" without
|
||||
* any problems after being returned.
|
||||
*
|
||||
* @param c The component for which to return the next code-block.
|
||||
* @param ccb If non-null this object might be used in returning the coded
|
||||
* code-block in this or any subsequent call to this method. If null a new
|
||||
* one is created and returned. If the 'data' array of 'cbb' is not null
|
||||
* it may be reused to return the compressed data.
|
||||
* @return The next coded code-block in the current tile for component
|
||||
* 'n', or null if all code-blocks for the current tile have been
|
||||
* returned.
|
||||
* @see CBlkRateDistStats
|
||||
*/
|
||||
CBlkRateDistStats getNextCodeBlock(int c, CBlkRateDistStats ccb);
|
||||
|
||||
/**
|
||||
* Returns the width of a packet for the specified tile-
|
||||
* component and resolution level.
|
||||
*
|
||||
* @param t The tile
|
||||
* @param c The component
|
||||
* @param r The resolution level
|
||||
* @return The width of a packet for the specified tile-
|
||||
* component and resolution level.
|
||||
*/
|
||||
int getPPX(int t, int c, int r);
|
||||
|
||||
/**
|
||||
* Returns the height of a packet for the specified tile-
|
||||
* component and resolution level.
|
||||
*
|
||||
* @param t The tile
|
||||
* @param c The component
|
||||
* @param r The resolution level
|
||||
* @return The height of a packet for the specified tile-
|
||||
* component and resolution level.
|
||||
*/
|
||||
int getPPY(int t, int c, int r);
|
||||
|
||||
/**
|
||||
* Returns true if the precinct partition is used for the
|
||||
* specified component and tile, returns false otherwise
|
||||
*
|
||||
* @param c The component
|
||||
* @param t The tile
|
||||
*/
|
||||
boolean precinctPartitionUsed(int c, int t);
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* $RCSfile: EBCOTLayer.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:08 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: EBCOTLayer
|
||||
*
|
||||
* Description: Storage for layer information,
|
||||
* used by EBCOTRateAllocator
|
||||
*
|
||||
* class that was in EBCOTRateAllocator.
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.encoder;
|
||||
|
||||
/**
|
||||
* This class holds information about each layer that is to be, or has already
|
||||
* been, allocated . It is used in the rate-allocation process to keep the
|
||||
* necessary layer information. It is used by EBCOTRateAllocator.
|
||||
*
|
||||
* @see EBCOTRateAllocator
|
||||
**/
|
||||
class EBCOTLayer {
|
||||
/**
|
||||
* This is the maximum number of bytes that should be allocated for
|
||||
* this and previous layers. This is actually the target length for
|
||||
* the layer.
|
||||
**/
|
||||
int maxBytes;
|
||||
|
||||
/**
|
||||
* The actual number of bytes which are consumed by the the current and
|
||||
* any previous layers. This is the result from a simulation when the
|
||||
* threshold for the layer has been set.
|
||||
**/
|
||||
int actualBytes;
|
||||
|
||||
/**
|
||||
* If true the `maxBytes' value is the hard maximum and the threshold is
|
||||
* determined iteratively. If false the `maxBytes' value is a target
|
||||
* bitrate and the threshold is estimated from summary information
|
||||
* accumulated during block coding.
|
||||
**/
|
||||
boolean optimize;
|
||||
|
||||
/**
|
||||
* The rate-distortion threshold associated with the bit-stream
|
||||
* layer. When set the layer includes data up to the truncation points
|
||||
* that have a slope no smaller than 'rdThreshold'.
|
||||
**/
|
||||
float rdThreshold;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,307 @@
|
|||
/*
|
||||
* $RCSfile: EntropyCoder.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:08 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: EntropyCoder
|
||||
*
|
||||
* Description: The abstract class for entropy encoders
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
* */
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.encoder;
|
||||
|
||||
import org.xbib.graphics.jpeg2000.J2KWriteParam;
|
||||
import org.xbib.graphics.jpeg2000.j2k.StringSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.CBlkSizeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.PrecinctSizeSpec;
|
||||
import org.xbib.graphics.jpeg2000.j2k.entropy.StdEntropyCoderOptions;
|
||||
import org.xbib.graphics.jpeg2000.j2k.image.ImgDataAdapter;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.quantizer.CBlkQuantDataSrcEnc;
|
||||
import org.xbib.graphics.jpeg2000.j2k.quantization.quantizer.Quantizer;
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.Subband;
|
||||
import org.xbib.graphics.jpeg2000.j2k.wavelet.analysis.SubbandAn;
|
||||
import org.xbib.graphics.jpeg2000.j2k.roi.encoder.ROIScaler;
|
||||
|
||||
/**
|
||||
* This abstract class provides the general interface for block-based entropy
|
||||
* encoders. The input to the entropy coder is the quantized wavelet
|
||||
* coefficients, or codewords, represented in sign magnitude. The output is a
|
||||
* compressed code-block with rate-distortion information.
|
||||
*
|
||||
* <P>The source of data for objects of this class are 'CBlkQuantDataSrcEnc'
|
||||
* objects.
|
||||
*
|
||||
* <P>For more details on the sign magnitude representation used see the
|
||||
* Quantizer class.
|
||||
*
|
||||
* <P>This class provides default implemenations for most of the methods
|
||||
* (wherever it makes sense), under the assumption that the image and
|
||||
* component dimensions, and the tiles, are not modifed by the entropy
|
||||
* coder. If that is not the case for a particular implementation then the
|
||||
* methods should be overriden.
|
||||
*
|
||||
* @see Quantizer
|
||||
* @see CBlkQuantDataSrcEnc
|
||||
*/
|
||||
public abstract class EntropyCoder extends ImgDataAdapter
|
||||
implements CodedCBlkDataSrcEnc, StdEntropyCoderOptions {
|
||||
|
||||
/**
|
||||
* The prefix for entropy coder options: 'C'
|
||||
*/
|
||||
public final static char OPT_PREFIX = 'C';
|
||||
|
||||
/**
|
||||
* The list of parameters that is accepted for entropy coding. Options
|
||||
* for entropy coding start with 'C'.
|
||||
*/
|
||||
private final static String[][] pinfo = {
|
||||
{"Cblksiz", "[<tile-component idx>] <width> <height> " +
|
||||
"[[<tile-component idx>] <width> <height>]",
|
||||
"Specifies the maximum code-block size to use for tile-component. " +
|
||||
"The maximum width and height is 1024, however the surface area " +
|
||||
"(i.e. width x height) must not exceed 4096. The minimum width and " +
|
||||
"height is 4.", "64 64"},
|
||||
{"Cbypass", "[<tile-component idx>] true|false" +
|
||||
"[ [<tile-component idx>] true|false ...]",
|
||||
"Uses the lazy coding mode with the entropy coder. This will bypass " +
|
||||
"the MQ coder for some of the coding passes, where the distribution " +
|
||||
"is often close to uniform. Since the MQ codeword will be " +
|
||||
"terminated " +
|
||||
"at least once per lazy pass, it is important to use an efficient " +
|
||||
"termination algorithm, see the 'Cterm' option." +
|
||||
"'true' enables, 'false' disables it.", "false"},
|
||||
{"CresetMQ", "[<tile-component idx>] true|false" +
|
||||
"[ [<tile-component idx>] true|false ...]",
|
||||
"If this is enabled the probability estimates of the MQ coder are " +
|
||||
"reset after each arithmetically coded (i.e. non-lazy) coding pass. " +
|
||||
"'true' enables, 'false' disables it.", "false"},
|
||||
{"Creg_term", "[<tile-component idx>] true|false" +
|
||||
"[ [<tile-component idx>] true|false ...]",
|
||||
"If this is enabled the codeword (raw or MQ) is terminated on a " +
|
||||
"byte boundary after each coding pass. In this case it is important " +
|
||||
"to use an efficient termination algorithm, see the 'Cterm' option. " +
|
||||
"'true' enables, 'false' disables it.", "false"},
|
||||
{"Ccausal", "[<tile-component idx>] true|false" +
|
||||
"[ [<tile-component idx>] true|false ...]",
|
||||
"Uses vertically stripe causal context formation. If this is " +
|
||||
"enabled " +
|
||||
"the context formation process in one stripe is independant of the " +
|
||||
"next stripe (i.e. the one below it). 'true' " +
|
||||
"enables, 'false' disables it.", "false"},
|
||||
{"Cseg_symbol", "[<tile-component idx>] true|false" +
|
||||
"[ [<tile-component idx>] true|false ...]",
|
||||
"Inserts an error resilience segmentation symbol in the MQ " +
|
||||
"codeword at the end of " +
|
||||
"each bit-plane (cleanup pass). Decoders can use this " +
|
||||
"information to detect and " +
|
||||
"conceal errors.'true' enables, 'false' disables " +
|
||||
"it.", "false"},
|
||||
{"Cterm", "[<tile-component idx>] near_opt|easy|predict|full" +
|
||||
"[ [<tile-component idx>] near_opt|easy|predict|full ...]",
|
||||
"Specifies the algorithm used to terminate the MQ codeword. " +
|
||||
"The most efficient one is 'near_opt', which delivers a codeword " +
|
||||
"which in almost all cases is the shortest possible. The 'easy' is " +
|
||||
"a simpler algorithm that delivers a codeword length that is close " +
|
||||
"to the previous one (in average 1 bit longer). The 'predict' is" +
|
||||
" almost " +
|
||||
"the same as the 'easy' but it leaves error resilient information " +
|
||||
"on " +
|
||||
"the spare least significant bits (in average 3.5 bits), which can " +
|
||||
"be used by a decoder to detect errors. The 'full' algorithm " +
|
||||
"performs a full flush of the MQ coder and is highly inefficient.\n" +
|
||||
"It is important to use a good termination policy since the MQ " +
|
||||
"codeword can be terminated quite often, specially if the 'Cbypass'" +
|
||||
" or " +
|
||||
"'Creg_term' options are enabled (in the normal case it would be " +
|
||||
"terminated once per code-block, while if 'Creg_term' is specified " +
|
||||
"it will be done almost 3 times per bit-plane in each code-block).",
|
||||
"near_opt"},
|
||||
{"Clen_calc", "[<tile-component idx>] near_opt|lazy_good|lazy" +
|
||||
"[ [<tile-component idx>] ...]",
|
||||
"Specifies the algorithm to use in calculating the necessary MQ " +
|
||||
"length for each decoding pass. The best one is 'near_opt', which " +
|
||||
"performs a rather sophisticated calculation and provides the best " +
|
||||
"results. The 'lazy_good' and 'lazy' are very simple algorithms " +
|
||||
"that " +
|
||||
"provide rather conservative results, 'lazy_good' one being " +
|
||||
"slightly " +
|
||||
"better. Do not change this option unless you want to experiment " +
|
||||
"the effect of different length calculation algorithms.", "near_opt"},
|
||||
{"Cpp", "[<tile-component idx>] <dim> <dim> [<dim> <dim>] " +
|
||||
"[ [<tile-component idx>] ...]",
|
||||
"Specifies precinct partition dimensions for tile-component. The " +
|
||||
"first " +
|
||||
"two values apply to the highest resolution and the following ones " +
|
||||
"(if " +
|
||||
"any) apply to the remaining resolutions in decreasing order. If " +
|
||||
"less " +
|
||||
"values than the number of decomposition levels are specified, " +
|
||||
"then the " +
|
||||
"last two values are used for the remaining resolutions.", null},
|
||||
};
|
||||
|
||||
/**
|
||||
* The source of quantized wavelet coefficients
|
||||
*/
|
||||
protected CBlkQuantDataSrcEnc src;
|
||||
|
||||
/**
|
||||
* Initializes the source of quantized wavelet coefficients.
|
||||
*
|
||||
* @param src The source of quantized wavelet coefficients.
|
||||
*/
|
||||
public EntropyCoder(CBlkQuantDataSrcEnc src) {
|
||||
super(src);
|
||||
this.src = src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameters that are used in this class and
|
||||
* implementing classes. It returns a 2D String array. Each of the
|
||||
* 1D arrays is for a different option, and they have 3
|
||||
* elements. The first element is the option name, the second one
|
||||
* is the synopsis, the third one is a long description of what
|
||||
* the parameter is and the fourth is its default value. The
|
||||
* synopsis or description may be 'null', in which case it is
|
||||
* assumed that there is no synopsis or description of the option,
|
||||
* respectively. Null may be returned if no options are supported.
|
||||
*
|
||||
* @return the options name, their synopsis and their explanation,
|
||||
* or null if no options are supported.
|
||||
*/
|
||||
public static String[][] getParameterInfo() {
|
||||
return pinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a EntropyCoder object for the appropriate entropy coding
|
||||
* parameters in the parameter list 'pl', and having 'src' as the source
|
||||
* of quantized data.
|
||||
*
|
||||
* @param src The source of data to be entropy coded
|
||||
* @param wp The parameter list (or options).
|
||||
* @param cblks Code-block size specifications
|
||||
* @param pss Precinct partition specifications
|
||||
* @param bms By-pass mode specifications
|
||||
* @param mqrs MQ-reset specifications
|
||||
* @param rts Regular termination specifications
|
||||
* @param css Causal stripes specifications
|
||||
* @param sss Error resolution segment symbol use specifications
|
||||
* @param lcs Length computation specifications
|
||||
* @param tts Termination type specifications
|
||||
* @throws IllegalArgumentException If an error occurs while parsing
|
||||
* the options in 'pl'
|
||||
*/
|
||||
public static EntropyCoder createInstance(CBlkQuantDataSrcEnc src,
|
||||
J2KWriteParam wp,
|
||||
CBlkSizeSpec cblks,
|
||||
PrecinctSizeSpec pss,
|
||||
StringSpec bms, StringSpec mqrs,
|
||||
StringSpec rts, StringSpec css,
|
||||
StringSpec sss, StringSpec lcs,
|
||||
StringSpec tts) {
|
||||
// Check parameters
|
||||
//pl.checkList(OPT_PREFIX,pl.toNameArray(pinfo));
|
||||
return new StdEntropyCoder(src, cblks, pss, bms, mqrs, rts, css, sss, lcs, tts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code-block width for the specified tile and component.
|
||||
*
|
||||
* @param t The tile index
|
||||
* @param c the component index
|
||||
* @return The code-block width for the specified tile and component
|
||||
*/
|
||||
public abstract int getCBlkWidth(int t, int c);
|
||||
|
||||
/**
|
||||
* Returns the code-block height for the specified tile and component.
|
||||
*
|
||||
* @param t The tile index
|
||||
* @param c the component index
|
||||
* @return The code-block height for the specified tile and component
|
||||
*/
|
||||
public abstract int getCBlkHeight(int t, int c);
|
||||
|
||||
/**
|
||||
* Returns the reversibility of the tile-component data that is provided
|
||||
* by the object. Data is reversible when it is suitable for lossless and
|
||||
* lossy-to-lossless compression.
|
||||
*
|
||||
* <P>Since entropy coders themselves are always reversible, it returns
|
||||
* the reversibility of the data that comes from the 'CBlkQuantDataSrcEnc'
|
||||
* source object (i.e. ROIScaler).
|
||||
*
|
||||
* @param t Tile index
|
||||
* @param c Component index
|
||||
* @return true is the data is reversible, false if not.
|
||||
* @see ROIScaler
|
||||
*/
|
||||
public boolean isReversible(int t, int c) {
|
||||
return src.isReversible(t, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the root of subband tree structure representing
|
||||
* the subband decomposition for the specified tile-component.
|
||||
*
|
||||
* @param t The index of the tile.
|
||||
* @param c The index of the component.
|
||||
* @return The root of the subband tree structure, see Subband.
|
||||
* @see SubbandAn
|
||||
* @see Subband
|
||||
*/
|
||||
public SubbandAn getAnSubbandTree(int t, int c) {
|
||||
return src.getAnSubbandTree(t, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the horizontal offset of the code-block partition. Allowable
|
||||
* values are 0 and 1, nothing else.
|
||||
*/
|
||||
public int getCbULX() {
|
||||
return src.getCbULX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertical offset of the code-block partition. Allowable
|
||||
* values are 0 and 1, nothing else.
|
||||
*/
|
||||
public int getCbULY() {
|
||||
return src.getCbULY();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* $RCSfile: LayersInfo.java,v $
|
||||
* $Revision: 1.1 $
|
||||
* $Date: 2005/02/11 05:02:08 $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Class: LayersInfo
|
||||
*
|
||||
* Description: Specification of a layer
|
||||
*
|
||||
*
|
||||
*
|
||||
* COPYRIGHT:
|
||||
*
|
||||
* This software module was originally developed by Raphaël Grosbois and
|
||||
* Diego Santa Cruz (Swiss Federal Institute of Technology-EPFL); Joel
|
||||
* Askelöf (Ericsson Radio Systems AB); and Bertrand Berthelot, David
|
||||
* Bouchard, Félix Henry, Gerard Mozelle and Patrice Onno (Canon Research
|
||||
* Centre France S.A) in the course of development of the JPEG2000
|
||||
* standard as specified by ISO/IEC 15444 (JPEG 2000 Standard). This
|
||||
* software module is an implementation of a part of the JPEG 2000
|
||||
* Standard. Swiss Federal Institute of Technology-EPFL, Ericsson Radio
|
||||
* Systems AB and Canon Research Centre France S.A (collectively JJ2000
|
||||
* Partners) agree not to assert against ISO/IEC and users of the JPEG
|
||||
* 2000 Standard (Users) any of their rights under the copyright, not
|
||||
* including other intellectual property rights, for this software module
|
||||
* with respect to the usage by ISO/IEC and Users of this software module
|
||||
* or modifications thereof for use in hardware or software products
|
||||
* claiming conformance to the JPEG 2000 Standard. Those intending to use
|
||||
* this software module in hardware or software products are advised that
|
||||
* their use may infringe existing patents. The original developers of
|
||||
* this software module, JJ2000 Partners and ISO/IEC assume no liability
|
||||
* for use of this software module or modifications thereof. No license
|
||||
* or right to this software module is granted for non JPEG 2000 Standard
|
||||
* conforming products. JJ2000 Partners have full right to use this
|
||||
* software module for his/her own purpose, assign or donate this
|
||||
* software module to any third party and to inhibit third parties from
|
||||
* using this software module for non JPEG 2000 Standard conforming
|
||||
* products. This copyright notice must be included in all copies or
|
||||
* derivative works of this software module.
|
||||
*
|
||||
* Copyright (c) 1999/2000 JJ2000 Partners.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
package org.xbib.graphics.jpeg2000.j2k.entropy.encoder;
|
||||
|
||||
/**
|
||||
* This class stores the specification of a layer distribution in the
|
||||
* bit stream. The specification is made of optimization points and a number of
|
||||
* extra layers to add between the optimization points. Each optimization
|
||||
* point creates a layer which is optimized by the rate allocator to the
|
||||
* specified target bitrate. The extra layers are added by the rate allocator
|
||||
* between the optimized layers, with the difference that they are not
|
||||
* optimized (i.e. they have no precise target bitrate).
|
||||
*
|
||||
* <P>The overall target bitrate for the bit stream is always added as the last
|
||||
* optimization point without any extra layers after it. If there are some
|
||||
* optimization points whose target bitrate is larger than the overall target
|
||||
* bitrate, the overall target bitrate will still appear as the last
|
||||
* optimization point, even though it does not follow the increasing target
|
||||
* bitrate order of the other optimization points. The rate allocator is
|
||||
* responsible for eliminating layers that have target bitrates larger than
|
||||
* the overall target bitrate.
|
||||
*
|
||||
* <P>Optimization points can be added with the addOptPoint() method. It takes
|
||||
* the target bitrate for the optimized layer and the number of extra layers
|
||||
* to add after it.
|
||||
*
|
||||
* <P>Information about the total number of layers, total number of
|
||||
* optimization points, target bitrates, etc. can be obtained with the other
|
||||
* methods.
|
||||
*/
|
||||
public class LayersInfo {
|
||||
|
||||
/**
|
||||
* The initial size for the arrays: 10
|
||||
*/
|
||||
private final static int SZ_INIT = 10;
|
||||
|
||||
/**
|
||||
* The size increment for the arrays
|
||||
*/
|
||||
private final static int SZ_INCR = 5;
|
||||
|
||||
/**
|
||||
* The total number of layers
|
||||
*/
|
||||
// Starts at 1: overall target bitrate is always an extra optimized layer
|
||||
int totlyrs = 1;
|
||||
|
||||
/**
|
||||
* The overall target bitrate, for the whole bit stream
|
||||
*/
|
||||
float totbrate;
|
||||
|
||||
/**
|
||||
* The number of optimized layers, or optimization points, without
|
||||
* counting the extra one coming from the overall target bitrate
|
||||
*/
|
||||
int nopt;
|
||||
|
||||
/**
|
||||
* The target bitrate to which specified layers should be optimized.
|
||||
*/
|
||||
float[] optbrate = new float[SZ_INIT];
|
||||
|
||||
/**
|
||||
* The number of extra layers to be added after an optimized layer. After
|
||||
* the layer that is optimized to optbrate[i], extralyrs[i] extra layers
|
||||
* should be added. These layers are allocated between the bitrate
|
||||
* optbrate[i] and the next optimized bitrate optbrate[i+1] or, if it does
|
||||
* not exist, the overall target bitrate.
|
||||
*/
|
||||
int[] extralyrs = new int[SZ_INIT];
|
||||
|
||||
/**
|
||||
* Creates a new LayersInfo object. The overall target bitrate 'brate' is
|
||||
* always an extra optimization point, with no extra layers are after
|
||||
* it. Note that any optimization points that are added with addOptPoint()
|
||||
* are always added before the overall target bitrate.
|
||||
*
|
||||
* @param brate The overall target bitrate for the bit stream
|
||||
*/
|
||||
public LayersInfo(float brate) {
|
||||
if (brate <= 0) {
|
||||
throw new IllegalArgumentException("Overall target bitrate must " +
|
||||
"be a positive number");
|
||||
}
|
||||
totbrate = brate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the overall target bitrate for the entire bit stream.
|
||||
*
|
||||
* @return The overall target bitrate
|
||||
*/
|
||||
public float getTotBitrate() {
|
||||
return totbrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of layers, according to the layer
|
||||
* specification of this object and the overall target bitrate.
|
||||
*
|
||||
* @return The total number of layers, according to the layer spec.
|
||||
*/
|
||||
public int getTotNumLayers() {
|
||||
return totlyrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of layers to optimize, or optimization points, as
|
||||
* specified by this object.
|
||||
*
|
||||
* @return The number of optimization points
|
||||
*/
|
||||
public int getNOptPoints() {
|
||||
// overall target bitrate is counted as extra
|
||||
return nopt + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target bitrate of the optmimization point 'n'.
|
||||
*
|
||||
* @param n The optimization point index (starts at 0).
|
||||
* @return The target bitrate (in bpp) for the optimization point 'n'.
|
||||
*/
|
||||
public float getTargetBitrate(int n) {
|
||||
// overall target bitrate is counted as extra
|
||||
return (n < nopt) ? optbrate[n] : totbrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of extra layers to add after the optimization point
|
||||
* 'n', but before optimization point 'n+1'. If there is no optimization
|
||||
* point 'n+1' then they should be added before the overall target bitrate.
|
||||
*
|
||||
* @param n The optimization point index (starts at 0).
|
||||
* @return The number of extra (unoptimized) layers to add after the
|
||||
* optimization point 'n'
|
||||
*/
|
||||
public int getExtraLayers(int n) {
|
||||
// overall target bitrate is counted as extra
|
||||
return (n < nopt) ? extralyrs[n] : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new optimization point, with target bitrate 'brate' and with
|
||||
* 'elyrs' (unoptimized) extra layers after it. The target bitrate 'brate'
|
||||
* must be larger than the previous optimization point. The arguments are
|
||||
* checked and IllegalArgumentException is thrown if they are not correct.
|
||||
*
|
||||
* @param brate The target bitrate for the optimized layer.
|
||||
* @param elyrs The number of extra (unoptimized) layers to add after the
|
||||
* optimized layer.
|
||||
*/
|
||||
public void addOptPoint(float brate, int elyrs) {
|
||||
// Check validity of arguments
|
||||
if (brate <= 0) {
|
||||
throw new
|
||||
IllegalArgumentException("Target bitrate must be positive");
|
||||
}
|
||||
if (elyrs < 0) {
|
||||
throw new IllegalArgumentException("The number of extra layers " +
|
||||
"must be 0 or more");
|
||||
}
|
||||
if (nopt > 0 && optbrate[nopt - 1] >= brate) {
|
||||
throw new
|
||||
IllegalArgumentException("New optimization point must have " +
|
||||
"a target bitrate higher than the " +
|
||||
"preceding one");
|
||||
}
|
||||
// Check room for new optimization point
|
||||
if (optbrate.length == nopt) { // Need more room
|
||||
float[] tbr = optbrate;
|
||||
int[] tel = extralyrs;
|
||||
// both arrays always have same size
|
||||
optbrate = new float[optbrate.length + SZ_INCR];
|
||||
extralyrs = new int[extralyrs.length + SZ_INCR];
|
||||
System.arraycopy(tbr, 0, optbrate, 0, nopt);
|
||||
System.arraycopy(tel, 0, extralyrs, 0, nopt);
|
||||
}
|
||||
// Add new optimization point
|
||||
optbrate[nopt] = brate;
|
||||
extralyrs[nopt] = elyrs;
|
||||
nopt++;
|
||||
// Update total number of layers
|
||||
totlyrs += 1 + elyrs;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue