jdk/src/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java
changeset 3009 de653b2cab31
parent 2381 0afc5d868c46
child 3013 d661931d1ca0
equal deleted inserted replaced
3008:e6248b598ca5 3009:de653b2cab31
    51 import java.awt.image.ColorConvertOp;
    51 import java.awt.image.ColorConvertOp;
    52 import java.io.IOException;
    52 import java.io.IOException;
    53 import java.util.List;
    53 import java.util.List;
    54 import java.util.Iterator;
    54 import java.util.Iterator;
    55 import java.util.ArrayList;
    55 import java.util.ArrayList;
       
    56 import java.util.NoSuchElementException;
    56 
    57 
    57 import sun.java2d.Disposer;
    58 import sun.java2d.Disposer;
    58 import sun.java2d.DisposerRecord;
    59 import sun.java2d.DisposerRecord;
    59 
    60 
    60 public class JPEGImageReader extends ImageReader {
    61 public class JPEGImageReader extends ImageReader {
   212     /** The referent to be registered with the Disposer. */
   213     /** The referent to be registered with the Disposer. */
   213     private Object disposerReferent = new Object();
   214     private Object disposerReferent = new Object();
   214 
   215 
   215     /** The DisposerRecord that handles the actual disposal of this reader. */
   216     /** The DisposerRecord that handles the actual disposal of this reader. */
   216     private DisposerRecord disposerRecord;
   217     private DisposerRecord disposerRecord;
   217 
       
   218     /**
       
   219      * Maintain an array of the default image types corresponding to the
       
   220      * various supported IJG colorspace codes.
       
   221      */
       
   222     private static final ImageTypeSpecifier [] defaultTypes =
       
   223         new ImageTypeSpecifier [JPEG.NUM_JCS_CODES];
       
   224 
       
   225     static {
       
   226         defaultTypes[JPEG.JCS_GRAYSCALE] =
       
   227             ImageTypeSpecifier.createFromBufferedImageType
       
   228             (BufferedImage.TYPE_BYTE_GRAY);
       
   229         defaultTypes[JPEG.JCS_RGB] =
       
   230             ImageTypeSpecifier.createInterleaved
       
   231             (JPEG.JCS.sRGB,
       
   232              JPEG.bOffsRGB,
       
   233              DataBuffer.TYPE_BYTE,
       
   234              false,
       
   235              false);
       
   236         defaultTypes[JPEG.JCS_RGBA] =
       
   237             ImageTypeSpecifier.createPacked
       
   238             (JPEG.JCS.sRGB,
       
   239              0xff000000,
       
   240              0x00ff0000,
       
   241              0x0000ff00,
       
   242              0x000000ff,
       
   243              DataBuffer.TYPE_INT,
       
   244              false);
       
   245         if (JPEG.JCS.YCC != null) {
       
   246             defaultTypes[JPEG.JCS_YCC] =
       
   247                 ImageTypeSpecifier.createInterleaved
       
   248                 (JPEG.JCS.YCC,
       
   249                  JPEG.bandOffsets[2],
       
   250                  DataBuffer.TYPE_BYTE,
       
   251                  false,
       
   252                  false);
       
   253             defaultTypes[JPEG.JCS_YCCA] =
       
   254                 ImageTypeSpecifier.createInterleaved
       
   255                 (JPEG.JCS.YCC,
       
   256                  JPEG.bandOffsets[3],
       
   257                  DataBuffer.TYPE_BYTE,
       
   258                  true,
       
   259                  false);
       
   260         }
       
   261     }
       
   262 
   218 
   263     /** Sets up static C structures. */
   219     /** Sets up static C structures. */
   264     private static native void initReaderIDs(Class iisClass,
   220     private static native void initReaderIDs(Class iisClass,
   265                                              Class qTableClass,
   221                                              Class qTableClass,
   266                                              Class huffClass);
   222                                              Class huffClass);
   704 
   660 
   705     /**
   661     /**
   706      * Return an ImageTypeSpecifier corresponding to the given
   662      * Return an ImageTypeSpecifier corresponding to the given
   707      * color space code, or null if the color space is unsupported.
   663      * color space code, or null if the color space is unsupported.
   708      */
   664      */
   709     private ImageTypeSpecifier getImageType(int code) {
   665     private ImageTypeProducer getImageType(int code) {
   710         ImageTypeSpecifier ret = null;
   666         ImageTypeProducer ret = null;
   711 
   667 
   712         if ((code > 0) && (code < JPEG.NUM_JCS_CODES)) {
   668         if ((code > 0) && (code < JPEG.NUM_JCS_CODES)) {
   713             ret = defaultTypes[code];
   669             ret = ImageTypeProducer.getTypeProducer(code);
   714         }
   670         }
   715         return ret;
   671         return ret;
   716     }
   672     }
   717 
   673 
   718     public ImageTypeSpecifier getRawImageType(int imageIndex)
   674     public ImageTypeSpecifier getRawImageType(int imageIndex)
   722             if (currentImage != imageIndex) {
   678             if (currentImage != imageIndex) {
   723                 readHeader(imageIndex, true);
   679                 readHeader(imageIndex, true);
   724             }
   680             }
   725 
   681 
   726             // Returns null if it can't be represented
   682             // Returns null if it can't be represented
   727             return getImageType(colorSpaceCode);
   683             return getImageType(colorSpaceCode).getType();
   728         } finally {
   684         } finally {
   729             clearThreadLock();
   685             clearThreadLock();
   730         }
   686         }
   731     }
   687     }
   732 
   688 
   756         // If this image can't be interpreted, this method
   712         // If this image can't be interpreted, this method
   757         // returns an empty Iterator.
   713         // returns an empty Iterator.
   758 
   714 
   759         // Get the raw ITS, if there is one.  Note that this
   715         // Get the raw ITS, if there is one.  Note that this
   760         // won't always be the same as the default.
   716         // won't always be the same as the default.
   761         ImageTypeSpecifier raw = getImageType(colorSpaceCode);
   717         ImageTypeProducer raw = getImageType(colorSpaceCode);
   762 
   718 
   763         // Given the encoded colorspace, build a list of ITS's
   719         // Given the encoded colorspace, build a list of ITS's
   764         // representing outputs you could handle starting
   720         // representing outputs you could handle starting
   765         // with the default.
   721         // with the default.
   766 
   722 
   767         ArrayList list = new ArrayList(1);
   723         ArrayList<ImageTypeProducer> list = new ArrayList<ImageTypeProducer>(1);
   768 
   724 
   769         switch (colorSpaceCode) {
   725         switch (colorSpaceCode) {
   770         case JPEG.JCS_GRAYSCALE:
   726         case JPEG.JCS_GRAYSCALE:
   771             list.add(raw);
   727             list.add(raw);
   772             list.add(getImageType(JPEG.JCS_RGB));
   728             list.add(getImageType(JPEG.JCS_RGB));
   773             break;
   729             break;
   774         case JPEG.JCS_RGB:
   730         case JPEG.JCS_RGB:
   775             list.add(raw);
   731             list.add(raw);
   776             list.add(getImageType(JPEG.JCS_GRAYSCALE));
   732             list.add(getImageType(JPEG.JCS_GRAYSCALE));
   777             if (JPEG.JCS.YCC != null) {
   733             list.add(getImageType(JPEG.JCS_YCC));
   778                 list.add(getImageType(JPEG.JCS_YCC));
       
   779             }
       
   780             break;
   734             break;
   781         case JPEG.JCS_RGBA:
   735         case JPEG.JCS_RGBA:
   782             list.add(raw);
   736             list.add(raw);
   783             break;
   737             break;
   784         case JPEG.JCS_YCC:
   738         case JPEG.JCS_YCC:
   799             // due to 4705399, use RGB as default in order to avoid
   753             // due to 4705399, use RGB as default in order to avoid
   800             // slowing down of drawing operations with result image.
   754             // slowing down of drawing operations with result image.
   801             list.add(getImageType(JPEG.JCS_RGB));
   755             list.add(getImageType(JPEG.JCS_RGB));
   802 
   756 
   803             if (iccCS != null) {
   757             if (iccCS != null) {
   804                 list.add(ImageTypeSpecifier.createInterleaved
   758                 list.add(new ImageTypeProducer() {
       
   759                     protected ImageTypeSpecifier produce() {
       
   760                         return ImageTypeSpecifier.createInterleaved
   805                          (iccCS,
   761                          (iccCS,
   806                           JPEG.bOffsRGB,  // Assume it's for RGB
   762                           JPEG.bOffsRGB,  // Assume it's for RGB
   807                           DataBuffer.TYPE_BYTE,
   763                           DataBuffer.TYPE_BYTE,
   808                           false,
   764                           false,
   809                           false));
   765                           false);
       
   766                     }
       
   767                 });
   810 
   768 
   811             }
   769             }
   812 
   770 
   813             list.add(getImageType(JPEG.JCS_GRAYSCALE));
   771             list.add(getImageType(JPEG.JCS_GRAYSCALE));
   814             if (JPEG.JCS.YCC != null) { // Might be null if PYCC.pf not installed
   772             list.add(getImageType(JPEG.JCS_YCC));
   815                 list.add(getImageType(JPEG.JCS_YCC));
       
   816             }
       
   817             break;
   773             break;
   818         case JPEG.JCS_YCbCrA:  // Default is to convert to RGBA
   774         case JPEG.JCS_YCbCrA:  // Default is to convert to RGBA
   819             // As there is no YCbCr ColorSpace, we can't support
   775             // As there is no YCbCr ColorSpace, we can't support
   820             // the raw type.
   776             // the raw type.
   821             list.add(getImageType(JPEG.JCS_RGBA));
   777             list.add(getImageType(JPEG.JCS_RGBA));
   822             break;
   778             break;
   823         }
   779         }
   824 
   780 
   825         return list.iterator();
   781         return new ImageTypeIterator(list.iterator());
   826     }
   782     }
   827 
   783 
   828     /**
   784     /**
   829      * Checks the implied color conversion between the stream and
   785      * Checks the implied color conversion between the stream and
   830      * the target image, altering the IJG output color space if necessary.
   786      * the target image, altering the IJG output color space if necessary.
   870         switch (outColorSpaceCode) {
   826         switch (outColorSpaceCode) {
   871         case JPEG.JCS_GRAYSCALE:  // Its gray in the file
   827         case JPEG.JCS_GRAYSCALE:  // Its gray in the file
   872             if  (csType == ColorSpace.TYPE_RGB) { // We want RGB
   828             if  (csType == ColorSpace.TYPE_RGB) { // We want RGB
   873                 // IJG can do this for us more efficiently
   829                 // IJG can do this for us more efficiently
   874                 setOutColorSpace(structPointer, JPEG.JCS_RGB);
   830                 setOutColorSpace(structPointer, JPEG.JCS_RGB);
       
   831                 // Update java state according to changes
       
   832                 // in the native part of decoder.
       
   833                 outColorSpaceCode = JPEG.JCS_RGB;
       
   834                 numComponents = 3;
   875             } else if (csType != ColorSpace.TYPE_GRAY) {
   835             } else if (csType != ColorSpace.TYPE_GRAY) {
   876                 throw new IIOException("Incompatible color conversion");
   836                 throw new IIOException("Incompatible color conversion");
   877             }
   837             }
   878             break;
   838             break;
   879         case JPEG.JCS_RGB:  // IJG wants to go to RGB
   839         case JPEG.JCS_RGB:  // IJG wants to go to RGB
   880             if (csType ==  ColorSpace.TYPE_GRAY) {  // We want gray
   840             if (csType ==  ColorSpace.TYPE_GRAY) {  // We want gray
   881                 if (colorSpaceCode == JPEG.JCS_YCbCr) {
   841                 if (colorSpaceCode == JPEG.JCS_YCbCr) {
   882                     // If the jpeg space is YCbCr, IJG can do it
   842                     // If the jpeg space is YCbCr, IJG can do it
   883                     setOutColorSpace(structPointer, JPEG.JCS_GRAYSCALE);
   843                     setOutColorSpace(structPointer, JPEG.JCS_GRAYSCALE);
       
   844                     // Update java state according to changes
       
   845                     // in the native part of decoder.
       
   846                     outColorSpaceCode = JPEG.JCS_GRAYSCALE;
       
   847                     numComponents = 1;
   884                 }
   848                 }
   885             } else if ((iccCS != null) &&
   849             } else if ((iccCS != null) &&
   886                        (cm.getNumComponents() == numComponents) &&
   850                        (cm.getNumComponents() == numComponents) &&
   887                        (cs != iccCS)) {
   851                        (cs != iccCS)) {
   888                 // We have an ICC profile but it isn't used in the dest
   852                 // We have an ICC profile but it isn't used in the dest
   904                 (cm.getNumComponents() != numComponents)) {
   868                 (cm.getNumComponents() != numComponents)) {
   905                 throw new IIOException("Incompatible color conversion");
   869                 throw new IIOException("Incompatible color conversion");
   906             }
   870             }
   907             break;
   871             break;
   908         case JPEG.JCS_YCC:
   872         case JPEG.JCS_YCC:
   909             if (JPEG.JCS.YCC == null) { // We can't do YCC at all
   873             {
   910                 throw new IIOException("Incompatible color conversion");
   874                 ColorSpace YCC = JPEG.JCS.getYCC();
   911             }
   875                 if (YCC == null) { // We can't do YCC at all
   912             if ((cs != JPEG.JCS.YCC) &&
   876                     throw new IIOException("Incompatible color conversion");
   913                 (cm.getNumComponents() == numComponents)) {
   877                 }
   914                 convert = new ColorConvertOp(JPEG.JCS.YCC, cs, null);
   878                 if ((cs != YCC) &&
       
   879                     (cm.getNumComponents() == numComponents)) {
       
   880                     convert = new ColorConvertOp(YCC, cs, null);
       
   881                 }
   915             }
   882             }
   916             break;
   883             break;
   917         case JPEG.JCS_YCCA:
   884         case JPEG.JCS_YCCA:
   918             // No conversions available; image must be YCCA
   885             {
   919             if ((JPEG.JCS.YCC == null) || // We can't do YCC at all
   886                 ColorSpace YCC = JPEG.JCS.getYCC();
   920                 (cs != JPEG.JCS.YCC) ||
   887                 // No conversions available; image must be YCCA
   921                 (cm.getNumComponents() != numComponents)) {
   888                 if ((YCC == null) || // We can't do YCC at all
   922                 throw new IIOException("Incompatible color conversion");
   889                     (cs != YCC) ||
       
   890                     (cm.getNumComponents() != numComponents)) {
       
   891                     throw new IIOException("Incompatible color conversion");
       
   892                 }
   923             }
   893             }
   924             break;
   894             break;
   925         default:
   895         default:
   926             // Anything else we can't handle at all
   896             // Anything else we can't handle at all
   927             throw new IIOException("Incompatible color conversion");
   897             throw new IIOException("Incompatible color conversion");
  1552         if (theLockCount == 0) {
  1522         if (theLockCount == 0) {
  1553             theThread = null;
  1523             theThread = null;
  1554         }
  1524         }
  1555     }
  1525     }
  1556 }
  1526 }
       
  1527 
       
  1528 /**
       
  1529  * An internal helper class that wraps producer's iterator
       
  1530  * and extracts specifier instances on demand.
       
  1531  */
       
  1532 class ImageTypeIterator implements Iterator<ImageTypeSpecifier> {
       
  1533      private Iterator<ImageTypeProducer> producers;
       
  1534      private ImageTypeSpecifier theNext = null;
       
  1535 
       
  1536      public ImageTypeIterator(Iterator<ImageTypeProducer> producers) {
       
  1537          this.producers = producers;
       
  1538      }
       
  1539 
       
  1540      public boolean hasNext() {
       
  1541          if (theNext != null) {
       
  1542              return true;
       
  1543          }
       
  1544          if (!producers.hasNext()) {
       
  1545              return false;
       
  1546          }
       
  1547          do {
       
  1548              theNext = producers.next().getType();
       
  1549          } while (theNext == null && producers.hasNext());
       
  1550 
       
  1551          return (theNext != null);
       
  1552      }
       
  1553 
       
  1554      public ImageTypeSpecifier next() {
       
  1555          if (theNext != null || hasNext()) {
       
  1556              ImageTypeSpecifier t = theNext;
       
  1557              theNext = null;
       
  1558              return t;
       
  1559          } else {
       
  1560              throw new NoSuchElementException();
       
  1561          }
       
  1562      }
       
  1563 
       
  1564      public void remove() {
       
  1565          producers.remove();
       
  1566      }
       
  1567 }
       
  1568 
       
  1569 /**
       
  1570  * An internal helper class that provides means for deferred creation
       
  1571  * of ImageTypeSpecifier instance required to describe available
       
  1572  * destination types.
       
  1573  *
       
  1574  * This implementation only supports standard
       
  1575  * jpeg color spaces (defined by corresponding JCS color space code).
       
  1576  *
       
  1577  * To support other color spaces one can override produce() method to
       
  1578  * return custom instance of ImageTypeSpecifier.
       
  1579  */
       
  1580 class ImageTypeProducer {
       
  1581 
       
  1582     private ImageTypeSpecifier type = null;
       
  1583     boolean failed = false;
       
  1584     private int csCode;
       
  1585 
       
  1586     public ImageTypeProducer(int csCode) {
       
  1587         this.csCode = csCode;
       
  1588     }
       
  1589 
       
  1590     public ImageTypeProducer() {
       
  1591         csCode = -1; // undefined
       
  1592     }
       
  1593 
       
  1594     public synchronized ImageTypeSpecifier getType() {
       
  1595         if (!failed && type == null) {
       
  1596             try {
       
  1597                 type = produce();
       
  1598             } catch (Throwable e) {
       
  1599                 failed = true;
       
  1600             }
       
  1601         }
       
  1602         return type;
       
  1603     }
       
  1604 
       
  1605     private static final ImageTypeProducer [] defaultTypes =
       
  1606             new ImageTypeProducer [JPEG.NUM_JCS_CODES];
       
  1607 
       
  1608     public synchronized static ImageTypeProducer getTypeProducer(int csCode) {
       
  1609         if (csCode < 0 || csCode >= JPEG.NUM_JCS_CODES) {
       
  1610             return null;
       
  1611         }
       
  1612         if (defaultTypes[csCode] == null) {
       
  1613             defaultTypes[csCode] = new ImageTypeProducer(csCode);
       
  1614         }
       
  1615         return defaultTypes[csCode];
       
  1616     }
       
  1617 
       
  1618     protected ImageTypeSpecifier produce() {
       
  1619         switch (csCode) {
       
  1620             case JPEG.JCS_GRAYSCALE:
       
  1621                 return ImageTypeSpecifier.createFromBufferedImageType
       
  1622                         (BufferedImage.TYPE_BYTE_GRAY);
       
  1623             case JPEG.JCS_RGB:
       
  1624                 return ImageTypeSpecifier.createInterleaved(JPEG.JCS.sRGB,
       
  1625                         JPEG.bOffsRGB,
       
  1626                         DataBuffer.TYPE_BYTE,
       
  1627                         false,
       
  1628                         false);
       
  1629             case JPEG.JCS_RGBA:
       
  1630                 return ImageTypeSpecifier.createPacked(JPEG.JCS.sRGB,
       
  1631                         0xff000000,
       
  1632                         0x00ff0000,
       
  1633                         0x0000ff00,
       
  1634                         0x000000ff,
       
  1635                         DataBuffer.TYPE_INT,
       
  1636                         false);
       
  1637             case JPEG.JCS_YCC:
       
  1638                 if (JPEG.JCS.getYCC() != null) {
       
  1639                     return ImageTypeSpecifier.createInterleaved(
       
  1640                             JPEG.JCS.getYCC(),
       
  1641                         JPEG.bandOffsets[2],
       
  1642                         DataBuffer.TYPE_BYTE,
       
  1643                         false,
       
  1644                         false);
       
  1645                 } else {
       
  1646                     return null;
       
  1647                 }
       
  1648             case JPEG.JCS_YCCA:
       
  1649                 if (JPEG.JCS.getYCC() != null) {
       
  1650                     return ImageTypeSpecifier.createInterleaved(
       
  1651                             JPEG.JCS.getYCC(),
       
  1652                         JPEG.bandOffsets[3],
       
  1653                         DataBuffer.TYPE_BYTE,
       
  1654                         true,
       
  1655                         false);
       
  1656                 } else {
       
  1657                     return null;
       
  1658                 }
       
  1659             default:
       
  1660                 return null;
       
  1661         }
       
  1662     }
       
  1663 }