Source: ptolemy/actor/lib/jjs/modules/imageFilters/imageFilters.js

// Below is the copyright agreement for the Ptolemy II system.
//
// Copyright (c) 2015-2016 The Regents of the University of California.
// All rights reserved.
//
// Permission is hereby granted, without written agreement and without
// license or royalty fees, to use, copy, modify, and distribute this
// software and its documentation for any purpose, provided that the above
// copyright notice and the following two paragraphs appear in all copies
// of this software.
//
// IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
// FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
// THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
//
// THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
// PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
// CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
// ENHANCEMENTS, OR MODIFICATIONS.
//
//
// Ptolemy II includes the work of others, to see those copyrights, follow
// the copyright link on the splash page or see copyright.htm.
/**
 * Module to filter images. This module provides a set of image filters,
 * each realized by calling the {@link filter} function, passing it an input
 * image, a filter name, and optional filter options.
 * The list of available filters is provided by the {@link filters()} function.
 *
 * This implementation uses code by Jerry Huxtable, licensed under
 * the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0).
 * The code is available at [http://www.jhlabs.com/ip/filters](http://www.jhlabs.com/ip/filters).
 *
 * The filters provided by this implementation include at least the ones listed below,
 * with options in the sublist (if there are options).
 * <font color="red">FIXME:</font> <i>This list is incomplete. See
 * $PTII/com/jhlabs/image for a complete list of filters</i>.
 * * __Annotate__: Annotate an image with an overlaid SVG graphic.
 *   * _Graphic_: The SVG graphic. Defaults to an empty string, which specifies to use GraphicURI.
 *   * _GraphicURI_: The location of the graphic. Defaults to an empty string, which specifies no graphic.
 *   * _Rotation_: A rotation to apply before translating.
 *   * _Scale_: A scaling to apply before translating.
 *   * _XOffset_: The horizontal offset (translation) for the graphic in pixels. Defaults to 0.
 *   * _YOffset_: The vertical offset (translation) for the graphic in pixels. Defaults to 0.
 * * __Average__: Average the 3x3 neighbourhood of each pixel, providing a simple blur.
 * * __BicubicScale__: Scale an image using bi-cubic interpolation.
 *   * _Height_: The height of the result image, in pixels. Defaults to 256.
 *   * _Width_: The width of the result image, in pixels. Defaults to 256.
 * * __Block__: Pixellate an image.
 *   * _BlockSize_: The size of the blocks.
 * * __Border__: Put a border around the image.
 *   * _BorderColor_: The color (see below) for the border. This defaults to white.
 *   * _BottomBorder_: The width of the bottom border, in pixels. This defaults to 10.
 *   * _LeftBorder_: The width of the left border, in pixels. This defaults to 10.
 *   * _RightBorder_: The width of the right border, in pixels. This defaults to 10.
 *   * _TopBorder_: The width of the top border, in pixels. This defaults to 10.
 * * __BoxBlur__: Box blur the image.
 *   * _HRadius_: The horizontal radius, in pixels. This defaults to 10.
 *   * _VRadius_: The vertical radius, in pixels. This defaults to 10.
 *   * _Iterations_: The number of iterations. This defaults to 1, but larger integers will approximate Gaussian blur.
 * * __Bump__: A simple embossing filter.
 * * __ChannelMix__: Mix the red, green and blue channels of an image into each other.
 *   The default options are {"IntoR": 255, "IntoG": 255, "IntoB": 255, "BlueGreen": 127, "GreenRed": 127, "RedBlue": 127},
 *   which inverts the colors while preserving the original brightness.
 *   * _IntoB_: How much of the blue in the output is taken from red and green.
 *     255 means all of it, and 0 means none of it (all the original blue is preserved).
 *   * _IntoG_: How much of the green in the output is taken from red and blue.
 *     255 means all of it, and 0 means none of it (all the original green is preserved).
 *   * _IntoR_: How much of the red in the output is taken from blue and green.
 *     255 means all of it, and 0 means none of it (all the original red is preserved).
 *   * _BlueGreen_: Proportion of blue vs. green that goes into red.
 *      0 means only blue and 255 means only green.
 *   * _GreenRed_: Proportion of green vs. red that goes into blue.
 *      0 means only green and 255 means only red.
 *   * _RedBlue_: Proportion of red vs. blue that goes into green.
 *      0 means only red and 255 means only green.
 * * __Chrome__: Create a chrome effect on the image.
 *   * _Amount_: The amount of the effect. This ranges from 0.0 to 1.0 and defaults to 0.5.
 *   * _Exposure_: The exposure, ranging from 0.0 (black image) to 1.0 (maximum, the default).
 * * __Circle__: Wrap an image around a circular arc.
 *   * _Angle_: The starting angle of the arc, in radians. This defaults to 0.0.
 *   * _Height_: The height of the arc, in pixels. This defaults to 200.
 *   * _Radius_: The radius of the inner arc, in pixels. This defaults to 100.
 *   * _CentreX_: The horizontal center of the arc, as a fraction of the width. This ranges from 0.0 to 1.0 and defaults to 0.5.
 *   * _CentreY_: The vertical center of the arc, as a fraction of the width. This ranges from 0.0 to 1.0 and defaults to 1.0.
 *   * _SpreadAngle_: The spread angle of the arc, in radians. This defaults to $PI.
 * * __ColorHalftone__:
 *   * _DotRadius_: The size of the dots, in pixels. This defaults to 2.0.
 *   * _CyanScreenAngle_: The angle of the cyan screen, in radians. This defaults to 1.885 (108 degrees).
 *   * _MagentaScreenAngle_: The angle of the magenta screen, in radians. This defaults to 2.827 (162 degrees).
 *   * _YellowScreenAngle_: The angle of the yellow screen, in radians. This defaults to 1.571 (90 degrees).
 * * __Contour___: Draw contours on an image at given changes in brightness levels.
 *   * _Levels_: The number of levels into which to divide the image. This defaults to 5.
 *   * _Scale_: The scale factor to apply to the brightness before leveling. This defaults to 1.
 *   * _Offset_: An offset to apply to the brightness. This defaults to 0.
 *   * _ContourColor_: The color to use in drawing the contours. This defaults to "black" (see below for color specs).
 * * __Contrast__: Change the brightness and contrast of an image.
 *   * _Brightness_: The brightness scale factor. This defaults to 1.0, which makes no change in brightness.
 *   * _Contrast_: The contrast scale factor. This defaults to 1.0, which makes no change in contrast.
 * * __Crop__: Crop an image.
 *   * _X_: The starting horizontal position, in pixels. This defaults to 0.
 *   * _Y_: The starting vertical position, in pixels. This defaults to 0.
 *   * _Width_: The width, in pixels. This defaults to 128.
 *   * _Height_: The height, in pixels. This defaults to 128.
 * * __Crystallize__: Apply a crystallizing effect to an image, by producing Voronoi cells filled with colours from the image.
 *   * _Angle_: Angle of the cells in radians. Defaults to 0.0.
 *   * _EdgeColor_: Color for the edge lines (see below). Defaults to black.
 *   * _EdgeThickness_: Thickness of the edges. Defaults to 0.4.
 *   * _FadeEdges_: Boolean indicating whether to fade edges. Defaults to false.
 *   * _Scale_: Size of the cells, in pixels. Defaults to 16.
 *   * _Stretch_: Vertical stretch of the cells. Defaults to 1.0, which does not stretch.
 * * __FIXME__: Missing filters (alphabetically) here.
 * * __Gray__: Gray out an image by averaging each pixel with white.
 * * __Invert__: Invert the colors of an image.
 * * __LensBlur__: Simulate a lens blur. Options:
 *   * _Bloom_: The bloom factor. This is an int that defaults to 2.
 *   * _BloomThreshold_: The bloom threshold. This is an int that defaults to 255, which disables bloom.
 *   * _Radius_: The radius, in pixels. This is an int that defaults to 10.
 *   * _Sides_: The number of sides of the aperture. This is an int that defaults to 5.
 * * __MotionDetector__: Detect motion and indicate it on the image.
 *   * _PixelThreshold_: Intensity threshold whereby a pixel is deemed to different (an int 0 - 255, with default 25).
 *   * _AreaThreshold_: The percentage threshold of image that has different pixels for motion to be detected (a double 0-100, with default 0.2).
 * * __Solarize__: Solarize an image.
 * * __Threshold__: Threshold pixels in an image, based on their brightness. Options:
 *   * _LowerThreshold_: The threshold below which pixels become _Black_. This is an int that defaults to 127.
 *   * _UpperThreshold_: The threshold above which pixels become _White_. This is an int that defaults to 127.
 *   * _Black_: The color produced for pixels below _LowerThreshold_. This is color (see below) that defaults to black.
 *   * _White_: The color produced for pixels above _UpperThreshold_. This is color (see below) that defaults to white.
 *
 * For options that specify a color, the color may be given as an integer where bits 24-31
 * represent alpha, bits 16-23 represent red, bits 8-15 represent green, and bits 0-7 represent blue.
 * Alternatively, the color may be given as a string of the form of a hexadecimal number,
 * e.g. "0xff0000" for red, a standard color name, e.g. "red", or a CSS-style color specification,
 * e.g. "#FF0000" for red. The color names supported are black, blue, cyan, darkGray, gray, green,
 * lightGray, magenta, orange, pink, red, white, and yellow.
 *
 * @module imageFilters
 * @author Edward A. Lee
 * @version $$Id$$
 */

// Stop extra messages from jslint.  Note that there should be no
// space between the / and the * and global.
/*globals Java, error, exports */
/*jshint globalstrict: true*/
"use strict";

////////////////////////////////////////////////////////////
//// Private variables.

// Object to keep filters so that we don't instantiate them more than once.
var filters = {};

////////////////////////////////////////////////////////////
//// Functions provided in this module.

/** Return an array of filter names for image filters currently available
 *  on the current host.
 *  @return An array of filter names.
 */
exports.filters = function () {
    return ['Annotate', 'Average', 'BicubicScale', 'Block', 'Border', 'BoxBlur',
        'Bump', 'ChannelMix', 'Chrome', 'Circle',
        'ColorHalftone', 'Contour', 'Contrast', 'Crop',
        'Crystallize',
        'Gray', 'Invert', 'LensBlur', 'MotionDetector', 'Solarize', 'Threshold'
    ];
};

/** Invoke the named filter on the specified image with the specified
 *  options and return the result.  Any unrecognized options are ignored.
 *  Note that previously applied options for a given filter will still be
 *  used, even if they are not set in this call.
 *  @param image The image to filter.
 *  @param filterName The name of the filter.
 *  @param options An object whose fields specify filter options.
 *  @return The filtered image.
 */
exports.filter = function (image, filterName, options) {
    image = image.asAWTImage();
    var filter = filters[filterName],
        Filter,
        optionName,
        root,
        setter;
    if (!filter) {
        root = 'com.jhlabs.image.';
        Filter = null;
        try {
            Filter = Java.type(root + filterName + 'Filter');
        } catch (ex) {
            // Try alternative location.
            try {
                Filter = Java.type(root + 'svg.' + filterName + 'Filter');
            } catch (ex2) {
                throw new Error('Cannot find filter: ' + filterName);
            }
        }
        filter = new Filter();
        filters[filterName] = filter;
    }
    if (options) {
        for (optionName in options) {
            if (options.hasOwnProperty(optionName)) {
                // Look for a setter function for the option.
                setter = 'set' + optionName;
                if (typeof filter[setter] === 'function') {
                    // Invoke the setter function.
                    filter[setter](options[optionName]);
                }
            }
        }
    }
    // The second (null) argument declines to give a destination image.
    return filter.filter(image, null);
};