1 /* 2 * Copyright (c) 2003, 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 23 * questions. 24 */ 25 26 package com.sun.imageio.plugins.wbmp; 27 28 import java.awt.Rectangle; 29 import java.awt.image.BufferedImage; 30 import java.awt.image.DataBufferByte; 31 import java.awt.image.MultiPixelPackedSampleModel; 32 import java.awt.image.Raster; 33 import java.awt.image.WritableRaster; 34 35 import javax.imageio.IIOException; 36 import javax.imageio.ImageReader; 37 import javax.imageio.ImageReadParam; 38 import javax.imageio.ImageTypeSpecifier; 39 import javax.imageio.metadata.IIOMetadata; 40 import javax.imageio.spi.ImageReaderSpi; 41 import javax.imageio.stream.ImageInputStream; 42 43 import java.io.*; 44 import java.util.ArrayList; 45 import java.util.Iterator; 46 47 import com.sun.imageio.plugins.common.I18N; 48 import com.sun.imageio.plugins.common.ReaderUtil; 49 50 /** This class is the Java Image IO plugin reader for WBMP images. 51 * It may subsample the image, clip the image, 52 * and shift the decoded image origin if the proper decoding parameter 53 * are set in the provided <code>WBMPImageReadParam</code>. 54 */ 55 public class WBMPImageReader extends ImageReader { 56 /** The input stream where reads from */ 57 private ImageInputStream iis = null; 58 59 /** Indicates whether the header is read. */ 60 private boolean gotHeader = false; 61 62 /** The original image width. */ 63 private int width; 64 65 /** The original image height. */ 66 private int height; 67 68 private int wbmpType; 69 70 private WBMPMetadata metadata; 71 72 /** Constructs <code>WBMPImageReader</code> from the provided 73 * <code>ImageReaderSpi</code>. 74 */ 75 public WBMPImageReader(ImageReaderSpi originator) { 76 super(originator); 77 } 78 79 /** Overrides the method defined in the superclass. */ 80 public void setInput(Object input, 81 boolean seekForwardOnly, 82 boolean ignoreMetadata) { 83 super.setInput(input, seekForwardOnly, ignoreMetadata); 84 iis = (ImageInputStream) input; // Always works 85 gotHeader = false; 86 } 87 88 /** Overrides the method defined in the superclass. */ 89 public int getNumImages(boolean allowSearch) throws IOException { 90 if (iis == null) { 91 throw new IllegalStateException(I18N.getString("GetNumImages0")); 92 } 93 if (seekForwardOnly && allowSearch) { 94 throw new IllegalStateException(I18N.getString("GetNumImages1")); 95 } 96 return 1; 97 } 98 99 public int getWidth(int imageIndex) throws IOException { 100 checkIndex(imageIndex); 101 readHeader(); 102 return width; 103 } 104 105 public int getHeight(int imageIndex) throws IOException { 106 checkIndex(imageIndex); 107 readHeader(); 108 return height; 109 } 110 111 public boolean isRandomAccessEasy(int imageIndex) throws IOException { 112 checkIndex(imageIndex); 113 return true; 114 } 115 116 private void checkIndex(int imageIndex) { 117 if (imageIndex != 0) { 118 throw new IndexOutOfBoundsException(I18N.getString("WBMPImageReader0")); 119 } 120 } 121 122 public void readHeader() throws IOException { 123 if (gotHeader) 124 return; 125 126 if (iis == null) { 127 throw new IllegalStateException("Input source not set!"); 128 } 129 130 metadata = new WBMPMetadata(); 131 132 wbmpType = iis.readByte(); // TypeField 133 byte fixHeaderField = iis.readByte(); 134 135 // check for valid wbmp image 136 if (fixHeaderField != 0 137 || !isValidWbmpType(wbmpType)) 138 { 139 throw new IIOException(I18N.getString("WBMPImageReader2")); 140 } 141 142 metadata.wbmpType = wbmpType; 143 144 // Read image width 145 width = ReaderUtil.readMultiByteInteger(iis); 146 metadata.width = width; 147 148 // Read image height 149 height = ReaderUtil.readMultiByteInteger(iis); 150 metadata.height = height; 151 152 gotHeader = true; 153 } 154 155 public Iterator getImageTypes(int imageIndex) 156 throws IOException { 157 checkIndex(imageIndex); 158 readHeader(); 159 160 BufferedImage bi = 161 new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_BINARY); 162 ArrayList list = new ArrayList(1); 163 list.add(new ImageTypeSpecifier(bi)); 164 return list.iterator(); 165 } 166 167 public ImageReadParam getDefaultReadParam() { 168 return new ImageReadParam(); 169 } 170 171 public IIOMetadata getImageMetadata(int imageIndex) 172 throws IOException { 173 checkIndex(imageIndex); 174 if (metadata == null) { 175 readHeader(); 176 } 177 return metadata; 178 } 179 180 public IIOMetadata getStreamMetadata() throws IOException { 181 return null; 182 } 183 184 public BufferedImage read(int imageIndex, ImageReadParam param) 185 throws IOException { 186 187 if (iis == null) { 188 throw new IllegalStateException(I18N.getString("WBMPImageReader1")); 189 } 190 191 checkIndex(imageIndex); 192 clearAbortRequest(); 193 processImageStarted(imageIndex); 194 if (param == null) 195 param = getDefaultReadParam(); 196 197 //read header 198 readHeader(); 199 200 Rectangle sourceRegion = new Rectangle(0, 0, 0, 0); 201 Rectangle destinationRegion = new Rectangle(0, 0, 0, 0); 202 203 computeRegions(param, this.width, this.height, 204 param.getDestination(), 205 sourceRegion, 206 destinationRegion); 207 208 int scaleX = param.getSourceXSubsampling(); 209 int scaleY = param.getSourceYSubsampling(); 210 int xOffset = param.getSubsamplingXOffset(); 211 int yOffset = param.getSubsamplingYOffset(); 212 213 // If the destination is provided, then use it. Otherwise, create new one 214 BufferedImage bi = param.getDestination(); 215 216 if (bi == null) 217 bi = new BufferedImage(destinationRegion.x + destinationRegion.width, 218 destinationRegion.y + destinationRegion.height, 219 BufferedImage.TYPE_BYTE_BINARY); 220 221 boolean noTransform = 222 destinationRegion.equals(new Rectangle(0, 0, width, height)) && 223 destinationRegion.equals(new Rectangle(0, 0, bi.getWidth(), bi.getHeight())); 224 225 // Get the image data. 226 WritableRaster tile = bi.getWritableTile(0, 0); 227 228 // Get the SampleModel. 229 MultiPixelPackedSampleModel sm = 230 (MultiPixelPackedSampleModel)bi.getSampleModel(); 231 232 if (noTransform) { 233 if (abortRequested()) { 234 processReadAborted(); 235 return bi; 236 } 237 238 // If noTransform is necessary, read the data. 239 iis.read(((DataBufferByte)tile.getDataBuffer()).getData(), 240 0, height*sm.getScanlineStride()); 241 processImageUpdate(bi, 242 0, 0, 243 width, height, 1, 1, 244 new int[]{0}); 245 processImageProgress(100.0F); 246 } else { 247 int len = (this.width + 7) / 8; 248 byte[] buf = new byte[len]; 249 byte[] data = ((DataBufferByte)tile.getDataBuffer()).getData(); 250 int lineStride = sm.getScanlineStride(); 251 iis.skipBytes(len * sourceRegion.y); 252 int skipLength = len * (scaleY - 1); 253 254 // cache the values to avoid duplicated computation 255 int[] srcOff = new int[destinationRegion.width]; 256 int[] destOff = new int[destinationRegion.width]; 257 int[] srcPos = new int[destinationRegion.width]; 258 int[] destPos = new int[destinationRegion.width]; 259 260 for (int i = destinationRegion.x, x = sourceRegion.x, j = 0; 261 i < destinationRegion.x + destinationRegion.width; 262 i++, j++, x += scaleX) { 263 srcPos[j] = x >> 3; 264 srcOff[j] = 7 - (x & 7); 265 destPos[j] = i >> 3; 266 destOff[j] = 7 - (i & 7); 267 } 268 269 for (int j = 0, y = sourceRegion.y, 270 k = destinationRegion.y * lineStride; 271 j < destinationRegion.height; j++, y+=scaleY) { 272 273 if (abortRequested()) 274 break; 275 iis.read(buf, 0, len); 276 for (int i = 0; i < destinationRegion.width; i++) { 277 //get the bit and assign to the data buffer of the raster 278 int v = (buf[srcPos[i]] >> srcOff[i]) & 1; 279 data[k + destPos[i]] |= v << destOff[i]; 280 } 281 282 k += lineStride; 283 iis.skipBytes(skipLength); 284 processImageUpdate(bi, 285 0, j, 286 destinationRegion.width, 1, 1, 1, 287 new int[]{0}); 288 processImageProgress(100.0F*j/destinationRegion.height); 289 } 290 } 291 292 if (abortRequested()) 293 processReadAborted(); 294 else 295 processImageComplete(); 296 return bi; 297 } 298 299 public boolean canReadRaster() { 300 return true; 301 } 302 303 public Raster readRaster(int imageIndex, 304 ImageReadParam param) throws IOException { 305 BufferedImage bi = read(imageIndex, param); 306 return bi.getData(); 307 } 308 309 public void reset() { 310 super.reset(); 311 iis = null; 312 gotHeader = false; 313 } 314 315 /* 316 * This method verifies that given byte is valid wbmp type marker. 317 * At the moment only 0x0 marker is described by wbmp spec. 318 */ 319 boolean isValidWbmpType(int type) { 320 return type == 0; 321 } 322 }