📄 jpegimagereader.java
字号:
return numImages; } if (iis == null) { throw new IllegalStateException("Input not set"); } if (allowSearch == true) { if (seekForwardOnly) { throw new IllegalStateException( "seekForwardOnly and allowSearch can't both be true!"); } // Otherwise we have to read the entire stream if (!tablesOnlyChecked) { checkTablesOnly(); } iis.mark(); gotoImage(0); JPEGBuffer buffer = new JPEGBuffer(iis); buffer.loadBuf(0); boolean done = false; while (!done) { done = buffer.scanForFF(this); switch (buffer.buf[buffer.bufPtr] & 0xff) { case JPEG.SOI: numImages++; // FALL THROUGH to decrement buffer vars // This first set doesn't have a length case 0: // not a marker, just a data 0xff case JPEG.RST0: case JPEG.RST1: case JPEG.RST2: case JPEG.RST3: case JPEG.RST4: case JPEG.RST5: case JPEG.RST6: case JPEG.RST7: case JPEG.EOI: buffer.bufAvail--; buffer.bufPtr++; break; // All the others have a length default: buffer.bufAvail--; buffer.bufPtr++; buffer.loadBuf(2); int length = ((buffer.buf[buffer.bufPtr++] & 0xff) << 8) | (buffer.buf[buffer.bufPtr++] & 0xff); buffer.bufAvail -= 2; length -= 2; // length includes itself buffer.skipData(length); } } iis.reset(); return numImages; } return -1; // Search is necessary for JPEG } /** * Sets the input stream to the start of the requested image. * <pre> * @exception IllegalStateException if the input source has not been * set. * @exception IndexOutOfBoundsException if the supplied index is * out of bounds. * </pre> */ private void gotoImage(int imageIndex) throws IOException { if (iis == null) { throw new IllegalStateException("Input not set"); } if (imageIndex < minIndex) { throw new IndexOutOfBoundsException(); } if (!tablesOnlyChecked) { checkTablesOnly(); } if (imageIndex < imagePositions.size()) { iis.seek(((Long)(imagePositions.get(imageIndex))).longValue()); } else { // read to start of image, saving positions // First seek to the last position we already have, and skip the // entire image Long pos = (Long) imagePositions.get(imagePositions.size()-1); iis.seek(pos.longValue()); skipImage(); // Now add all intervening positions, skipping images for (int index = imagePositions.size(); index <= imageIndex; index++) { // Is there an image? if (!hasNextImage()) { throw new IndexOutOfBoundsException(); } pos = new Long(iis.getStreamPosition()); imagePositions.add(pos); if (seekForwardOnly) { iis.flushBefore(pos.longValue()); } if (index < imageIndex) { skipImage(); } // Otherwise we are where we want to be } } if (seekForwardOnly) { minIndex = imageIndex; } haveSeeked = true; // No way is native buffer still valid } /** * Skip over a complete image in the stream, leaving the stream * positioned such that the next byte to be read is the first * byte of the next image. For JPEG, this means that we read * until we encounter an EOI marker or until the end of the stream. * If the stream ends before an EOI marker is encountered, an * IndexOutOfBoundsException is thrown. */ private void skipImage() throws IOException { if (debug) { System.out.println("skipImage called"); } boolean foundFF = false; for (int byteval = iis.read(); byteval != -1; byteval = iis.read()) { if (foundFF == true) { if (byteval == JPEG.EOI) { return; } } foundFF = (byteval == 0xff) ? true : false; } throw new IndexOutOfBoundsException(); } /** * Returns <code>true</code> if there is an image beyond * the current stream position. Does not disturb the * stream position. */ private boolean hasNextImage() throws IOException { if (debug) { System.out.print("hasNextImage called; returning "); } iis.mark(); boolean foundFF = false; for (int byteval = iis.read(); byteval != -1; byteval = iis.read()) { if (foundFF == true) { if (byteval == JPEG.SOI) { iis.reset(); if (debug) { System.out.println("true"); } return true; } } foundFF = (byteval == 0xff) ? true : false; } // We hit the end of the stream before we hit an SOI, so no image iis.reset(); if (debug) { System.out.println("false"); } return false; } /** * Push back the given number of bytes to the input stream. * Called by the native code at the end of each image so * that the next one can be identified from Java. */ private void pushBack(int num) throws IOException { if (debug) { System.out.println("pushing back " + num + " bytes"); } iis.seek(iis.getStreamPosition()-num); // The buffer is clear after this, so no need to set haveSeeked. } /** * Reads header information for the given image, if possible. */ private void readHeader(int imageIndex, boolean reset) throws IOException { gotoImage(imageIndex); readNativeHeader(reset); // Ignore return currentImage = imageIndex; } private boolean readNativeHeader(boolean reset) throws IOException { boolean retval = false; retval = readImageHeader(structPointer, haveSeeked, reset); haveSeeked = false; return retval; } /** * Read in the header information starting from the current * stream position, returning <code>true</code> if the * header was a tables-only image. After this call, the * native IJG decompression struct will contain the image * information required by most query calls below * (e.g. getWidth, getHeight, etc.), if the header was not * a tables-only image. * If reset is <code>true</code>, the state of the IJG * object is reset so that it can read a header again. * This happens automatically if the header was a tables-only * image. */ private native boolean readImageHeader(long structPointer, boolean clearBuffer, boolean reset) throws IOException; /* * Called by the native code whenever an image header has been * read. Whether we read metadata or not, we always need this * information, so it is passed back independently of * metadata, which may never be read. */ private void setImageData(int width, int height, int colorSpaceCode, int outColorSpaceCode, int numComponents, byte [] iccData) { this.width = width; this.height = height; this.colorSpaceCode = colorSpaceCode; this.outColorSpaceCode = outColorSpaceCode; this.numComponents = numComponents; if (iccData == null) { iccCS = null; return; } ICC_Profile newProfile = null; try { newProfile = ICC_Profile.getInstance(iccData); } catch (IllegalArgumentException e) { /* * Color profile data seems to be invalid. * Ignore this profile. */ iccCS = null; warningOccurred(WARNING_IGNORE_INVALID_ICC); return; } byte[] newData = newProfile.getData(); ICC_Profile oldProfile = null; if (iccCS instanceof ICC_ColorSpace) { oldProfile = ((ICC_ColorSpace)iccCS).getProfile(); } byte[] oldData = null; if (oldProfile != null) { oldData = oldProfile.getData(); } /* * At the moment we can't rely on the ColorSpace.equals() * and ICC_Profile.equals() because they do not detect * the case when two profiles are created from same data. * * So, we have to do data comparison in order to avoid * creation of different ColorSpace instances for the same * embedded data. */ if (oldData == null || !java.util.Arrays.equals(oldData, newData)) { iccCS = new ICC_ColorSpace(newProfile); } } public int getWidth(int imageIndex) throws IOException { if (currentImage != imageIndex) { readHeader(imageIndex, true); } return width; } public int getHeight(int imageIndex) throws IOException { if (currentImage != imageIndex) { readHeader(imageIndex, true); } return height; } /////////// Color Conversion and Image Types /** * Return an ImageTypeSpecifier corresponding to the given * color space code, or null if the color space is unsupported. */ private ImageTypeSpecifier getImageType(int code) { ImageTypeSpecifier ret = null; if ((code > 0) && (code < JPEG.NUM_JCS_CODES)) { ret = defaultTypes[code]; } return ret; } public ImageTypeSpecifier getRawImageType(int imageIndex) throws IOException { if (currentImage != imageIndex) { readHeader(imageIndex, true); } // Returns null if it can't be represented return getImageType(colorSpaceCode); } public Iterator getImageTypes(int imageIndex) throws IOException { if (currentImage != imageIndex) { readHeader(imageIndex, true); } // We return an iterator containing the default, any // conversions that the library provides, and // all the other default types with the same number // of components, as we can do these as a post-process. // As we convert Rasters rather than images, images // with alpha cannot be converted in a post-process. // If this image can't be interpreted, this method // returns an empty Iterator. // Get the raw ITS, if there is one. Note that this // won't always be the same as the default. ImageTypeSpecifier raw = getImageType(colorSpaceCode); // Given the encoded colorspace, build a list of ITS's // representing outputs you could handle starting // with the default.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -