< prev index next >

src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java

Print this page


   1 /*
   2  * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 261      * This routine is called by the native code when it has already
 262      * formatted a string for output.
 263      * XXX  For truly complete localization of all warning messages,
 264      * the sun_jpeg_output_message routine in the native code should
 265      * send only the codes and parameters to a method here in Java,
 266      * which will then format and send the warnings, using localized
 267      * strings.  This method will have to deal with all the parameters
 268      * and formats (%u with possibly large numbers, %02d, %02x, etc.)
 269      * that actually occur in the JPEG library.  For now, this prevents
 270      * library warnings from being printed to stderr.
 271      */
 272     protected void warningWithMessage(String msg) {
 273         cbLock.lock();
 274         try {
 275             processWarningOccurred(msg);
 276         } finally {
 277             cbLock.unlock();
 278         }
 279     }
 280 

 281     public void setInput(Object input,
 282                          boolean seekForwardOnly,
 283                          boolean ignoreMetadata)
 284     {
 285         setThreadLock();
 286         try {
 287             cbLock.check();
 288 
 289             super.setInput(input, seekForwardOnly, ignoreMetadata);
 290             this.ignoreMetadata = ignoreMetadata;
 291             resetInternalState();
 292             iis = (ImageInputStream) input; // Always works
 293             setSource(structPointer);
 294         } finally {
 295             clearThreadLock();
 296         }
 297     }
 298 
 299     /**
 300      * This method is called from native code in order to fill


 367             // Now we are at the first image if there are any, so add it
 368             // to the list
 369             if (hasNextImage()) {
 370                 imagePositions.add(iis.getStreamPosition());
 371             }
 372         } else { // Not tables only, so add original pos to the list
 373             imagePositions.add(savePos);
 374             // And set current image since we've read it now
 375             currentImage = 0;
 376         }
 377         // If the image positions list is empty as in the case of a tables-only
 378         // stream, then attempting to access the element at index
 379         // imagePositions.size() - 1 will cause an IndexOutOfBoundsException.
 380         if (seekForwardOnly && !imagePositions.isEmpty()) {
 381             Long pos = imagePositions.get(imagePositions.size()-1);
 382             iis.flushBefore(pos.longValue());
 383         }
 384         tablesOnlyChecked = true;
 385     }
 386 

 387     public int getNumImages(boolean allowSearch) throws IOException {
 388         setThreadLock();
 389         try { // locked thread
 390             cbLock.check();
 391 
 392             return getNumImagesOnThread(allowSearch);
 393         } finally {
 394             clearThreadLock();
 395         }
 396     }
 397 
 398     private void skipPastImage(int imageIndex) {
 399         cbLock.lock();
 400         try {
 401             gotoImage(imageIndex);
 402             skipImage();
 403         } catch (IOException | IndexOutOfBoundsException e) {
 404         } finally {
 405             cbLock.unlock();
 406         }


 813             iccCS = new ICC_ColorSpace(newProfile);
 814             // verify new color space
 815             try {
 816                 float[] colors = iccCS.fromRGB(new float[] {1f, 0f, 0f});
 817             } catch (CMMException e) {
 818                 /*
 819                  * Embedded profile seems to be corrupted.
 820                  * Ignore this profile.
 821                  */
 822                 iccCS = null;
 823                 cbLock.lock();
 824                 try {
 825                     warningOccurred(WARNING_IGNORE_INVALID_ICC);
 826                 } finally {
 827                     cbLock.unlock();
 828                 }
 829             }
 830         }
 831     }
 832 

 833     public int getWidth(int imageIndex) throws IOException {
 834         setThreadLock();
 835         try {
 836             if (currentImage != imageIndex) {
 837                 cbLock.check();
 838                 readHeader(imageIndex, true);
 839             }
 840             return width;
 841         } finally {
 842             clearThreadLock();
 843         }
 844     }
 845 

 846     public int getHeight(int imageIndex) throws IOException {
 847         setThreadLock();
 848         try {
 849             if (currentImage != imageIndex) {
 850                 cbLock.check();
 851                 readHeader(imageIndex, true);
 852             }
 853             return height;
 854         } finally {
 855             clearThreadLock();
 856         }
 857     }
 858 
 859     /////////// Color Conversion and Image Types
 860 
 861     /**
 862      * Return an ImageTypeSpecifier corresponding to the given
 863      * color space code, or null if the color space is unsupported.
 864      */
 865     private ImageTypeProducer getImageType(int code) {
 866         ImageTypeProducer ret = null;
 867 
 868         if ((code > 0) && (code < JPEG.NUM_JCS_CODES)) {
 869             ret = ImageTypeProducer.getTypeProducer(code);
 870         }
 871         return ret;
 872     }
 873 

 874     public ImageTypeSpecifier getRawImageType(int imageIndex)
 875         throws IOException {
 876         setThreadLock();
 877         try {
 878             if (currentImage != imageIndex) {
 879                 cbLock.check();
 880 
 881                 readHeader(imageIndex, true);
 882             }
 883 
 884             // Returns null if it can't be represented
 885             return getImageType(colorSpaceCode).getType();
 886         } finally {
 887             clearThreadLock();
 888         }
 889     }
 890 

 891     public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex)
 892         throws IOException {
 893         setThreadLock();
 894         try {
 895             return getImageTypesOnThread(imageIndex);
 896         } finally {
 897             clearThreadLock();
 898         }
 899     }
 900 
 901     private Iterator<ImageTypeSpecifier> getImageTypesOnThread(int imageIndex)
 902         throws IOException {
 903         if (currentImage != imageIndex) {
 904             cbLock.check();
 905             readHeader(imageIndex, true);
 906         }
 907 
 908         // We return an iterator containing the default, any
 909         // conversions that the library provides, and
 910         // all the other default types with the same number


1041                 // Target isn't sRGB, so convert from sRGB to the target
1042                 convert = new ColorConvertOp(JPEG.JCS.sRGB, cs, null);
1043             } else if (csType != ColorSpace.TYPE_RGB) {
1044                 throw new IIOException("Incompatible color conversion");
1045             }
1046             break;
1047         default:
1048             // Anything else we can't handle at all
1049             throw new IIOException("Incompatible color conversion");
1050         }
1051     }
1052 
1053     /**
1054      * Set the IJG output space to the given value.  The library will
1055      * perform the appropriate colorspace conversions.
1056      */
1057     private native void setOutColorSpace(long structPointer, int id);
1058 
1059     /////// End of Color Conversion & Image Types
1060 

1061     public ImageReadParam getDefaultReadParam() {
1062         return new JPEGImageReadParam();
1063     }
1064 

1065     public IIOMetadata getStreamMetadata() throws IOException {
1066         setThreadLock();
1067         try {
1068             if (!tablesOnlyChecked) {
1069                 cbLock.check();
1070                 checkTablesOnly();
1071             }
1072             return streamMetadata;
1073         } finally {
1074             clearThreadLock();
1075         }
1076     }
1077 

1078     public IIOMetadata getImageMetadata(int imageIndex)
1079         throws IOException {
1080         setThreadLock();
1081         try {
1082             // imageMetadataIndex will always be either a valid index or
1083             // -1, in which case imageMetadata will not be null.
1084             // So we can leave checking imageIndex for gotoImage.
1085             if ((imageMetadataIndex == imageIndex)
1086                 && (imageMetadata != null)) {
1087                 return imageMetadata;
1088             }
1089 
1090             cbLock.check();
1091 
1092             gotoImage(imageIndex);
1093 
1094             imageMetadata = new JPEGMetadata(false, false, iis, this);
1095 
1096             imageMetadataIndex = imageIndex;
1097 
1098             return imageMetadata;
1099         } finally {
1100             clearThreadLock();
1101         }
1102     }
1103 

1104     public BufferedImage read(int imageIndex, ImageReadParam param)
1105         throws IOException {
1106         setThreadLock();
1107         try {
1108             cbLock.check();
1109             try {
1110                 readInternal(imageIndex, param, false);
1111             } catch (RuntimeException e) {
1112                 resetLibraryState(structPointer);
1113                 throw e;
1114             } catch (IOException e) {
1115                 resetLibraryState(structPointer);
1116                 throw e;
1117             }
1118 
1119             BufferedImage ret = image;
1120             image = null;  // don't keep a reference here
1121             return ret;
1122         } finally {
1123             clearThreadLock();


1476                                      byte [] buffer,
1477                                      int numRasterBands,
1478                                      int [] srcBands,
1479                                      int [] bandSizes,
1480                                      int sourceXOffset, int sourceYOffset,
1481                                      int sourceWidth, int sourceHeight,
1482                                      int periodX, int periodY,
1483                                      JPEGQTable [] abbrevQTables,
1484                                      JPEGHuffmanTable [] abbrevDCHuffmanTables,
1485                                      JPEGHuffmanTable [] abbrevACHuffmanTables,
1486                                      int minProgressivePass,
1487                                      int maxProgressivePass,
1488                                      boolean wantUpdates);
1489 
1490     /*
1491      * We should call clearNativeReadAbortFlag() before we start reading
1492      * jpeg image as image processing happens at native side.
1493      */
1494     private native void clearNativeReadAbortFlag(long structPointer);
1495 

1496     public void abort() {
1497         setThreadLock();
1498         try {
1499             /**
1500              * NB: we do not check the call back lock here,
1501              * we allow to abort the reader any time.
1502              */
1503 
1504             super.abort();
1505             abortRead(structPointer);
1506         } finally {
1507             clearThreadLock();
1508         }
1509     }
1510 
1511     /** Set the C level abort flag. Keep it atomic for thread safety. */
1512     private native void abortRead(long structPointer);
1513 
1514     /** Resets library state when an exception occurred during a read. */
1515     private native void resetLibraryState(long structPointer);
1516 

1517     public boolean canReadRaster() {
1518         return true;
1519     }
1520 

1521     public Raster readRaster(int imageIndex, ImageReadParam param)
1522         throws IOException {
1523         setThreadLock();
1524         Raster retval = null;
1525         try {
1526             cbLock.check();
1527             /*
1528              * This could be further optimized by not resetting the dest.
1529              * offset and creating a translated raster in readInternal()
1530              * (see bug 4994702 for more info).
1531              */
1532 
1533             // For Rasters, destination offset is logical, not physical, so
1534             // set it to 0 before calling computeRegions, so that the destination
1535             // region is not clipped.
1536             Point saveDestOffset = null;
1537             if (param != null) {
1538                 saveDestOffset = param.getDestinationOffset();
1539                 param.setDestinationOffset(new Point(0, 0));
1540             }
1541             retval = readInternal(imageIndex, param, true);
1542             // Apply the destination offset, if any, as a logical offset
1543             if (saveDestOffset != null) {
1544                 target = target.createWritableTranslatedChild(saveDestOffset.x,
1545                                                               saveDestOffset.y);
1546             }
1547         } catch (RuntimeException e) {
1548             resetLibraryState(structPointer);
1549             throw e;
1550         } catch (IOException e) {
1551             resetLibraryState(structPointer);
1552             throw e;
1553         } finally {
1554             clearThreadLock();
1555         }
1556         return retval;
1557     }
1558 

1559     public boolean readerSupportsThumbnails() {
1560         return true;
1561     }
1562 

1563     public int getNumThumbnails(int imageIndex) throws IOException {
1564         setThreadLock();
1565         try {
1566             cbLock.check();
1567 
1568             getImageMetadata(imageIndex);  // checks iis state for us
1569             // Now check the jfif segments
1570             JFIFMarkerSegment jfif =
1571                 (JFIFMarkerSegment) imageMetadata.findMarkerSegment
1572                 (JFIFMarkerSegment.class, true);
1573             int retval = 0;
1574             if (jfif != null) {
1575                 retval = (jfif.thumb == null) ? 0 : 1;
1576                 retval += jfif.extSegments.size();
1577             }
1578             return retval;
1579         } finally {
1580             clearThreadLock();
1581         }
1582     }
1583 

1584     public int getThumbnailWidth(int imageIndex, int thumbnailIndex)
1585         throws IOException {
1586         setThreadLock();
1587         try {
1588             cbLock.check();
1589 
1590             if ((thumbnailIndex < 0)
1591                 || (thumbnailIndex >= getNumThumbnails(imageIndex))) {
1592                 throw new IndexOutOfBoundsException("No such thumbnail");
1593             }
1594             // Now we know that there is a jfif segment
1595             JFIFMarkerSegment jfif =
1596                 (JFIFMarkerSegment) imageMetadata.findMarkerSegment
1597                 (JFIFMarkerSegment.class, true);
1598             return  jfif.getThumbnailWidth(thumbnailIndex);
1599         } finally {
1600             clearThreadLock();
1601         }
1602     }
1603 

1604     public int getThumbnailHeight(int imageIndex, int thumbnailIndex)
1605         throws IOException {
1606         setThreadLock();
1607         try {
1608             cbLock.check();
1609 
1610             if ((thumbnailIndex < 0)
1611                 || (thumbnailIndex >= getNumThumbnails(imageIndex))) {
1612                 throw new IndexOutOfBoundsException("No such thumbnail");
1613             }
1614             // Now we know that there is a jfif segment
1615             JFIFMarkerSegment jfif =
1616                 (JFIFMarkerSegment) imageMetadata.findMarkerSegment
1617                 (JFIFMarkerSegment.class, true);
1618             return  jfif.getThumbnailHeight(thumbnailIndex);
1619         } finally {
1620             clearThreadLock();
1621         }
1622     }
1623 

1624     public BufferedImage readThumbnail(int imageIndex,
1625                                        int thumbnailIndex)
1626         throws IOException {
1627         setThreadLock();
1628         try {
1629             cbLock.check();
1630 
1631             if ((thumbnailIndex < 0)
1632                 || (thumbnailIndex >= getNumThumbnails(imageIndex))) {
1633                 throw new IndexOutOfBoundsException("No such thumbnail");
1634             }
1635             // Now we know that there is a jfif segment and that iis is good
1636             JFIFMarkerSegment jfif =
1637                 (JFIFMarkerSegment) imageMetadata.findMarkerSegment
1638                 (JFIFMarkerSegment.class, true);
1639             return  jfif.getThumbnail(iis, thumbnailIndex, this);
1640         } finally {
1641             clearThreadLock();
1642         }
1643     }


1648 
1649         // reset local Java structures
1650         numImages = 0;
1651         imagePositions = new ArrayList<>();
1652         currentImage = -1;
1653         image = null;
1654         raster = null;
1655         target = null;
1656         buffer = null;
1657         destROI = null;
1658         destinationBands = null;
1659         streamMetadata = null;
1660         imageMetadata = null;
1661         imageMetadataIndex = -1;
1662         haveSeeked = false;
1663         tablesOnlyChecked = false;
1664         iccCS = null;
1665         initProgressData();
1666     }
1667 

1668     public void reset() {
1669         setThreadLock();
1670         try {
1671             cbLock.check();
1672             super.reset();
1673         } finally {
1674             clearThreadLock();
1675         }
1676     }
1677 
1678     private native void resetReader(long structPointer);
1679 

1680     public void dispose() {
1681         setThreadLock();
1682         try {
1683             cbLock.check();
1684 
1685             if (structPointer != 0) {
1686                 disposerRecord.dispose();
1687                 structPointer = 0;
1688             }
1689         } finally {
1690             clearThreadLock();
1691         }
1692     }
1693 
1694     private static native void disposeReader(long structPointer);
1695 
1696     private static class JPEGReaderDisposerRecord implements DisposerRecord {
1697         private long pData;
1698 
1699         public JPEGReaderDisposerRecord(long pData) {
1700             this.pData = pData;
1701         }
1702 

1703         public synchronized void dispose() {
1704             if (pData != 0) {
1705                 disposeReader(pData);
1706                 pData = 0;
1707             }
1708         }
1709     }
1710 
1711     private Thread theThread = null;
1712     private int theLockCount = 0;
1713 
1714     private synchronized void setThreadLock() {
1715         Thread currThread = Thread.currentThread();
1716         if (theThread != null) {
1717             if (theThread != currThread) {
1718                 // it looks like that this reader instance is used
1719                 // by multiple threads.
1720                 throw new IllegalStateException("Attempt to use instance of " +
1721                                                 this + " locked on thread " +
1722                                                 theThread + " from thread " +


   1 /*
   2  * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 261      * This routine is called by the native code when it has already
 262      * formatted a string for output.
 263      * XXX  For truly complete localization of all warning messages,
 264      * the sun_jpeg_output_message routine in the native code should
 265      * send only the codes and parameters to a method here in Java,
 266      * which will then format and send the warnings, using localized
 267      * strings.  This method will have to deal with all the parameters
 268      * and formats (%u with possibly large numbers, %02d, %02x, etc.)
 269      * that actually occur in the JPEG library.  For now, this prevents
 270      * library warnings from being printed to stderr.
 271      */
 272     protected void warningWithMessage(String msg) {
 273         cbLock.lock();
 274         try {
 275             processWarningOccurred(msg);
 276         } finally {
 277             cbLock.unlock();
 278         }
 279     }
 280 
 281     @Override
 282     public void setInput(Object input,
 283                          boolean seekForwardOnly,
 284                          boolean ignoreMetadata)
 285     {
 286         setThreadLock();
 287         try {
 288             cbLock.check();
 289 
 290             super.setInput(input, seekForwardOnly, ignoreMetadata);
 291             this.ignoreMetadata = ignoreMetadata;
 292             resetInternalState();
 293             iis = (ImageInputStream) input; // Always works
 294             setSource(structPointer);
 295         } finally {
 296             clearThreadLock();
 297         }
 298     }
 299 
 300     /**
 301      * This method is called from native code in order to fill


 368             // Now we are at the first image if there are any, so add it
 369             // to the list
 370             if (hasNextImage()) {
 371                 imagePositions.add(iis.getStreamPosition());
 372             }
 373         } else { // Not tables only, so add original pos to the list
 374             imagePositions.add(savePos);
 375             // And set current image since we've read it now
 376             currentImage = 0;
 377         }
 378         // If the image positions list is empty as in the case of a tables-only
 379         // stream, then attempting to access the element at index
 380         // imagePositions.size() - 1 will cause an IndexOutOfBoundsException.
 381         if (seekForwardOnly && !imagePositions.isEmpty()) {
 382             Long pos = imagePositions.get(imagePositions.size()-1);
 383             iis.flushBefore(pos.longValue());
 384         }
 385         tablesOnlyChecked = true;
 386     }
 387 
 388     @Override
 389     public int getNumImages(boolean allowSearch) throws IOException {
 390         setThreadLock();
 391         try { // locked thread
 392             cbLock.check();
 393 
 394             return getNumImagesOnThread(allowSearch);
 395         } finally {
 396             clearThreadLock();
 397         }
 398     }
 399 
 400     private void skipPastImage(int imageIndex) {
 401         cbLock.lock();
 402         try {
 403             gotoImage(imageIndex);
 404             skipImage();
 405         } catch (IOException | IndexOutOfBoundsException e) {
 406         } finally {
 407             cbLock.unlock();
 408         }


 815             iccCS = new ICC_ColorSpace(newProfile);
 816             // verify new color space
 817             try {
 818                 float[] colors = iccCS.fromRGB(new float[] {1f, 0f, 0f});
 819             } catch (CMMException e) {
 820                 /*
 821                  * Embedded profile seems to be corrupted.
 822                  * Ignore this profile.
 823                  */
 824                 iccCS = null;
 825                 cbLock.lock();
 826                 try {
 827                     warningOccurred(WARNING_IGNORE_INVALID_ICC);
 828                 } finally {
 829                     cbLock.unlock();
 830                 }
 831             }
 832         }
 833     }
 834 
 835     @Override
 836     public int getWidth(int imageIndex) throws IOException {
 837         setThreadLock();
 838         try {
 839             if (currentImage != imageIndex) {
 840                 cbLock.check();
 841                 readHeader(imageIndex, true);
 842             }
 843             return width;
 844         } finally {
 845             clearThreadLock();
 846         }
 847     }
 848 
 849     @Override
 850     public int getHeight(int imageIndex) throws IOException {
 851         setThreadLock();
 852         try {
 853             if (currentImage != imageIndex) {
 854                 cbLock.check();
 855                 readHeader(imageIndex, true);
 856             }
 857             return height;
 858         } finally {
 859             clearThreadLock();
 860         }
 861     }
 862 
 863     /////////// Color Conversion and Image Types
 864 
 865     /**
 866      * Return an ImageTypeSpecifier corresponding to the given
 867      * color space code, or null if the color space is unsupported.
 868      */
 869     private ImageTypeProducer getImageType(int code) {
 870         ImageTypeProducer ret = null;
 871 
 872         if ((code > 0) && (code < JPEG.NUM_JCS_CODES)) {
 873             ret = ImageTypeProducer.getTypeProducer(code);
 874         }
 875         return ret;
 876     }
 877 
 878     @Override
 879     public ImageTypeSpecifier getRawImageType(int imageIndex)
 880         throws IOException {
 881         setThreadLock();
 882         try {
 883             if (currentImage != imageIndex) {
 884                 cbLock.check();
 885 
 886                 readHeader(imageIndex, true);
 887             }
 888 
 889             // Returns null if it can't be represented
 890             return getImageType(colorSpaceCode).getType();
 891         } finally {
 892             clearThreadLock();
 893         }
 894     }
 895 
 896     @Override
 897     public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex)
 898         throws IOException {
 899         setThreadLock();
 900         try {
 901             return getImageTypesOnThread(imageIndex);
 902         } finally {
 903             clearThreadLock();
 904         }
 905     }
 906 
 907     private Iterator<ImageTypeSpecifier> getImageTypesOnThread(int imageIndex)
 908         throws IOException {
 909         if (currentImage != imageIndex) {
 910             cbLock.check();
 911             readHeader(imageIndex, true);
 912         }
 913 
 914         // We return an iterator containing the default, any
 915         // conversions that the library provides, and
 916         // all the other default types with the same number


1047                 // Target isn't sRGB, so convert from sRGB to the target
1048                 convert = new ColorConvertOp(JPEG.JCS.sRGB, cs, null);
1049             } else if (csType != ColorSpace.TYPE_RGB) {
1050                 throw new IIOException("Incompatible color conversion");
1051             }
1052             break;
1053         default:
1054             // Anything else we can't handle at all
1055             throw new IIOException("Incompatible color conversion");
1056         }
1057     }
1058 
1059     /**
1060      * Set the IJG output space to the given value.  The library will
1061      * perform the appropriate colorspace conversions.
1062      */
1063     private native void setOutColorSpace(long structPointer, int id);
1064 
1065     /////// End of Color Conversion & Image Types
1066 
1067     @Override
1068     public ImageReadParam getDefaultReadParam() {
1069         return new JPEGImageReadParam();
1070     }
1071 
1072     @Override
1073     public IIOMetadata getStreamMetadata() throws IOException {
1074         setThreadLock();
1075         try {
1076             if (!tablesOnlyChecked) {
1077                 cbLock.check();
1078                 checkTablesOnly();
1079             }
1080             return streamMetadata;
1081         } finally {
1082             clearThreadLock();
1083         }
1084     }
1085 
1086     @Override
1087     public IIOMetadata getImageMetadata(int imageIndex)
1088         throws IOException {
1089         setThreadLock();
1090         try {
1091             // imageMetadataIndex will always be either a valid index or
1092             // -1, in which case imageMetadata will not be null.
1093             // So we can leave checking imageIndex for gotoImage.
1094             if ((imageMetadataIndex == imageIndex)
1095                 && (imageMetadata != null)) {
1096                 return imageMetadata;
1097             }
1098 
1099             cbLock.check();
1100 
1101             gotoImage(imageIndex);
1102 
1103             imageMetadata = new JPEGMetadata(false, false, iis, this);
1104 
1105             imageMetadataIndex = imageIndex;
1106 
1107             return imageMetadata;
1108         } finally {
1109             clearThreadLock();
1110         }
1111     }
1112 
1113     @Override
1114     public BufferedImage read(int imageIndex, ImageReadParam param)
1115         throws IOException {
1116         setThreadLock();
1117         try {
1118             cbLock.check();
1119             try {
1120                 readInternal(imageIndex, param, false);
1121             } catch (RuntimeException e) {
1122                 resetLibraryState(structPointer);
1123                 throw e;
1124             } catch (IOException e) {
1125                 resetLibraryState(structPointer);
1126                 throw e;
1127             }
1128 
1129             BufferedImage ret = image;
1130             image = null;  // don't keep a reference here
1131             return ret;
1132         } finally {
1133             clearThreadLock();


1486                                      byte [] buffer,
1487                                      int numRasterBands,
1488                                      int [] srcBands,
1489                                      int [] bandSizes,
1490                                      int sourceXOffset, int sourceYOffset,
1491                                      int sourceWidth, int sourceHeight,
1492                                      int periodX, int periodY,
1493                                      JPEGQTable [] abbrevQTables,
1494                                      JPEGHuffmanTable [] abbrevDCHuffmanTables,
1495                                      JPEGHuffmanTable [] abbrevACHuffmanTables,
1496                                      int minProgressivePass,
1497                                      int maxProgressivePass,
1498                                      boolean wantUpdates);
1499 
1500     /*
1501      * We should call clearNativeReadAbortFlag() before we start reading
1502      * jpeg image as image processing happens at native side.
1503      */
1504     private native void clearNativeReadAbortFlag(long structPointer);
1505 
1506     @Override
1507     public void abort() {
1508         setThreadLock();
1509         try {
1510             /**
1511              * NB: we do not check the call back lock here,
1512              * we allow to abort the reader any time.
1513              */
1514 
1515             super.abort();
1516             abortRead(structPointer);
1517         } finally {
1518             clearThreadLock();
1519         }
1520     }
1521 
1522     /** Set the C level abort flag. Keep it atomic for thread safety. */
1523     private native void abortRead(long structPointer);
1524 
1525     /** Resets library state when an exception occurred during a read. */
1526     private native void resetLibraryState(long structPointer);
1527 
1528     @Override
1529     public boolean canReadRaster() {
1530         return true;
1531     }
1532 
1533     @Override
1534     public Raster readRaster(int imageIndex, ImageReadParam param)
1535         throws IOException {
1536         setThreadLock();
1537         Raster retval = null;
1538         try {
1539             cbLock.check();
1540             /*
1541              * This could be further optimized by not resetting the dest.
1542              * offset and creating a translated raster in readInternal()
1543              * (see bug 4994702 for more info).
1544              */
1545 
1546             // For Rasters, destination offset is logical, not physical, so
1547             // set it to 0 before calling computeRegions, so that the destination
1548             // region is not clipped.
1549             Point saveDestOffset = null;
1550             if (param != null) {
1551                 saveDestOffset = param.getDestinationOffset();
1552                 param.setDestinationOffset(new Point(0, 0));
1553             }
1554             retval = readInternal(imageIndex, param, true);
1555             // Apply the destination offset, if any, as a logical offset
1556             if (saveDestOffset != null) {
1557                 target = target.createWritableTranslatedChild(saveDestOffset.x,
1558                                                               saveDestOffset.y);
1559             }
1560         } catch (RuntimeException e) {
1561             resetLibraryState(structPointer);
1562             throw e;
1563         } catch (IOException e) {
1564             resetLibraryState(structPointer);
1565             throw e;
1566         } finally {
1567             clearThreadLock();
1568         }
1569         return retval;
1570     }
1571 
1572     @Override
1573     public boolean readerSupportsThumbnails() {
1574         return true;
1575     }
1576 
1577     @Override
1578     public int getNumThumbnails(int imageIndex) throws IOException {
1579         setThreadLock();
1580         try {
1581             cbLock.check();
1582 
1583             getImageMetadata(imageIndex);  // checks iis state for us
1584             // Now check the jfif segments
1585             JFIFMarkerSegment jfif =
1586                 (JFIFMarkerSegment) imageMetadata.findMarkerSegment
1587                 (JFIFMarkerSegment.class, true);
1588             int retval = 0;
1589             if (jfif != null) {
1590                 retval = (jfif.thumb == null) ? 0 : 1;
1591                 retval += jfif.extSegments.size();
1592             }
1593             return retval;
1594         } finally {
1595             clearThreadLock();
1596         }
1597     }
1598 
1599     @Override
1600     public int getThumbnailWidth(int imageIndex, int thumbnailIndex)
1601         throws IOException {
1602         setThreadLock();
1603         try {
1604             cbLock.check();
1605 
1606             if ((thumbnailIndex < 0)
1607                 || (thumbnailIndex >= getNumThumbnails(imageIndex))) {
1608                 throw new IndexOutOfBoundsException("No such thumbnail");
1609             }
1610             // Now we know that there is a jfif segment
1611             JFIFMarkerSegment jfif =
1612                 (JFIFMarkerSegment) imageMetadata.findMarkerSegment
1613                 (JFIFMarkerSegment.class, true);
1614             return  jfif.getThumbnailWidth(thumbnailIndex);
1615         } finally {
1616             clearThreadLock();
1617         }
1618     }
1619 
1620     @Override
1621     public int getThumbnailHeight(int imageIndex, int thumbnailIndex)
1622         throws IOException {
1623         setThreadLock();
1624         try {
1625             cbLock.check();
1626 
1627             if ((thumbnailIndex < 0)
1628                 || (thumbnailIndex >= getNumThumbnails(imageIndex))) {
1629                 throw new IndexOutOfBoundsException("No such thumbnail");
1630             }
1631             // Now we know that there is a jfif segment
1632             JFIFMarkerSegment jfif =
1633                 (JFIFMarkerSegment) imageMetadata.findMarkerSegment
1634                 (JFIFMarkerSegment.class, true);
1635             return  jfif.getThumbnailHeight(thumbnailIndex);
1636         } finally {
1637             clearThreadLock();
1638         }
1639     }
1640 
1641     @Override
1642     public BufferedImage readThumbnail(int imageIndex,
1643                                        int thumbnailIndex)
1644         throws IOException {
1645         setThreadLock();
1646         try {
1647             cbLock.check();
1648 
1649             if ((thumbnailIndex < 0)
1650                 || (thumbnailIndex >= getNumThumbnails(imageIndex))) {
1651                 throw new IndexOutOfBoundsException("No such thumbnail");
1652             }
1653             // Now we know that there is a jfif segment and that iis is good
1654             JFIFMarkerSegment jfif =
1655                 (JFIFMarkerSegment) imageMetadata.findMarkerSegment
1656                 (JFIFMarkerSegment.class, true);
1657             return  jfif.getThumbnail(iis, thumbnailIndex, this);
1658         } finally {
1659             clearThreadLock();
1660         }
1661     }


1666 
1667         // reset local Java structures
1668         numImages = 0;
1669         imagePositions = new ArrayList<>();
1670         currentImage = -1;
1671         image = null;
1672         raster = null;
1673         target = null;
1674         buffer = null;
1675         destROI = null;
1676         destinationBands = null;
1677         streamMetadata = null;
1678         imageMetadata = null;
1679         imageMetadataIndex = -1;
1680         haveSeeked = false;
1681         tablesOnlyChecked = false;
1682         iccCS = null;
1683         initProgressData();
1684     }
1685 
1686     @Override
1687     public void reset() {
1688         setThreadLock();
1689         try {
1690             cbLock.check();
1691             super.reset();
1692         } finally {
1693             clearThreadLock();
1694         }
1695     }
1696 
1697     private native void resetReader(long structPointer);
1698 
1699     @Override
1700     public void dispose() {
1701         setThreadLock();
1702         try {
1703             cbLock.check();
1704 
1705             if (structPointer != 0) {
1706                 disposerRecord.dispose();
1707                 structPointer = 0;
1708             }
1709         } finally {
1710             clearThreadLock();
1711         }
1712     }
1713 
1714     private static native void disposeReader(long structPointer);
1715 
1716     private static class JPEGReaderDisposerRecord implements DisposerRecord {
1717         private long pData;
1718 
1719         public JPEGReaderDisposerRecord(long pData) {
1720             this.pData = pData;
1721         }
1722 
1723         @Override
1724         public synchronized void dispose() {
1725             if (pData != 0) {
1726                 disposeReader(pData);
1727                 pData = 0;
1728             }
1729         }
1730     }
1731 
1732     private Thread theThread = null;
1733     private int theLockCount = 0;
1734 
1735     private synchronized void setThreadLock() {
1736         Thread currThread = Thread.currentThread();
1737         if (theThread != null) {
1738             if (theThread != currThread) {
1739                 // it looks like that this reader instance is used
1740                 // by multiple threads.
1741                 throw new IllegalStateException("Attempt to use instance of " +
1742                                                 this + " locked on thread " +
1743                                                 theThread + " from thread " +


< prev index next >