001: /*
002: * $RCSfile: MlibRotateRIF.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.2 $
009: * $Date: 2005/11/21 22:49:40 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.mlib;
013:
014: import java.awt.RenderingHints;
015: import java.awt.geom.AffineTransform;
016: import java.awt.geom.NoninvertibleTransformException;
017: import java.awt.image.RenderedImage;
018: import java.awt.image.renderable.ParameterBlock;
019: import java.awt.image.renderable.RenderedImageFactory;
020: import javax.media.jai.BorderExtender;
021: import javax.media.jai.ImageLayout;
022: import javax.media.jai.Interpolation;
023: import javax.media.jai.InterpolationBicubic2;
024: import javax.media.jai.InterpolationBicubic;
025: import javax.media.jai.InterpolationBilinear;
026: import javax.media.jai.InterpolationNearest;
027: import javax.media.jai.InterpolationTable;
028: import javax.media.jai.ImageLayout;
029: import javax.media.jai.JAI;
030: import javax.media.jai.OpImage;
031: import javax.media.jai.PlanarImage;
032: import java.util.Map;
033: import javax.media.jai.BorderExtender;
034: import com.sun.media.jai.opimage.RIFUtil;
035: import com.sun.media.jai.opimage.PointMapperOpImage;
036: import com.sun.media.jai.opimage.TranslateIntOpImage;
037:
038: /**
039: * A <code>RIF</code> supporting the "Rotate" operation in the
040: * rendered image mode using MediaLib.
041: *
042: * @see javax.media.jai.operator.RotateDescriptor
043: * @see MlibAffineOpimage
044: *
045: * @since EA4
046: */
047: public class MlibRotateRIF implements RenderedImageFactory {
048:
049: /** Constructor. */
050: public MlibRotateRIF() {
051: }
052:
053: /**
054: * Creates an rotate operation.
055: */
056: public RenderedImage create(ParameterBlock args,
057: RenderingHints hints) {
058: /* Get ImageLayout and TileCache from RenderingHints. */
059: ImageLayout layout = RIFUtil.getImageLayoutHint(hints);
060:
061: Interpolation interp = (Interpolation) args
062: .getObjectParameter(3);
063: double[] backgroundValues = (double[]) args
064: .getObjectParameter(4);
065:
066: RenderedImage source = args.getRenderedSource(0);
067:
068: if (!MediaLibAccessor.isMediaLibCompatible(args, layout)
069: || !MediaLibAccessor.hasSameNumBands(args, layout)
070: ||
071: // Medialib cannot deal with source image having tiles with any
072: // dimension greater than or equal to 32768
073: source.getTileWidth() >= 32768
074: || source.getTileHeight() >= 32768) {
075: return null;
076: }
077:
078: /* Get BorderExtender from hints if any. */
079: BorderExtender extender = RIFUtil.getBorderExtenderHint(hints);
080:
081: float x_center = args.getFloatParameter(0);
082: float y_center = args.getFloatParameter(1);
083: float angle = args.getFloatParameter(2);
084:
085: /*
086: * Convert angle to degrees (within some precision) given PI's
087: * transcendantal nature. All this, to check if we can call
088: * simpler methods like Copy or Transpose for certain angles
089: * viz., 0, 90, 180, 270, 360, 450, .....
090: */
091: double tmp_angle = 180.0F * angle / Math.PI;
092: double rnd_angle = Math.round(tmp_angle);
093:
094: /* Represent the angle as an AffineTransform. */
095: AffineTransform transform = AffineTransform.getRotateInstance(
096: angle, x_center, y_center);
097:
098: // Check if angle is (nearly) integral
099: if (Math.abs(rnd_angle - tmp_angle) < 0.0001) {
100: int dangle = (int) rnd_angle % 360;
101:
102: // Shift dangle into the range [0..359].
103: if (dangle < 0) {
104: dangle += 360;
105: }
106:
107: //
108: // Do a copy if angle is 0 degrees or
109: // multiple of 360 degrees
110: //
111: if (dangle == 0) {
112: return new MlibCopyOpImage(source, hints, layout);
113: }
114:
115: int ix_center = (int) Math.round(x_center);
116: int iy_center = (int) Math.round(y_center);
117:
118: // Do a transpose if angle is mutiple of 270, 180, 90 degrees
119: // and the translation is (nearly) integral.
120: if (((dangle % 90) == 0)
121: && (Math.abs(x_center - ix_center) < 0.0001)
122: && (Math.abs(y_center - iy_center) < 0.0001)) {
123:
124: int transType = -1;
125: int rotMinX = 0;
126: int rotMinY = 0;
127:
128: int sourceMinX = source.getMinX();
129: int sourceMinY = source.getMinY();
130: int sourceMaxX = sourceMinX + source.getWidth();
131: int sourceMaxY = sourceMinY + source.getHeight();
132:
133: if (dangle == 90) {
134: transType = 4;
135: rotMinX = ix_center - (sourceMaxY - iy_center);
136: rotMinY = iy_center - (ix_center - sourceMinX);
137: } else if (dangle == 180) {
138: transType = 5;
139: rotMinX = 2 * ix_center - sourceMaxX;
140: rotMinY = 2 * iy_center - sourceMaxY;
141: } else { // dangle == 270
142: transType = 6;
143: rotMinX = ix_center - (iy_center - sourceMinY);
144: rotMinY = iy_center - (sourceMaxX - ix_center);
145: }
146:
147: RenderedImage trans = new MlibTransposeOpImage(source,
148: hints, layout, transType);
149:
150: // Determine current image origin
151: int imMinX = trans.getMinX();
152: int imMinY = trans.getMinY();
153:
154: // Translate image and return it
155: // TranslateIntOpImage can't deal with ImageLayout hint
156: if (layout == null) {
157: OpImage intermediateImage = new TranslateIntOpImage(
158: trans, hints, rotMinX - imMinX, rotMinY
159: - imMinY);
160: try {
161: return new PointMapperOpImage(
162: intermediateImage, hints, transform);
163: } catch (NoninvertibleTransformException nite) {
164: return intermediateImage;
165: }
166: } else {
167: ParameterBlock pbScale = new ParameterBlock();
168: pbScale.addSource(trans);
169: pbScale.add(0F);
170: pbScale.add(0F);
171: pbScale.add(rotMinX - imMinX);
172: pbScale.add(rotMinY - imMinY);
173: pbScale.add(interp);
174: PlanarImage intermediateImage = JAI.create("scale",
175: pbScale, hints).getRendering();
176: try {
177: return new PointMapperOpImage(
178: intermediateImage, hints, transform);
179: } catch (NoninvertibleTransformException nite) {
180: return intermediateImage;
181: }
182: }
183: }
184: }
185:
186: /*
187: * At this point we know that we cannot call other operations.
188: * Have to do Affine.
189: */
190:
191: /* Do the Affine operation. */
192: if (interp instanceof InterpolationNearest) {
193: return new MlibAffineNearestOpImage(source, extender,
194: hints, layout, transform, interp, backgroundValues);
195: } else if (interp instanceof InterpolationBilinear) {
196: return new MlibAffineBilinearOpImage(source, extender,
197: hints, layout, transform, interp, backgroundValues);
198: } else if (interp instanceof InterpolationBicubic
199: || interp instanceof InterpolationBicubic2) {
200: return new MlibAffineBicubicOpImage(source, extender,
201: hints, layout, transform, interp, backgroundValues);
202: } else if (interp instanceof InterpolationTable) {
203: return new MlibAffineTableOpImage(source, extender, hints,
204: layout, transform, interp, backgroundValues);
205: } else {
206: return null;
207: }
208: }
209: }
|