From: DRC Date: Thu, 29 Jun 2017 21:49:09 +0000 (-0500) Subject: TJBench: Recover from non-fatal errors if possible X-Git-Tag: 1.5.90~65 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c94531212fe4f460ce00e22a12fd522bb71c3d7a;p=libjpeg-turbo TJBench: Recover from non-fatal errors if possible Previously, -stoponwarning only had an effect on the underlying TurboJPEG C functions, but TJBench still aborted if a non-fatal error occurred. This commit modifies the C version of TJBench such that it always recovers from a non-fatal error unless -stoponwarning is specified. Furthermore, the benchmark stores the details of the last non-fatal error and does not print any subsequent non-fatal error messages unless they differ from the last one. Due to limitations in the Java API (specifically, the fact that it cannot communicate errors, fatal or otherwise, to the calling program without throwing a TJException), it was only possible to make decompression operations fully recoverable within TJBench. With other operations, -stoponwarning still has an effect on the underlying C library but has no effect at the Java level. The Java API documentation has been amended to reflect that only certain methods are truly recoverable, regardless of the state of TJ.FLAG_STOPONWARNING. --- diff --git a/java/TJBench.java b/java/TJBench.java index f1de27a..0733816 100644 --- a/java/TJBench.java +++ b/java/TJBench.java @@ -63,6 +63,26 @@ class TJBench { } + static String tjErrorMsg; + static int tjErrorCode = -1; + + static void handleTJException(TJException e) throws TJException { + String _tjErrorMsg = e.getMessage(); + int _tjErrorCode = e.getErrorCode(); + + if ((flags & TJ.FLAG_STOPONWARNING) == 0 && + _tjErrorCode == TJ.ERR_WARNING) { + if (tjErrorMsg == null || !tjErrorMsg.equals(_tjErrorMsg) || + tjErrorCode != _tjErrorCode) { + tjErrorMsg = _tjErrorMsg; + tjErrorCode = _tjErrorCode; + System.out.println("WARNING: " + _tjErrorMsg); + } + } else + throw e; + } + + static String formatName(int subsamp, int cs) { if (cs == TJ.CS_YCbCr) return subNameLong[subsamp]; @@ -174,14 +194,21 @@ class TJBench { tjd.setSourceImage(jpegBuf[tile], jpegSize[tile]); if (doYUV) { yuvImage.setBuf(yuvImage.getBuf(), width, yuvpad, height, subsamp); - tjd.decompressToYUV(yuvImage, flags); + try { + tjd.decompressToYUV(yuvImage, flags); + } catch (TJException e) { handleTJException(e); } double startDecode = getTime(); tjd.setSourceImage(yuvImage); - tjd.decompress(dstBuf, x, y, width, pitch, height, pf, flags); + try { + tjd.decompress(dstBuf, x, y, width, pitch, height, pf, flags); + } catch (TJException e) { handleTJException(e); } if (iter >= 0) elapsedDecode += getTime() - startDecode; - } else - tjd.decompress(dstBuf, x, y, width, pitch, height, pf, flags); + } else { + try { + tjd.decompress(dstBuf, x, y, width, pitch, height, pf, flags); + } catch (TJException e) { handleTJException(e); } + } } } elapsed += getTime() - start; diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJ.html b/java/doc/org/libjpegturbo/turbojpeg/TJ.html index a544179..d569126 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/TJ.html +++ b/java/doc/org/libjpegturbo/turbojpeg/TJ.html @@ -995,7 +995,12 @@ public static final int FLAG_FORCESSE3
Immediately discontinue the current compression/decompression/transform operation if the underlying codec throws a warning (non-fatal error). The default behavior is to allow the operation to complete unless a fatal - error is encountered.
+ error is encountered. +

+ NOTE: due to the design of the TurboJPEG Java API, only certain methods + (specifically, TJDecompressor.decompress*() methods + with a void return type) will complete and leave the output image in a + fully recoverable state after a non-fatal error occurs.

See Also:
Constant Field Values
@@ -1032,7 +1037,12 @@ public static final int FLAG_FORCESSE3

ERR_WARNING

public static final int ERR_WARNING
The error was non-fatal and recoverable, but the image may still be - corrupt.
+ corrupt. +

+ NOTE: due to the design of the TurboJPEG Java API, only certain methods + (specifically, TJDecompressor.decompress*() methods + with a void return type) will complete and leave the output image in a + fully recoverable state after a non-fatal error occurs.

See Also:
Constant Field Values
diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html b/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html index a914de9..8e33249 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html +++ b/java/doc/org/libjpegturbo/turbojpeg/TJDecompressor.html @@ -785,7 +785,11 @@ public void setJPEGImage(byte[] jpegImage, throws TJException
Decompress the JPEG source image or decode the YUV source image associated with this decompressor instance and output a grayscale, RGB, or CMYK image - to the given destination buffer.
+ to the given destination buffer. +

+ NOTE: The output image is fully recoverable if this method throws a + non-fatal TJException (unless + TJ.FLAG_STOPONWARNING is specified.)

Parameters:
dstBuf - buffer that will receive the decompressed/decoded image. If the source image is a JPEG image, then this buffer should normally be pitch * scaledHeight bytes in size, where @@ -895,7 +899,11 @@ public void decompress(byte[] dstBuf, YUVImage instance. This method performs JPEG decompression but leaves out the color conversion step, so a planar YUV image is generated instead of an RGB or grayscale image. This method cannot be - used to decompress JPEG source images with the CMYK or YCCK colorspace. + used to decompress JPEG source images with the CMYK or YCCK colorspace. +

+ NOTE: The YUV planar output image is fully recoverable if this method + throws a non-fatal TJException (unless + TJ.FLAG_STOPONWARNING is specified.)

Parameters:
dstImage - YUVImage instance that will receive the YUV planar image. The level of subsampling specified in this YUVImage instance must match that of the JPEG image, and the width and height @@ -1035,7 +1043,11 @@ public byte[] decompressToYUV(int flags) throws TJException
Decompress the JPEG source image or decode the YUV source image associated with this decompressor instance and output a grayscale, RGB, or CMYK image - to the given destination buffer.
+ to the given destination buffer. +

+ NOTE: The output image is fully recoverable if this method throws a + non-fatal TJException (unless + TJ.FLAG_STOPONWARNING is specified.)

Parameters:
dstBuf - buffer that will receive the decompressed/decoded image. If the source image is a JPEG image, then this buffer should normally be stride * scaledHeight pixels in size, where @@ -1092,7 +1104,11 @@ public byte[] decompressToYUV(int flags) throws TJException
Decompress the JPEG source image or decode the YUV source image associated with this decompressor instance and output a decompressed/decoded image to - the given BufferedImage instance.
+ the given BufferedImage instance. +

+ NOTE: The output image is fully recoverable if this method throws a + non-fatal TJException (unless + TJ.FLAG_STOPONWARNING is specified.)

Parameters:
dstImage - a BufferedImage instance that will receive the decompressed/decoded image. If the source image is a JPEG image, then the width and height of the BufferedImage instance must match diff --git a/java/org/libjpegturbo/turbojpeg/TJ.java b/java/org/libjpegturbo/turbojpeg/TJ.java index 045e829..ee000a9 100644 --- a/java/org/libjpegturbo/turbojpeg/TJ.java +++ b/java/org/libjpegturbo/turbojpeg/TJ.java @@ -391,6 +391,11 @@ public final class TJ { * operation if the underlying codec throws a warning (non-fatal error). The * default behavior is to allow the operation to complete unless a fatal * error is encountered. + *

+ * NOTE: due to the design of the TurboJPEG Java API, only certain methods + * (specifically, {@link TJDecompressor TJDecompressor.decompress*()} methods + * with a void return type) will complete and leave the output image in a + * fully recoverable state after a non-fatal error occurs. */ public static final int FLAG_STOPONWARNING = 8192; /** @@ -409,6 +414,11 @@ public final class TJ { /** * The error was non-fatal and recoverable, but the image may still be * corrupt. + *

+ * NOTE: due to the design of the TurboJPEG Java API, only certain methods + * (specifically, {@link TJDecompressor TJDecompressor.decompress*()} methods + * with a void return type) will complete and leave the output image in a + * fully recoverable state after a non-fatal error occurs. */ public static final int ERR_WARNING = 0; /** diff --git a/java/org/libjpegturbo/turbojpeg/TJDecompressor.java b/java/org/libjpegturbo/turbojpeg/TJDecompressor.java index bd0e694..be71cb0 100644 --- a/java/org/libjpegturbo/turbojpeg/TJDecompressor.java +++ b/java/org/libjpegturbo/turbojpeg/TJDecompressor.java @@ -308,6 +308,10 @@ public class TJDecompressor implements Closeable { * Decompress the JPEG source image or decode the YUV source image associated * with this decompressor instance and output a grayscale, RGB, or CMYK image * to the given destination buffer. + *

+ * NOTE: The output image is fully recoverable if this method throws a + * non-fatal {@link TJException} (unless + * {@link TJ#FLAG_STOPONWARNING TJ.FLAG_STOPONWARNING} is specified.) * * @param dstBuf buffer that will receive the decompressed/decoded image. * If the source image is a JPEG image, then this buffer should normally be @@ -451,6 +455,10 @@ public class TJDecompressor implements Closeable { * but leaves out the color conversion step, so a planar YUV image is * generated instead of an RGB or grayscale image. This method cannot be * used to decompress JPEG source images with the CMYK or YCCK colorspace. + *

+ * NOTE: The YUV planar output image is fully recoverable if this method + * throws a non-fatal {@link TJException} (unless + * {@link TJ#FLAG_STOPONWARNING TJ.FLAG_STOPONWARNING} is specified.) * * @param dstImage {@link YUVImage} instance that will receive the YUV planar * image. The level of subsampling specified in this YUVImage @@ -618,6 +626,10 @@ public class TJDecompressor implements Closeable { * Decompress the JPEG source image or decode the YUV source image associated * with this decompressor instance and output a grayscale, RGB, or CMYK image * to the given destination buffer. + *

+ * NOTE: The output image is fully recoverable if this method throws a + * non-fatal {@link TJException} (unless + * {@link TJ#FLAG_STOPONWARNING TJ.FLAG_STOPONWARNING} is specified.) * * @param dstBuf buffer that will receive the decompressed/decoded image. * If the source image is a JPEG image, then this buffer should normally be @@ -699,6 +711,10 @@ public class TJDecompressor implements Closeable { * Decompress the JPEG source image or decode the YUV source image associated * with this decompressor instance and output a decompressed/decoded image to * the given BufferedImage instance. + *

+ * NOTE: The output image is fully recoverable if this method throws a + * non-fatal {@link TJException} (unless + * {@link TJ#FLAG_STOPONWARNING TJ.FLAG_STOPONWARNING} is specified.) * * @param dstImage a BufferedImage instance that will receive * the decompressed/decoded image. If the source image is a JPEG image, then diff --git a/tjbench.c b/tjbench.c index 450e128..a627510 100644 --- a/tjbench.c +++ b/tjbench.c @@ -38,15 +38,44 @@ #include "./turbojpeg.h" -#define _throw(op, err) { \ +#define _throw(op, err) \ +{ \ printf("ERROR in line %d while %s:\n%s\n", __LINE__, op, err); \ - retval=-1; goto bailout;} + retval=-1; goto bailout; \ +} #define _throwunix(m) _throw(m, strerror(errno)) -#define _throwtj(m) { \ - printf("%s in line %d while %s:\n%s\n", \ - tjGetErrorCode(handle)==TJERR_WARNING ? "WARNING" : "ERROR", __LINE__, \ - m, tjGetErrorStr2(handle)); \ - retval=-1; goto bailout;} + +char tjErrorStr[JMSG_LENGTH_MAX]="\0", tjErrorMsg[JMSG_LENGTH_MAX]="\0"; +int tjErrorLine=-1, tjErrorCode=-1; + +#define _throwtj(m) \ +{ \ + int _tjErrorCode=tjGetErrorCode(handle); \ + char *_tjErrorStr=tjGetErrorStr2(handle); \ + \ + if(!(flags&TJFLAG_STOPONWARNING) && _tjErrorCode==TJERR_WARNING) \ + { \ + if(strncmp(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX) || \ + strncmp(tjErrorMsg, m, JMSG_LENGTH_MAX) || \ + tjErrorCode!=_tjErrorCode || tjErrorLine!=__LINE__) \ + { \ + strncpy(tjErrorStr, _tjErrorStr, JMSG_LENGTH_MAX); \ + strncpy(tjErrorMsg, m, JMSG_LENGTH_MAX); \ + tjErrorCode=_tjErrorCode; \ + tjErrorLine=__LINE__; \ + printf("WARNING in line %d while %s:\n%s\n", __LINE__, m, \ + _tjErrorStr); \ + } \ + } \ + else \ + { \ + printf("%s in line %d while %s:\n%s\n", \ + _tjErrorCode==TJERR_WARNING ? "WARNING" : "ERROR", __LINE__, m, \ + _tjErrorStr); \ + retval=-1; goto bailout; \ + } \ +} + #define _throwbmp(m) _throw(m, bmpgeterr()) int flags=TJFLAG_NOREALLOC, componly=0, decomponly=0, doyuv=0, quiet=0,