0001: /*
0002: * $RCSfile: RenderedImageSrc.java,v $
0003: *
0004: *
0005: * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
0006: *
0007: * Redistribution and use in source and binary forms, with or without
0008: * modification, are permitted provided that the following conditions
0009: * are met:
0010: *
0011: * - Redistribution of source code must retain the above copyright
0012: * notice, this list of conditions and the following disclaimer.
0013: *
0014: * - Redistribution in binary form must reproduce the above copyright
0015: * notice, this list of conditions and the following disclaimer in
0016: * the documentation and/or other materials provided with the
0017: * distribution.
0018: *
0019: * Neither the name of Sun Microsystems, Inc. or the names of
0020: * contributors may be used to endorse or promote products derived
0021: * from this software without specific prior written permission.
0022: *
0023: * This software is provided "AS IS," without a warranty of any
0024: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
0025: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
0026: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
0027: * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
0028: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
0029: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
0030: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
0031: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
0032: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
0033: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
0034: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
0035: * POSSIBILITY OF SUCH DAMAGES.
0036: *
0037: * You acknowledge that this software is not designed or intended for
0038: * use in the design, construction, operation or maintenance of any
0039: * nuclear facility.
0040: *
0041: * $Revision: 1.2 $
0042: * $Date: 2006/09/22 23:07:25 $
0043: * $State: Exp $
0044: */
0045: package com.sun.media.imageioimpl.plugins.jpeg2000;
0046:
0047: import java.awt.Point;
0048: import java.awt.Rectangle;
0049: import java.awt.RenderingHints;
0050: import java.awt.image.ColorModel;
0051: import java.awt.image.ComponentSampleModel;
0052: import java.awt.image.DataBuffer;
0053: import java.awt.image.DataBufferByte;
0054: import java.awt.image.RenderedImage;
0055: import java.awt.image.Raster;
0056: import java.awt.image.MultiPixelPackedSampleModel;
0057: import java.awt.image.SampleModel;
0058: import java.awt.image.WritableRaster;
0059: import java.awt.image.renderable.ParameterBlock;
0060:
0061: import jj2000.j2k.image.*;
0062: import jj2000.j2k.*;
0063: import java.io.*;
0064:
0065: import com.sun.media.imageioimpl.common.ImageUtil;
0066:
0067: public class RenderedImageSrc implements BlkImgDataSrc {
0068: /** The width of the image */
0069: private int w;
0070:
0071: /** The height of the image */
0072: private int h;
0073:
0074: /** The tile width for encoding */
0075: int tileWidth;
0076:
0077: /** The tile height for encoding */
0078: int tileHeight;
0079:
0080: /** The tile grid offset for encoding */
0081: int tileXOffset, tileYOffset;
0082:
0083: /** The source -> destination transformation */
0084: int scaleX, scaleY, xOffset, yOffset;
0085:
0086: /** The source bands to be encoded. */
0087: int[] sourceBands = null;
0088:
0089: /** The destination upper-left corner */
0090: int minX, minY;
0091:
0092: /** The number of components in the image */
0093: private int nc;
0094:
0095: /** The number of bits that determine the nominal dynamic range */
0096: // XXX: Should be an int[] of length 'nc'.
0097: private int rb;
0098:
0099: /** Buffer for the 3 components of each pixel(in the current block) */
0100: private int[][] barr = null;
0101:
0102: /** Data block used only to store coordinates of the buffered blocks */
0103: private DataBlkInt dbi = new DataBlkInt();
0104:
0105: /** The line buffer. */
0106: private byte buf[];
0107:
0108: /** Temporary DataBlkInt object (needed when encoder uses floating-point
0109: filters). This avoid allocating new DataBlk at each time */
0110: private DataBlkInt intBlk;
0111:
0112: private RenderedImage src;
0113: private J2KImageWriteParamJava param;
0114:
0115: /** The input source raster. */
0116: private Raster raster;
0117:
0118: /** The raster for a destination tile */
0119: private Raster aTile;
0120:
0121: private Point co = new Point();
0122:
0123: private int dcOffset = 0;
0124:
0125: private boolean isBinary = false;
0126:
0127: private Rectangle destinationRegion;
0128: private Rectangle sourceRegion;
0129:
0130: private ColorModel cm;
0131: private SampleModel sm;
0132:
0133: private boolean noTransform = true;
0134: private boolean noSubband = true;
0135:
0136: /** Used to process abortion. */
0137: private J2KImageWriter writer;
0138:
0139: /** Indicates a <code>raster</code> rather than a <code>RenderedImage</code>
0140: * to be encoded.
0141: */
0142: private boolean inputIsRaster = false;
0143:
0144: /**
0145: * Creates <code>RenderedImageSrc</code> for encoding a <code>Raster</code>.
0146: *
0147: * @param raster The <code>Raster</code> to be encoded.
0148: * @param param The <code>J2KImageWriteParamJava</code> used in encoding.
0149: * @param writer The <code>J2KImageWriter</code> performs the encoding.
0150: *
0151: * @param IOException If an error occurs while opening the file.
0152: */
0153: public RenderedImageSrc(Raster raster,
0154: J2KImageWriteParamJava param, J2KImageWriter writer) {
0155: this .raster = raster;
0156: this .param = param;
0157: this .writer = writer;
0158: this .inputIsRaster = true;
0159:
0160: sourceRegion = param.getSourceRegion();
0161:
0162: if (sourceRegion == null)
0163: sourceRegion = new Rectangle(raster.getMinX(), raster
0164: .getMinY(), raster.getWidth(), raster.getHeight());
0165: else
0166: sourceRegion = sourceRegion
0167: .intersection(raster.getBounds());
0168:
0169: if (sourceRegion.isEmpty())
0170: throw new RuntimeException(I18N
0171: .getString("J2KImageWriterCodecLib0"));
0172:
0173: sm = raster.getSampleModel();
0174: getFromParam();
0175: setSampleModelAndMore();
0176: setTile(0, 0);
0177: }
0178:
0179: /**
0180: * Creates <code>RenderedImageSrc</code> for encoding a
0181: * <code>RenderedImage</code>.
0182: *
0183: * @param src The <code>RenderedImage</code> to be encoded.
0184: * @param param The <code>J2KImageWriteParamJava</code> used in encoding.
0185: * @param writer The <code>J2KImageWriter</code> performs the encoding.
0186: *
0187: * @param IOException If an error occurs while opening the file.
0188: * */
0189: public RenderedImageSrc(RenderedImage src,
0190: J2KImageWriteParamJava param, J2KImageWriter writer) {
0191: this .src = src;
0192: this .param = param;
0193: this .writer = writer;
0194:
0195: sourceRegion = param.getSourceRegion();
0196:
0197: if (sourceRegion == null)
0198: sourceRegion = new Rectangle(src.getMinX(), src.getMinY(),
0199: src.getWidth(), src.getHeight());
0200: else
0201: sourceRegion = sourceRegion.intersection(new Rectangle(src
0202: .getMinX(), src.getMinY(), src.getWidth(), src
0203: .getHeight()));
0204: if (sourceRegion.isEmpty())
0205: throw new RuntimeException(I18N
0206: .getString("J2KImageWriterCodecLib0"));
0207:
0208: sm = src.getSampleModel();
0209: cm = src.getColorModel();
0210: getFromParam();
0211: setSampleModelAndMore();
0212: }
0213:
0214: private void getFromParam() {
0215: try {
0216: tileWidth = param.getTileWidth();
0217: tileHeight = param.getTileHeight();
0218: tileXOffset = param.getTileGridXOffset();
0219: tileYOffset = param.getTileGridYOffset();
0220: } catch (IllegalStateException e) {
0221: param.setTilingMode(param.MODE_EXPLICIT);
0222: if (inputIsRaster) {
0223: param.setTiling(raster.getWidth(), raster.getHeight(),
0224: raster.getMinX(), raster.getMinY());
0225: } else {
0226: param.setTiling(src.getWidth(), src.getHeight(), src
0227: .getMinX(), src.getMinY());
0228: }
0229: tileWidth = param.getTileWidth();
0230: tileHeight = param.getTileHeight();
0231: tileXOffset = param.getTileGridXOffset();
0232: tileYOffset = param.getTileGridYOffset();
0233: }
0234:
0235: scaleX = param.getSourceXSubsampling();
0236: scaleY = param.getSourceYSubsampling();
0237: xOffset = param.getSubsamplingXOffset();
0238: yOffset = param.getSubsamplingYOffset();
0239:
0240: sourceRegion.translate(xOffset, yOffset);
0241: sourceRegion.width -= xOffset;
0242: sourceRegion.height -= yOffset;
0243:
0244: xOffset = sourceRegion.x % scaleX;
0245: yOffset = sourceRegion.y % scaleY;
0246:
0247: minX = sourceRegion.x / scaleX;
0248: minY = sourceRegion.y / scaleY;
0249:
0250: w = (sourceRegion.width + scaleX - 1) / scaleX;
0251: h = (sourceRegion.height + scaleY - 1) / scaleY;
0252:
0253: tileXOffset += (minX - tileXOffset) / tileWidth * tileWidth;
0254: tileYOffset += (minY - tileYOffset) / tileHeight * tileHeight;
0255:
0256: destinationRegion = new Rectangle(minX, minY, w, h);
0257:
0258: if (!destinationRegion.equals(sourceRegion)
0259: || tileWidth != sm.getWidth()
0260: || tileHeight != sm.getHeight()
0261: || (!inputIsRaster && (tileXOffset != src
0262: .getTileGridXOffset() || tileYOffset != src
0263: .getTileGridYOffset()))
0264: || (inputIsRaster && (tileXOffset != raster.getMinX() || tileYOffset != raster
0265: .getMinY())))
0266: noTransform = false;
0267:
0268: }
0269:
0270: private void setSampleModelAndMore() {
0271: nc = sm.getNumBands();
0272: sourceBands = param.getSourceBands();
0273: if (sourceBands != null) {
0274: sm = sm.createSubsetSampleModel(sourceBands);
0275: noSubband = false;
0276: } else {
0277: sourceBands = new int[nc];
0278: for (int i = 0; i < nc; i++)
0279: sourceBands[i] = i;
0280: }
0281:
0282: sm = sm.createCompatibleSampleModel(tileWidth, tileHeight);
0283: nc = sm.getNumBands();
0284: isBinary = ImageUtil.isBinary(sm);
0285:
0286: if (cm != null) {
0287: // XXX: rb should be set to getComponentSize();
0288: rb = cm.getComponentSize(0);
0289: for (int i = 1; i < cm.getNumComponents(); i++)
0290: if (rb < cm.getComponentSize(i))
0291: rb = cm.getComponentSize(i);
0292: } else {
0293: // XXX: rb should be set to getSampleSize();
0294: rb = sm.getSampleSize(0);
0295: for (int i = 1; i < sm.getNumBands(); i++)
0296: if (rb < sm.getSampleSize(i))
0297: rb = sm.getSampleSize(i);
0298: }
0299:
0300: if (!isOrigSigned(0) && rb > 1)
0301: // XXX: if rb is an int[] this will have to change.
0302: dcOffset = 1 << rb - 1;
0303: }
0304:
0305: public int getTilePartULX() {
0306: return tileXOffset;
0307: }
0308:
0309: public int getTilePartULY() {
0310: return tileYOffset;
0311: }
0312:
0313: /**
0314: * Returns the width of the current tile in pixels.
0315: *
0316: * @return The total image width in pixels.
0317: * */
0318: public int getTileWidth() {
0319: int width = tileWidth;
0320: int maxX = getImgULX() + getImgWidth();
0321: int x = co.x * tileWidth + tileXOffset;
0322: if (x + tileWidth >= maxX)
0323: width = maxX - x;
0324: return width;
0325: }
0326:
0327: /**
0328: * Returns the overall height of the current tile in pixels.
0329: *
0330: * @return The total image height in pixels. */
0331: public int getTileHeight() {
0332: int height = tileHeight;
0333: int maxY = getImgULY() + getImgHeight();
0334: int y = co.y * tileHeight + tileYOffset;
0335: if (y + tileHeight >= maxY)
0336: height = maxY - y;
0337:
0338: return height;
0339: }
0340:
0341: public int getNomTileWidth() {
0342: return tileWidth;
0343: }
0344:
0345: public int getNomTileHeight() {
0346: return tileHeight;
0347: }
0348:
0349: /**
0350: * Returns the overall width of the image in pixels. This is the image's
0351: * width without accounting for any component subsampling or tiling. The
0352: * value of <tt>w</tt> is returned.
0353: *
0354: * @return The total image's width in pixels.
0355: * */
0356: public int getImgWidth() {
0357: return w;
0358: }
0359:
0360: /**
0361: * Returns the overall height of the image in pixels. This is the image's
0362: * height without accounting for any component subsampling or tiling. The
0363: * value of <tt>h</tt> is returned.
0364: *
0365: * @return The total image's height in pixels.
0366: * */
0367: public int getImgHeight() {
0368: return h;
0369: }
0370:
0371: /**
0372: * Returns the number of components in the image. The value of <tt>nc</tt>
0373: * is returned.
0374: *
0375: * @return The number of components in the image.
0376: * */
0377: public int getNumComps() {
0378: return nc;
0379: }
0380:
0381: public int getTileGridXOffset() {
0382: return param.getTileGridXOffset();
0383: }
0384:
0385: public int getTileGridYOffset() {
0386: return param.getTileGridYOffset();
0387: }
0388:
0389: public int getTileCompHeight(int t, int c) {
0390: return tileHeight;
0391: }
0392:
0393: public int getTileCompWidth(int t, int c) {
0394: return tileWidth;
0395: }
0396:
0397: /**
0398: * Returns the component subsampling factor in the horizontal direction,
0399: * for the specified component. This is, approximately, the ratio of
0400: * dimensions between the reference grid and the component itself, see the
0401: * 'ImgData' interface desription for details.
0402: *
0403: * @param c The index of the component (between 0 and C-1)
0404: *
0405: * @return The horizontal subsampling factor of component 'c'
0406: *
0407: * @see ImgData
0408: * */
0409: public int getCompSubsX(int c) {
0410: return 1;
0411: }
0412:
0413: /**
0414: * Returns the component subsampling factor in the vertical direction, for
0415: * the specified component. This is, approximately, the ratio of
0416: * dimensions between the reference grid and the component itself, see the
0417: * 'ImgData' interface desription for details.
0418: *
0419: * @param c The index of the component (between 0 and C-1)
0420: *
0421: * @return The vertical subsampling factor of component 'c'
0422: *
0423: * @see ImgData
0424: * */
0425: public int getCompSubsY(int c) {
0426: return 1;
0427: }
0428:
0429: /**
0430: * Returns the width in pixels of the specified component in the current
0431: * tile. This default implementation assumes no tiling and no component
0432: * subsampling (i.e., all components, or components, have the same
0433: * dimensions in pixels).
0434: *
0435: * @param c The index of the component, from 0 to C-1.
0436: *
0437: * @return The width in pixels of component <tt>n</tt> in the current
0438: * tile.
0439: * */
0440: public int getCompWidth(int n) {
0441: return w;
0442: }
0443:
0444: /**
0445: * Returns the height in pixels of the specified component in the current
0446: * tile. This default implementation assumes no tiling and no component
0447: * subsampling (i.e., all components, or components, have the same
0448: * dimensions in pixels).
0449: *
0450: * @param c The index of the component, from 0 to C-1.
0451: *
0452: * @return The height in pixels of component <tt>c</tt> in the current
0453: * tile.
0454: * */
0455: public int getCompHeight(int c) {
0456: return h;
0457: }
0458:
0459: /**
0460: * Returns the width in pixels of the specified component in the overall
0461: * image. This default implementation assumes no component, or component,
0462: * subsampling (i.e. all components have the same dimensions in pixels).
0463: *
0464: * @param c The index of the component, from 0 to C-1.
0465: *
0466: * @return The width in pixels of component <tt>c</tt> in the overall
0467: * image.
0468: * */
0469: public int getCompImgWidth(int c) {
0470: return w;
0471: }
0472:
0473: /**
0474: * Returns the height in pixels of the specified component in the overall
0475: * image. This default implementation assumes no component, or component,
0476: * subsampling (i.e. all components have the same dimensions in pixels).
0477: *
0478: * @param c The index of the component, from 0 to C-1.
0479: *
0480: * @return The height in pixels of component <tt>c</tt> in the overall
0481: * image.
0482: * */
0483: public int getCompImgHeight(int c) {
0484: return h;
0485: }
0486:
0487: /**
0488: * Changes the current tile, given the new coordinates.
0489: *
0490: * @param x The horizontal coordinate of the tile.
0491: *
0492: * @param y The vertical coordinate of the new tile.
0493: * */
0494: public void setTile(int x, int y) {
0495: if (x >= getNumXTiles()) {
0496: y += x / getNumXTiles();
0497: x = x % getNumXTiles();
0498: }
0499: co.x = x;
0500: co.y = y;
0501: aTile = null;
0502: }
0503:
0504: /**
0505: * Advances to the next tile, in standard scan-line order (by rows then
0506: * columns).
0507: * */
0508: public void nextTile() {
0509: co.x++;
0510: if (co.x >= getNumXTiles()) {
0511: co.x = 0;
0512: co.y++;
0513: }
0514: setTile(co.x, co.y);
0515: }
0516:
0517: /**
0518: * Returns the coordinates of the current tile. This default
0519: * implementation assumes no-tiling, so (0,0) is returned.
0520: *
0521: * @param co If not null this object is used to return the information. If
0522: * null a new one is created and returned.
0523: *
0524: * @return The current tile's coordinates.
0525: * */
0526: public Point getTile(Point co) {
0527: if (co != null)
0528: return co;
0529: else
0530: return new Point(0, 0);
0531: }
0532:
0533: /**
0534: * Returns the index of the current tile, relative to a standard scan-line
0535: * order.
0536: *
0537: * @return The current tile's index (starts at 0).
0538: * */
0539: public int getTileIdx() {
0540: return getNumXTiles() * co.y + co.x;
0541: }
0542:
0543: /**
0544: * Returns the horizontal and vertical offset of the upper-left corner of
0545: * the current tile, in the specified component, relative to the canvas
0546: * origin, in the component coordinates (not in the reference grid
0547: * coordinates). These are the coordinates of the current tile's (not
0548: * active tile) upper-left corner relative to the canvas.
0549: *
0550: * @param co If not null the object is used to return the values, if null
0551: * a new one is created and returned.
0552: *
0553: * @param c The index of the component (between 0 and C-1)
0554: *
0555: * @return The horizontal and vertical offsets of the upper-left corner of
0556: * the current tile, for the specified component, relative to the canvas
0557: * origin, in the component coordinates.
0558: * */
0559: public Point getTileOff(Point p, int c) {
0560: if (p != null) {
0561: p.x = co.x * tileWidth + tileXOffset;
0562: p.y = co.y * tileHeight + tileYOffset;
0563: return co;
0564: } else
0565: return new Point(co.x * tileWidth + tileXOffset, co.y
0566: * tileHeight + tileYOffset);
0567: }
0568:
0569: /**
0570: * Returns the horizontal coordinate of the upper-left corner of the
0571: * active tile, with respect to the canvas origin, in the component
0572: * coordinates, for the specified component.
0573: *
0574: * @param c The index of the component (between 0 and C-1)
0575: *
0576: * @return The horizontal coordinate of the upper-left corner of the
0577: * active tile, with respect to the canvas origin, for component 'c', in
0578: * the component coordinates.
0579: * */
0580: public int getCompULX(int c) {
0581: return raster.getMinX();
0582: }
0583:
0584: /**
0585: * Returns the vertical coordinate of the upper-left corner of the active
0586: * tile, with respect to the canvas origin, in the component coordinates,
0587: * for the specified component.
0588: *
0589: * @param c The index of the component (between 0 and C-1)
0590: *
0591: * @return The vertical coordinate of the upper-left corner of the active
0592: * tile, with respect to the canvas origin, for component 'c', in the
0593: * component coordinates.
0594: * */
0595: public int getCompULY(int c) {
0596: return raster.getMinY();
0597: }
0598:
0599: /**
0600: * Returns the horizontal coordinate of the image origin, the top-left
0601: * corner, in the canvas system, on the reference grid.
0602: *
0603: * @return The horizontal coordinate of the image origin in the canvas
0604: * system, on the reference grid.
0605: * */
0606: public int getImgULX() {
0607: return destinationRegion.x;
0608: }
0609:
0610: /**
0611: * Returns the vertical coordinate of the image origin, the top-left
0612: * corner, in the canvas system, on the reference grid.
0613: *
0614: * @return The vertical coordinate of the image origin in the canvas
0615: * system, on the reference grid.
0616: * */
0617: public int getImgULY() {
0618: return destinationRegion.y;
0619: }
0620:
0621: /**
0622: * Returns the number of tiles in the horizontal and vertical
0623: * directions.
0624: *
0625: * @param co If not null this object is used to return the information. If
0626: * null a new one is created and returned.
0627: *
0628: * @return The number of tiles in the horizontal (Point.x) and vertical
0629: * (Point.y) directions.
0630: * */
0631: public Point getNumTiles(Point co) {
0632: if (co != null) {
0633: co.x = getNumXTiles();
0634: co.y = getNumYTiles();
0635: return co;
0636: } else {
0637: return new Point(getNumXTiles(), getNumYTiles());
0638: }
0639: }
0640:
0641: /**
0642: * Returns the total number of tiles in the image. This default
0643: * implementation assumes no tiling, so 1 is always returned.
0644: *
0645: * @return The total number of tiles in the image.
0646: * */
0647: public int getNumTiles() {
0648: return getNumXTiles() * getNumYTiles();
0649: }
0650:
0651: /**
0652: * Returns the number of bits corresponding to the nominal range of the
0653: * data in the specified component. This is the value rb (range bits) that
0654: * was specified in the constructor, which normally is 8 for non bilevel
0655: * data, and 1 for bilevel data.
0656: *
0657: * <P>If this number is <i>b</b> then the nominal range is between
0658: * -2^(b-1) and 2^(b-1)-1, since unsigned data is level shifted to have a
0659: * nominal avergae of 0.
0660: *
0661: * @param c The index of the component.
0662: *
0663: * @return The number of bits corresponding to the nominal range of the
0664: * data. For floating-point data this value is not applicable and the
0665: * return value is undefined.
0666: * */
0667: public int getNomRangeBits(int c) {
0668: // Check component index
0669: // XXX: Should be component-dependent.
0670: return rb;
0671: }
0672:
0673: /**
0674: * Returns the position of the fixed point in the specified component
0675: * (i.e. the number of fractional bits), which is always 0 for this
0676: * ImgReader.
0677: *
0678: * @param c The index of the component.
0679: *
0680: * @return The position of the fixed-point (i.e. the number of fractional
0681: * bits). Always 0 for this ImgReader.
0682: * */
0683: public int getFixedPoint(int c) {
0684: // Check component index
0685: return 0;
0686: }
0687:
0688: /**
0689: * Returns, in the blk argument, the block of image data containing the
0690: * specifed rectangular area, in the specified component. The data is
0691: * returned, as a reference to the internal data, if any, instead of as a
0692: * copy, therefore the returned data should not be modified.
0693: *
0694: * <P> After being read the coefficients are level shifted by subtracting
0695: * 2^(nominal bit range - 1)
0696: *
0697: * <P>The rectangular area to return is specified by the 'ulx', 'uly', 'w'
0698: * and 'h' members of the 'blk' argument, relative to the current
0699: * tile. These members are not modified by this method. The 'offset' and
0700: * 'scanw' of the returned data can be arbitrary. See the 'DataBlk' class.
0701: *
0702: * <P>If the data array in <tt>blk</tt> is <tt>null</tt>, then a new one
0703: * is created if necessary. The implementation of this interface may
0704: * choose to return the same array or a new one, depending on what is more
0705: * efficient. Therefore, the data array in <tt>blk</tt> prior to the
0706: * method call should not be considered to contain the returned data, a
0707: * new array may have been created. Instead, get the array from
0708: * <tt>blk</tt> after the method has returned.
0709: *
0710: * <P>The returned data always has its 'progressive' attribute unset
0711: * (i.e. false).
0712: *
0713: * <P>When an I/O exception is encountered the JJ2KExceptionHandler is
0714: * used. The exception is passed to its handleException method. The action
0715: * that is taken depends on the action that has been registered in
0716: * JJ2KExceptionHandler. See JJ2KExceptionHandler for details.
0717: *
0718: * <P>This method implements buffering for the 3 components: When the
0719: * first one is asked, all the 3 components are read and stored until they
0720: * are needed.
0721: *
0722: * @param blk Its coordinates and dimensions specify the area to
0723: * return. Some fields in this object are modified to return the data.
0724: *
0725: * @param c The index of the component from which to get the data. Only 0,
0726: * 1 and 3 are valid.
0727: *
0728: * @return The requested DataBlk
0729: *
0730: * @see #getCompData
0731: *
0732: * @see JJ2KExceptionHandler
0733: */
0734: public final DataBlk getInternCompData(DataBlk blk, int c) {
0735: if (writer != null && writer.getAbortRequest())
0736: throw new RuntimeException(J2KImageWriter.WRITE_ABORTED);
0737:
0738: if (barr == null)
0739: barr = new int[nc][];
0740:
0741: // Check type of block provided as an argument
0742: if (blk.getDataType() != DataBlk.TYPE_INT) {
0743: if (intBlk == null)
0744: intBlk = new DataBlkInt(blk.ulx, blk.uly, blk.w, blk.h);
0745: else {
0746: intBlk.ulx = blk.ulx;
0747: intBlk.uly = blk.uly;
0748: intBlk.w = blk.w;
0749: intBlk.h = blk.h;
0750: }
0751: blk = intBlk;
0752: }
0753:
0754: float percentage = (getTileIdx() + (blk.uly + 1.0F) / blk.h)
0755: / getNumTiles();
0756: writer.processImageProgressWrapper(percentage * 100.0F);
0757:
0758: // If asking a component for the first time for this block, read the 3
0759: // components
0760: if ((barr[c] == null) || (dbi.ulx > blk.ulx)
0761: || (dbi.uly > blk.uly)
0762: || (dbi.ulx + dbi.w < blk.ulx + blk.w)
0763: || (dbi.uly + dbi.h < blk.uly + blk.h)) {
0764: int k, j, i, mi;
0765:
0766: // Reset data arrays if needed
0767: if (barr[c] == null || barr[c].length < blk.w * blk.h) {
0768: barr[c] = new int[blk.w * blk.h];
0769: }
0770: blk.setData(barr[c]);
0771:
0772: for (i = (c + 1) % nc; i != c; i = (i + 1) % nc)
0773: if (barr[i] == null || barr[i].length < blk.w * blk.h) {
0774: barr[i] = new int[blk.w * blk.h];
0775: }
0776:
0777: // set attributes of the DataBlk used for buffering
0778: dbi.ulx = blk.ulx;
0779: dbi.uly = blk.uly;
0780: dbi.w = blk.w;
0781: dbi.h = blk.h;
0782:
0783: // get data from the image
0784: if (aTile == null) {
0785: aTile = getTile(co.x, co.y);
0786: Rectangle temp = aTile.getBounds();
0787: aTile = aTile.createTranslatedChild(temp.x - minX,
0788: temp.y - minY);
0789: }
0790:
0791: for (i = 0; i < nc; i++) {
0792: aTile.getSamples(blk.ulx, blk.uly, blk.w, blk.h, i,
0793: barr[i]);
0794: for (k = 0; k < barr[i].length; k++)
0795: barr[i][k] -= dcOffset;
0796: }
0797: //getByteData(raster, new Rectangle(blk.ulx, blk.uly, blk.w, blk.h), barr);
0798:
0799: // Set buffer attributes
0800: blk.setData(barr[c]);
0801: blk.offset = 0;
0802: blk.scanw = blk.w;
0803: } else { //Asking for the 2nd or 3rd block component
0804: blk.setData(barr[c]);
0805: blk.offset = (blk.ulx - dbi.ulx) * dbi.w + blk.ulx
0806: - dbi.ulx;
0807: blk.scanw = dbi.scanw;
0808: }
0809:
0810: // Turn off the progressive attribute
0811: blk.progressive = false;
0812: return blk;
0813: }
0814:
0815: /**
0816: * Returns, in the blk argument, a block of image data containing the
0817: * specifed rectangular area, in the specified component. The data is
0818: * returned, as a copy of the internal data, therefore the returned data
0819: * can be modified "in place".
0820: *
0821: * <P> After being read the coefficients are level shifted by subtracting
0822: * 2^(nominal bit range - 1)
0823: *
0824: * <P>The rectangular area to return is specified by the 'ulx', 'uly', 'w'
0825: * and 'h' members of the 'blk' argument, relative to the current
0826: * tile. These members are not modified by this method. The 'offset' of
0827: * the returned data is 0, and the 'scanw' is the same as the block's
0828: * width. See the 'DataBlk' class.
0829: *
0830: * <P>If the data array in 'blk' is 'null', then a new one is created. If
0831: * the data array is not 'null' then it is reused, and it must be large
0832: * enough to contain the block's data. Otherwise an 'ArrayStoreException'
0833: * or an 'IndexOutOfBoundsException' is thrown by the Java system.
0834: *
0835: * <P>The returned data has its 'progressive' attribute unset
0836: * (i.e. false).
0837: *
0838: * <P>When an I/O exception is encountered the JJ2KExceptionHandler is
0839: * used. The exception is passed to its handleException method. The action
0840: * that is taken depends on the action that has been registered in
0841: * JJ2KExceptionHandler. See JJ2KExceptionHandler for details.
0842: *
0843: * @param blk Its coordinates and dimensions specify the area to
0844: * return. If it contains a non-null data array, then it must have the
0845: * correct dimensions. If it contains a null data array a new one is
0846: * created. The fields in this object are modified to return the data.
0847: *
0848: * @param c The index of the component from which to get the data. Only
0849: * 0,1 and 2 are valid.
0850: *
0851: * @return The requested DataBlk
0852: *
0853: * @see #getInternCompData
0854: *
0855: * @see JJ2KExceptionHandler
0856: * */
0857: public final DataBlk getCompData(DataBlk blk, int c) {
0858: // NOTE: can not directly call getInterCompData since that returns
0859: // internally buffered data.
0860: int ulx, uly, w, h;
0861:
0862: // Check type of block provided as an argument
0863: if (blk.getDataType() != DataBlk.TYPE_INT) {
0864: DataBlkInt tmp = new DataBlkInt(blk.ulx, blk.uly, blk.w,
0865: blk.h);
0866: blk = tmp;
0867: }
0868:
0869: int bakarr[] = (int[]) blk.getData();
0870: // Save requested block size
0871: ulx = blk.ulx;
0872: uly = blk.uly;
0873: w = blk.w;
0874: h = blk.h;
0875: // Force internal data buffer to be different from external
0876: blk.setData(null);
0877: getInternCompData(blk, c);
0878: // Copy the data
0879: if (bakarr == null) {
0880: bakarr = new int[w * h];
0881: }
0882: if (blk.offset == 0 && blk.scanw == w) {
0883: // Requested and returned block buffer are the same size
0884: System.arraycopy(blk.getData(), 0, bakarr, 0, w * h);
0885: } else { // Requested and returned block are different
0886: for (int i = h - 1; i >= 0; i--) { // copy line by line
0887: System.arraycopy(blk.getData(), blk.offset + i
0888: * blk.scanw, bakarr, i * w, w);
0889: }
0890: }
0891: blk.setData(bakarr);
0892: blk.offset = 0;
0893: blk.scanw = blk.w;
0894: return blk;
0895: }
0896:
0897: /**
0898: * Returns true if the data read was originally signed in the specified
0899: * component, false if not. This method always returns false since PPM
0900: * data is always unsigned.
0901: *
0902: * @param c The index of the component, from 0 to N-1.
0903: *
0904: * @return always false, since PPM data is always unsigned.
0905: * */
0906: public boolean isOrigSigned(int c) {
0907: if (isBinary)
0908: return true;
0909:
0910: // Check component index
0911: SampleModel sm = null;
0912: if (inputIsRaster)
0913: sm = raster.getSampleModel();
0914: else
0915: sm = src.getSampleModel();
0916:
0917: if (sm.getDataType() == DataBuffer.TYPE_USHORT
0918: || sm.getDataType() == DataBuffer.TYPE_BYTE)
0919: return false;
0920: return true;
0921: }
0922:
0923: private int getNumXTiles() {
0924: int x = destinationRegion.x;
0925: int tx = tileXOffset;
0926: int tw = tileWidth;
0927: return ToTile(x + destinationRegion.width - 1, tx, tw)
0928: - ToTile(x, tx, tw) + 1;
0929: }
0930:
0931: private int getNumYTiles() {
0932: int y = destinationRegion.y;
0933: int ty = tileYOffset;
0934: int th = tileHeight;
0935: return ToTile(y + destinationRegion.height - 1, ty, th)
0936: - ToTile(y, ty, th) + 1;
0937: }
0938:
0939: private static int ToTile(int pos, int tileOffset, int tileSize) {
0940: pos -= tileOffset;
0941: if (pos < 0) {
0942: pos += 1 - tileSize; // force round to -infinity (ceiling)
0943: }
0944: return pos / tileSize;
0945: }
0946:
0947: private Raster getTile(int tileX, int tileY) {
0948: int sx = tileXOffset + tileX * tileWidth;
0949: int sy = tileYOffset + tileY * tileHeight;
0950: tileX += tileXOffset / tileWidth;
0951: tileY += tileYOffset / tileHeight;
0952:
0953: if (inputIsRaster) {
0954: if (noTransform) {
0955: return raster.createChild(sx, sy, getTileWidth(),
0956: getTileHeight(), sx, sy, sourceBands);
0957: }
0958:
0959: WritableRaster ras = Raster.createWritableRaster(sm,
0960: new Point(sx, sy));
0961:
0962: int x = mapToSourceX(sx);
0963: int y = mapToSourceY(sy);
0964:
0965: int minY = raster.getMinY();
0966: int maxY = raster.getMinY() + raster.getHeight();
0967:
0968: int cTileWidth = getTileWidth();
0969: for (int j = 0; j < getTileHeight(); j++, sy++, y += scaleY) {
0970: if (y < minY || y >= maxY)
0971: continue;
0972: Raster source = raster.createChild(x, y,
0973: (cTileWidth - 1) * scaleX + 1, 1, x, y, null);
0974: int tempX = sx;
0975: for (int i = 0, offset = x; i < cTileWidth; i++, tempX++, offset += scaleX) {
0976: for (int k = 0; k < nc; k++) {
0977: int p = source.getSample(offset, y,
0978: sourceBands[k]);
0979: ras.setSample(tempX, sy, k, p);
0980: }
0981: }
0982: }
0983:
0984: return ras;
0985:
0986: } else {
0987: if (noTransform) {
0988: Raster ras = src.getTile(tileX, tileY);
0989: if (noSubband)
0990: return ras;
0991: else {
0992: return ras.createChild(sx, sy, tileWidth,
0993: tileHeight, sx, sy, sourceBands);
0994: }
0995: }
0996:
0997: WritableRaster ras = Raster.createWritableRaster(sm,
0998: new Point(sx, sy));
0999:
1000: int x = mapToSourceX(sx);
1001: int y = mapToSourceY(sy);
1002:
1003: int minY = src.getMinY();
1004: int maxY = src.getMinY() + src.getHeight();
1005: int length = tileWidth * scaleX;
1006:
1007: if (x + length >= src.getWidth())
1008: length = src.getWidth() - x;
1009: int dLength = (length + scaleX - 1) / scaleX;
1010:
1011: for (int j = 0; j < tileHeight; j++, sy++, y += scaleY) {
1012: if (y < minY || y >= maxY)
1013: continue;
1014:
1015: Raster source = src.getData(new Rectangle(x, y, length,
1016: 1));
1017:
1018: int tempX = sx;
1019: for (int i = 0, offset = x; i < dLength; i++, tempX++, offset += scaleX) {
1020:
1021: for (int k = 0; k < nc; k++) {
1022: int p = source.getSample(offset, y,
1023: sourceBands[k]);
1024:
1025: ras.setSample(tempX, sy, k, p);
1026: }
1027: }
1028: }
1029: return ras;
1030: }
1031: }
1032:
1033: private int mapToSourceX(int x) {
1034: return x * scaleX + xOffset;
1035: }
1036:
1037: private int mapToSourceY(int y) {
1038: return y * scaleY + yOffset;
1039: }
1040: }
|