📄 jfifmarkersegment.java
字号:
// Remove the jfif segment, which should be there. MarkerSegment jfif = metadata.findMarkerSegment (JFIFMarkerSegment.class, true); if (jfif == null) { throw new IllegalThumbException(); } metadata.markerSequence.remove(jfif); /* Use this if removing leaves a hole and causes trouble // Get the tree String format = metadata.getNativeMetadataFormatName(); IIOMetadataNode tree = (IIOMetadataNode) metadata.getAsTree(format); // If there is no app0jfif node, the image is bad NodeList jfifs = tree.getElementsByTagName("app0JFIF"); if (jfifs.getLength() == 0) { throw new IllegalThumbException(); } // remove the app0jfif node Node jfif = jfifs.item(0); Node parent = jfif.getParentNode(); parent.removeChild(jfif); metadata.setFromTree(format, tree); */ thumbWriter.write(new IIOImage(thumb, null, metadata)); thumbWriter.dispose(); // Now check that the size is OK if (baos.size() > MAZ_BUFSIZE) { throw new IllegalThumbException(); } data = baos.toByteArray(); } catch (IOException e) { throw new IllegalThumbException(); } } int getWidth() { int retval = 0; SOFMarkerSegment sof = (SOFMarkerSegment) thumbMetadata.findMarkerSegment (SOFMarkerSegment.class, true); if (sof != null) { retval = sof.samplesPerLine; } return retval; } int getHeight() { int retval = 0; SOFMarkerSegment sof = (SOFMarkerSegment) thumbMetadata.findMarkerSegment (SOFMarkerSegment.class, true); if (sof != null) { retval = sof.numLines; } return retval; } private class ThumbnailReadListener implements IIOReadProgressListener { JPEGImageReader reader = null; ThumbnailReadListener (JPEGImageReader reader) { this.reader = reader; } public void sequenceStarted(ImageReader source, int minIndex) {} public void sequenceComplete(ImageReader source) {} public void imageStarted(ImageReader source, int imageIndex) {} public void imageProgress(ImageReader source, float percentageDone) { reader.thumbnailProgress(percentageDone); } public void imageComplete(ImageReader source) {} public void thumbnailStarted(ImageReader source, int imageIndex, int thumbnailIndex) {} public void thumbnailProgress(ImageReader source, float percentageDone) {} public void thumbnailComplete(ImageReader source) {} public void readAborted(ImageReader source) {} } BufferedImage getThumbnail(ImageInputStream iis, JPEGImageReader reader) throws IOException { iis.mark(); iis.seek(streamPos); JPEGImageReader thumbReader = new JPEGImageReader(null); thumbReader.setInput(iis); thumbReader.addIIOReadProgressListener (new ThumbnailReadListener(reader)); BufferedImage ret = thumbReader.read(0, null); thumbReader.dispose(); iis.reset(); return ret; } protected Object clone() { JFIFThumbJPEG newGuy = (JFIFThumbJPEG) super.clone(); if (thumbMetadata != null) { newGuy.thumbMetadata = (JPEGMetadata) thumbMetadata.clone(); } return newGuy; } IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("JFIFthumbJPEG"); if (thumbMetadata != null) { node.appendChild(thumbMetadata.getNativeTree()); } return node; } int getLength() { if (data == null) { return 0; } else { return data.length; } } void write(ImageOutputStream ios, JPEGImageWriter writer) throws IOException { int progInterval = data.length / 20; // approx. every 5% if (progInterval == 0) { progInterval = 1; } for (int offset = 0; offset < data.length;) { int len = Math.min(progInterval, data.length-offset); ios.write(data, offset, len); offset += progInterval; float percentDone = ((float) offset * 100) / data.length; if (percentDone > 100.0F) { percentDone = 100.0F; } writer.thumbnailProgress (percentDone); } } void print () { System.out.println("JFIF thumbnail stored as JPEG"); } } /** * Write out the given profile to the stream, embedded in * the necessary number of APP2 segments, per the ICC spec. * This is the only mechanism for writing an ICC profile * to a stream. */ static void writeICC(ICC_Profile profile, ImageOutputStream ios) throws IOException { int LENGTH_LENGTH = 2; final String ID = "ICC_PROFILE"; int ID_LENGTH = ID.length()+1; // spec says it's null-terminated int COUNTS_LENGTH = 2; int MAX_ICC_CHUNK_SIZE = 65535 - LENGTH_LENGTH - ID_LENGTH - COUNTS_LENGTH; byte [] data = profile.getData(); int numChunks = data.length / MAX_ICC_CHUNK_SIZE; if ((data.length % MAX_ICC_CHUNK_SIZE) != 0) { numChunks++; } int chunkNum = 1; int offset = 0; for (int i = 0; i < numChunks; i++) { int dataLength = Math.min(data.length-offset, MAX_ICC_CHUNK_SIZE); int segLength = dataLength+COUNTS_LENGTH+ID_LENGTH+LENGTH_LENGTH; ios.write(0xff); ios.write(JPEG.APP2); MarkerSegment.write2bytes(ios, segLength); byte [] id = ID.getBytes("US-ASCII"); ios.write(id); ios.write(0); // Null-terminate the string ios.write(chunkNum++); ios.write(numChunks); ios.write(data, offset, dataLength); offset += dataLength; } } /** * An APP2 marker segment containing an ICC profile. In the stream * a profile larger than 64K is broken up into a series of chunks. * This inner class represents the complete profile as a single objec, * combining chunks as necessary. */ class ICCMarkerSegment extends MarkerSegment { ArrayList chunks = null; byte [] profile = null; // The complete profile when it's fully read // May remain null when writing private static final int ID_SIZE = 12; int chunksRead; int numChunks; ICCMarkerSegment(ICC_ColorSpace cs) { super(JPEG.APP2); chunks = null; chunksRead = 0; numChunks = 0; profile = cs.getProfile().getData(); } ICCMarkerSegment(JPEGBuffer buffer) throws IOException { super(buffer); // gets whole segment or fills the buffer if (debug) { System.out.println("Creating new ICC segment"); } buffer.bufPtr += ID_SIZE; // Skip the id buffer.bufAvail -= ID_SIZE; /* * Reduce the stored length by the id size. The stored * length is used to store the length of the profile * data only. */ length -= ID_SIZE; // get the chunk number int chunkNum = buffer.buf[buffer.bufPtr] & 0xff; // get the total number of chunks numChunks = buffer.buf[buffer.bufPtr+1] & 0xff; if (chunkNum > numChunks) { throw new IIOException ("Image format Error; chunk num > num chunks"); } // if there are no more chunks, set up the data if (numChunks == 1) { // reduce the stored length by the two chunk numbering bytes length -= 2; profile = new byte[length]; buffer.bufPtr += 2; buffer.bufAvail-=2; buffer.readData(profile); inICC = false; } else { // If we store them away, include the chunk numbering bytes byte [] profileData = new byte[length]; // Now reduce the stored length by the // two chunk numbering bytes length -= 2; buffer.readData(profileData); chunks = new ArrayList(); chunks.add(profileData); chunksRead = 1; inICC = true; } } ICCMarkerSegment(Node node) throws IIOInvalidTreeException { super(JPEG.APP2); if (node instanceof IIOMetadataNode) { IIOMetadataNode ourNode = (IIOMetadataNode) node; ICC_Profile prof = (ICC_Profile) ourNode.getUserObject(); if (prof != null) { // May be null profile = prof.getData(); } } } protected Object clone () { ICCMarkerSegment newGuy = (ICCMarkerSegment) super.clone(); if (profile != null) { newGuy.profile = (byte[]) profile.clone(); } return newGuy; } boolean addData(JPEGBuffer buffer) throws IOException { if (debug) { System.out.println("Adding to ICC segment"); } // skip the tag buffer.bufPtr++; buffer.bufAvail--; // Get the length, but not in length int dataLen = (buffer.buf[buffer.bufPtr++] & 0xff) << 8; dataLen |= buffer.buf[buffer.bufPtr++] & 0xff; buffer.bufAvail -= 2; // Don't include length itself dataLen -= 2; // skip the id buffer.bufPtr += ID_SIZE; // Skip the id buffer.bufAvail -= ID_SIZE; /* * Reduce the stored length by the id size. The stored * length is used to store the length of the profile * data only. */ dataLen -= ID_SIZE; // get the chunk number int chunkNum = buffer.buf[buffer.bufPtr] & 0xff; if (chunkNum > numChunks) { throw new IIOException ("Image format Error; chunk num > num chunks"); } // get the number of chunks, which should match int newNumChunks = buffer.buf[buffer.bufPtr+1] & 0xff; if (numChunks != newNumChunks) { throw new IIOException ("Image format Error; icc num chunks mismatch"); } dataLen -= 2; if (debug) { System.out.println("chunkNum: " + chunkNum + ", numChunks: " + numChunks + ", dataLen: " + dataLen); } boolean retval = false; byte [] profileData = new byte[dataLen]; buffer.readData(profileData); chunks.add(profileData); length += dataLen; chunksRead++; if (chunksRead < numChunks) { inICC = true; } else { if (debug) { System.out.println("Completing profile; total length is " + length); } // create an array for the whole thing profile = new byte[length]; // copy the existing chunks, releasing them // Note that they may be out of order int index = 0; for (int i = 1; i <= numChunks; i++) { boolean foundIt = false; for (int chunk = 0; chunk < chunks.size(); chunk++) { byte [] chunkData = (byte []) chunks.get(chunk); if (chunkData[0] == i) { // Right one System.arraycopy(chunkData, 2, profile, index, chunkData.length-2); index += chunkData.length-2; foundIt = true; } } if (foundIt == false) { throw new IIOException ("Image Format Error: Missing ICC chunk num " + i); } } chunks = null; chunksRead = 0; numChunks = 0; inICC = false; retval = true; } return retval; } IIOMetadataNode getNativeNode() { IIOMetadataNode node = new IIOMetadataNode("app2ICC"); if (profile != null) { node.setUserObject(ICC_Profile.getInstance(profile)); } return node; } /** * No-op. Profiles are never written from metadata. * They are written from the ColorSpace of the image. */ void write(ImageOutputStream ios) throws IOException { // No-op } void print () { printTag("ICC Profile APP2"); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -