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) |
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 } |