/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-11 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.core;
import java.awt.*;
import java.awt.image.*;
import java.io.*;
import java.util.Iterator;
import javax.imageio.*;
import javax.imageio.metadata.*;
/**
* ( begin auto-generated from PImage.xml )
*
* Datatype for storing images. Processing can display .gif,
* .jpg, .tga, and .png images. Images may be
* displayed in 2D and 3D space. Before an image is used, it must be loaded
* with the loadImage() function. The PImage class contains
* fields for the width and height of the image, as well as
* an array called pixels[] that contains the values for every pixel
* in the image. The methods described below allow easy access to the
* image's pixels and alpha channel and simplify the process of compositing.
*
using the pixels[] array, be sure to use the
* loadPixels() method on the image to make sure that the pixel data
* is properly loaded.
*
create a new image, use the createImage() function. Do not
* use the syntax new PImage().
*
* ( end auto-generated )
*
* @webref image
* @usage Web & Application
* @instanceName pimg any object of type PImage
* @see PApplet#loadImage(String)
* @see PApplet#imageMode(int)
* @see PApplet#createImage(int, int, int)
*/
public class PImage implements PConstants, Cloneable {
/**
* Format for this image, one of RGB, ARGB or ALPHA.
* note that RGB images still require 0xff in the high byte
* because of how they'll be manipulated by other functions
*/
public int format;
/**
* ( begin auto-generated from pixels.xml )
*
* Array containing the values for all the pixels in the display window.
* These values are of the color datatype. This array is the size of the
* display window. For example, if the image is 100x100 pixels, there will
* be 10000 values and if the window is 200x300 pixels, there will be 60000
* values. The index value defines the position of a value within
* the array. For example, the statement color b = pixels[230] will
* set the variable b to be equal to the value at that location in
* the array.
*
* Before accessing this array, the data must loaded with the
* loadPixels() function. After the array data has been modified,
* the updatePixels() function must be run to update the changes.
* Without loadPixels(), running the code may (or will in future
* releases) result in a NullPointerException.
*
* ( end auto-generated )
*
* @webref image:pixels
* @usage web_application
* @brief Array containing the color of every pixel in the image
*/
public int[] pixels;
/**
* ( begin auto-generated from PImage_width.xml )
*
* The width of the image in units of pixels.
*
* ( end auto-generated )
* @webref pimage:field
* @usage web_application
* @brief Image width
*/
public int width;
/**
* ( begin auto-generated from PImage_height.xml )
*
* The height of the image in units of pixels.
*
* ( end auto-generated )
* @webref pimage:field
* @usage web_application
* @brief Image height
*/
public int height;
/**
* Path to parent object that will be used with save().
* This prevents users from needing savePath() to use PImage.save().
*/
public PApplet parent;
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/** for renderers that need to store info about the image */
//protected HashMap cacheMap;
// protected WeakHashMap cacheMap;
/** for renderers that need to store parameters about the image */
// protected HashMap paramMap;
/** modified portion of the image */
protected boolean modified;
protected int mx1, my1, mx2, my2;
/** Loaded pixels flag */
public boolean loaded = false;
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// private fields
private int fracU, ifU, fracV, ifV, u1, u2, v1, v2, sX, sY, iw, iw1, ih1;
private int ul, ll, ur, lr, cUL, cLL, cUR, cLR;
private int srcXOffset, srcYOffset;
private int r, g, b, a;
private int[] srcBuffer;
// fixed point precision is limited to 15 bits!!
static final int PRECISIONB = 15;
static final int PRECISIONF = 1 mx2) mx2 = PApplet.min(width - 1, x);
if (x > mx2) mx2 = PApplet.min(width, x);
if (y < my1) my1 = PApplet.max(0, y);
//if (y > my2) my2 = y;
if (y > my2) my2 = PApplet.min(height, y);
if (x2 < mx1) mx1 = PApplet.max(0, x2);
//if (x2 > mx2) mx2 = PApplet.min(width - 1, x2);
if (x2 > mx2) mx2 = PApplet.min(width, x2);
if (y2 < my1) my1 = PApplet.max(0, y2);
//if (y2 > my2) my2 = PApplet.min(height - 1, y2);
if (y2 > my2) my2 = PApplet.min(height, y2);
}
}
//////////////////////////////////////////////////////////////
// COPYING IMAGE DATA
/**
* Duplicate an image, returns new PImage object.
* The pixels[] array for the new object will be unique
* and recopied from the source image. This is implemented as an
* override of Object.clone(). We recommend using get() instead,
* because it prevents you from needing to catch the
* CloneNotSupportedException, and from doing a cast from the result.
*/
@Override
public Object clone() throws CloneNotSupportedException { // ignore
return get();
}
/**
* ( begin auto-generated from PImage_resize.xml )
*
* Resize the image to a new width and height. To make the image scale
* proportionally, use 0 as the value for the wide or high
* parameter. For instance, to make the width of an image 150 pixels, and
* change the height using the same proportion, use resize(150, 0).
*
* Even though a PGraphics is technically a PImage, it is not possible to
* rescale the image data found in a PGraphics. (It's simply not possible
* to do this consistently across renderers: technically infeasible with
* P3D, or what would it even do with PDF?) If you want to resize PGraphics
* content, first get a copy of its image data using the get()
* method, and call resize() on the PImage that is returned.
*
* ( end auto-generated )
* @webref pimage:method
* @brief Changes the size of an image to a new width and height
* @usage web_application
* @param w the resized image width
* @param h the resized image height
* @see PImage#get(int, int, int, int)
*/
public void resize(int w, int h) { // ignore
if (w targetWidth) {
w /= 2;
// if this is the last step, do the exact size
if (w < targetWidth) {
w = targetWidth;
}
} else if (targetWidth >= w) {
w = targetWidth;
}
if (h > targetHeight) {
h /= 2;
if (h < targetHeight) {
h = targetHeight;
}
} else if (targetHeight >= h) {
h = targetHeight;
}
if (scratchImage == null || isTranslucent) {
// Use a single scratch buffer for all iterations and then copy
// to the final, correctly-sized image before returning
scratchImage = new BufferedImage(w, h, type);
g2 = scratchImage.createGraphics();
}
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(outgoing, 0, 0, w, h, 0, 0, prevW, prevH, null);
prevW = w;
prevH = h;
outgoing = scratchImage;
} while (w != targetWidth || h != targetHeight);
if (g2 != null) {
g2.dispose();
}
// If we used a scratch buffer that is larger than our target size,
// create an image of the right size and copy the results into it
if (targetWidth != outgoing.getWidth() ||
targetHeight != outgoing.getHeight()) {
scratchImage = new BufferedImage(targetWidth, targetHeight, type);
g2 = scratchImage.createGraphics();
g2.drawImage(outgoing, 0, 0, null);
g2.dispose();
outgoing = scratchImage;
}
return outgoing;
}
//////////////////////////////////////////////////////////////
// MARKING IMAGE AS LOADED / FOR USE IN RENDERERS
public boolean isLoaded() { // ignore
return loaded;
}
public void setLoaded() { // ignore
loaded = true;
}
public void setLoaded(boolean l) { // ignore
loaded = l;
}
//////////////////////////////////////////////////////////////
// GET/SET PIXELS
/**
* ( begin auto-generated from PImage_get.xml )
*
* Reads the color of any pixel or grabs a section of an image. If no
* parameters are specified, the entire image is returned. Use the x
* and y parameters to get the value of one pixel. Get a section of
* the display window by specifying an additional width and
* height parameter. When getting an image, the x and
* y parameters define the coordinates for the upper-left corner of
* the image, regardless of the current imageMode().
*
* If the pixel requested is outside of the image window, black is
* returned. The numbers returned are scaled according to the current color
* ranges, but only RGB values are returned by this function. For example,
* even though you may have drawn a shape with colorMode(HSB), the
* numbers returned will be in RGB format.
*
* Getting the color of a single pixel with get(x, y) is easy, but
* not as fast as grabbing the data directly from pixels[]. The
* equivalent statement to get(x, y) using pixels[] is
* pixels[y*width+x]. See the reference for pixels[] for more information.
*
* ( end auto-generated )
*
* Advanced
* Returns an ARGB "color" type (a packed 32 bit int with the color.
* If the coordinate is outside the image, zero is returned
* (black, but completely transparent).
*
* If the image is in RGB format (i.e. on a PVideo object),
* the value will get its high bits set, just to avoid cases where
* they haven't been set already.
*
* If the image is in ALPHA format, this returns a white with its
* alpha value set.
*
* This function is included primarily for beginners. It is quite
* slow because it has to check to see if the x, y that was provided
* is inside the bounds, and then has to check to see what image
* type it is. If you want things to be more efficient, access the
* pixels[] array directly.
*
* @webref image:pixels
* @brief Reads the color of any pixel or grabs a rectangle of pixels
* @usage web_application
* @param x x-coordinate of the pixel
* @param y y-coordinate of the pixel
* @see PApplet#set(int, int, int)
* @see PApplet#pixels
* @see PApplet#copy(PImage, int, int, int, int, int, int, int, int)
*/
public int get(int x, int y) {
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) return 0;
switch (format) {
case RGB:
return pixels[y*width + x] | 0xff000000;
case ARGB:
return pixels[y*width + x];
case ALPHA:
return (pixels[y*width + x] width) {
w = width - x;
cropped = true;
}
if (y + h > height) {
h = height - y;
cropped = true;
}
if (w < 0) {
w = 0;
}
if (h < 0) {
h = 0;
}
int targetFormat = format;
if (cropped && format == RGB) {
targetFormat = ARGB;
}
PImage target = new PImage(targetWidth, targetHeight, targetFormat);
target.parent = parent; // parent may be null so can't use createImage()
if (w > 0 && h > 0) {
getImpl(x, y, w, h, target, targetX, targetY);
}
return target;
}
/**
* Returns a copy of this PImage. Equivalent to get(0, 0, width, height).
*/
public PImage get() {
// Formerly this used clone(), which caused memory problems.
// http://code.google.com/p/processing/issues/detail?id=42
return get(0, 0, width, height);
}
/**
* Internal function to actually handle getting a block of pixels that
* has already been properly cropped to a valid region. That is, x/y/w/h
* are guaranteed to be inside the image space, so the implementation can
* use the fastest possible pixel copying method.
*/
protected void getImpl(int sourceX, int sourceY,
int sourceWidth, int sourceHeight,
PImage target, int targetX, int targetY) {
int sourceIndex = sourceY*width + sourceX;
int targetIndex = targetY*target.width + targetX;
for (int row = 0; row < sourceHeight; row++) {
System.arraycopy(pixels, sourceIndex, target.pixels, targetIndex, sourceWidth);
sourceIndex += width;
targetIndex += target.width;
}
}
/**
* ( begin auto-generated from PImage_set.xml )
*
* Changes the color of any pixel or writes an image directly into the
* display window.
*
* The x and y parameters specify the pixel to change and the
* color parameter specifies the color value. The color parameter is
* affected by the current color mode (the default is RGB values from 0 to
* 255). When setting an image, the x and y parameters define
* the coordinates for the upper-left corner of the image, regardless of
* the current imageMode().
*
* Setting the color of a single pixel with set(x, y) is easy, but
* not as fast as putting the data directly into pixels[]. The
* equivalent statement to set(x, y, #000000) using pixels[]
* is pixels[y*width+x] = #000000. See the reference for
* pixels[] for more information.
*
* ( end auto-generated )
*
* @webref image:pixels
* @brief writes a color to any pixel or writes an image into another
* @usage web_application
* @param x x-coordinate of the pixel
* @param y y-coordinate of the pixel
* @param c any value of the color datatype
* @see PImage#get(int, int, int, int)
* @see PImage#pixels
* @see PImage#copy(PImage, int, int, int, int, int, int, int, int)
*/
public void set(int x, int y, int c) {
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) return;
pixels[y*width + x] = c;
//updatePixelsImpl(x, y, 1, 1); // slow?
updatePixels(x, y, 1, 1); // slow?
}
/**
*
Advanced
* Efficient method of drawing an image's pixels directly to this surface.
* No variations are employed, meaning that any scale, tint, or imageMode
* settings will be ignored.
*
* @param img image to copy into the original image
*/
public void set(int x, int y, PImage img) {
int sx = 0;
int sy = 0;
int sw = img.width;
int sh = img.height;
if (x < 0) { // off left edge
sx -= x;
sw += x;
x = 0;
}
if (y < 0) { // off top edge
sy -= y;
sh += y;
y = 0;
}
if (x + sw > width) { // off right edge
sw = width - x;
}
if (y + sh > height) { // off bottom edge
sh = height - y;
}
// this could be nonexistent
if ((sw