001: /*
002: * $RCSfile: FilterCRIF.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.1 $
009: * $Date: 2005/02/11 04:56:26 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import java.awt.RenderingHints;
015: import java.awt.image.RenderedImage;
016: import java.awt.image.renderable.ParameterBlock;
017: import java.awt.image.renderable.RenderableImage;
018: import java.awt.image.renderable.RenderContext;
019: import java.util.Arrays;
020: import javax.media.jai.CRIFImpl;
021: import javax.media.jai.JAI;
022: import javax.media.jai.KernelJAI;
023:
024: /**
025: * This CRIF implements rendering-independent filtering (blur/sharpen).
026: *
027: * @since 1.0
028: * @see FilterDescriptor
029: */
030: final class FilterCRIF extends CRIFImpl {
031: /**
032: * Step size of the filter parameter indicating a step from one kernel
033: * size to the next.
034: */
035: private static final int STEPSIZE = 5;
036:
037: /**
038: * Create a kernel given the filter parameter. Positive is blur,
039: * negative sharpen.
040: */
041: private static final KernelJAI createKernel(double p) {
042: int STEPSIZE = 5;
043:
044: if (p == 0.0) {
045: return null;
046: }
047:
048: double pAbs = Math.abs(p);
049: int idx = ((int) pAbs) / STEPSIZE;
050: double frac = (10.0F / STEPSIZE) * (pAbs - idx * STEPSIZE);
051: double blend = 1.0 / 99.0 * (Math.pow(10.0, 0.2 * frac) - 1.0);
052:
053: // First create a low-pass kernel.
054: int size;
055: float[] data;
056: if (idx * STEPSIZE == pAbs) {
057: // The parameter is at the left end of an interval so no
058: // blending of kernels is required.
059: size = 2 * idx + 1;
060: data = new float[size * size];
061: float val = 1.0F / (size * size);
062: Arrays.fill(data, val);
063: } else {
064: // Create data for the left and right intervals and blend them.
065: int size1 = 2 * idx + 1;
066: size = size1 + 2;
067: data = new float[size * size];
068: float val1 = (1.0F / (size1 * size1))
069: * (1.0F - (float) blend);
070: int row = size;
071: for (int j = 1; j < size - 1; j++) {
072: for (int i = 1; i < size - 1; i++) {
073: data[row + i] = val1;
074: }
075: row += size;
076: }
077: float val2 = (1.0F / (size * size)) * (float) blend;
078: for (int i = 0; i < data.length; i++) {
079: data[i] += val2;
080: }
081: }
082:
083: // For positive factor generate a high-pass kernel.
084: if (p > 0.0) {
085: // Subtract the low-pass kernel data from the image.
086: for (int i = 0; i < data.length; i++) {
087: data[i] *= -1.0;
088: }
089: data[data.length / 2] += 2.0F;
090: }
091:
092: return new KernelJAI(size, size, data);
093: }
094:
095: /** Constructor. */
096: public FilterCRIF() {
097: super ();
098: }
099:
100: /**
101: * Implementation of "RIF" create().
102: */
103: public RenderedImage create(ParameterBlock paramBlock,
104: RenderingHints renderHints) {
105: KernelJAI kernel = createKernel(paramBlock.getFloatParameter(0));
106:
107: return kernel == null ? paramBlock.getRenderedSource(0) : JAI
108: .create("convolve", paramBlock.getRenderedSource(0),
109: kernel);
110: }
111:
112: }
|