image.java
来自「j2me设计的界面包」· Java 代码 · 共 722 行 · 第 1/2 页
JAVA
722 行
/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.lwuit;
import com.sun.lwuit.geom.Dimension;
import java.io.IOException;
import java.io.InputStream;
import javax.microedition.lcdui.game.Sprite;
import java.lang.ref.WeakReference;
import java.util.Hashtable;
/**
* Abstracts the underlying platform images allowing us to treat them as a uniform
* object.
*
* @author Chen Fishbein
*/
public class Image {
private javax.microedition.lcdui.Image image;
private int transform;
private boolean opaqueTested = false;
private boolean opaque;
private Graphics g;
private Hashtable scaleCache;
/** Creates a new instance of ImageImpl */
Image(javax.microedition.lcdui.Image image) {
this.image = image;
}
/** Creates a new instance of ImageImpl */
Image(int[] imageArray, int w, int h) {
this(javax.microedition.lcdui.Image.createRGBImage(imageArray, w, h, true));
}
/**
* Returns a cached scaled image
*
* @param size the size of the cached image
* @return cached image
*/
Image getCachedImage(Dimension size) {
if(scaleCache != null) {
WeakReference w = (WeakReference)scaleCache.get(size);
if(w != null) {
return (Image)w.get();
}
}
return null;
}
/**
* Returns a cached scaled image
*
* @param size the size of the cached image
* @return cached image
*/
void cacheImage(Dimension size, Image i) {
if(scaleCache == null) {
scaleCache = new Hashtable();
}
WeakReference w = new WeakReference(i);
scaleCache.put(size, w);
}
/**
* Extracts a subimage from the given image allowing us to breakdown a single large image
* into multiple smaller images in RAM, this actually creates a standalone version
* of the image for use.
*
* @param width the width of internal images
* @param height the height of internal images
* @return An array of all the possible images that can be created from the source
* @throws java.io.IOException
*/
public Image subImage(int x, int y, int width, int height, boolean processAlpha) {
// we use the getRGB API rather than the mutable image API to allow translucency to
// be maintained in the newly created image
int[] arr = new int[width * height];
image.getRGB(arr, 0, width, x, y, width, height);
Image i = new Image(javax.microedition.lcdui.Image.createRGBImage(arr, width, height, processAlpha));
i.opaque = opaque;
i.opaqueTested = opaqueTested;
return i;
}
/**
* Returns an instance of this image rotated by the given number of degrees. By default 90 degree
* angle divisions are supported, anything else is implementation dependent. This method assumes
* a square image. Notice that it is inefficient in the current implementation to rotate to
* non-square angles,
* <p>E.g. rotating an image to 45, 90 and 135 degrees is inefficient. Use rotatate to 45, 90
* and then rotate the 45 to another 90 degrees to achieve the same effect with less memory.
*
* @param degrees A degree in right angle must be larer than 0 and up to 359 degrees
* @return new image instance with the closest possible rotation
*/
public Image rotate(int degrees) {
// a square angle so we can use the "fast" algorithm...
int transform = 0;
Image i;
if(degrees % 90 == 0) {
transform = fastRotate(degrees);
i = new Image(image);
} else {
// rotate up to the point to a smaller than 90 degree angle then let the radian code do its magic...
if(degrees > 90) {
int deg = degrees - degrees % 90;
transform = fastRotate(deg);
degrees -= deg;
}
// can't use sprite rotation since it will lose transparency information...
int width = image.getWidth();
int height = image.getHeight();
int[] arr = new int[width * height];
int[] dest = new int[arr.length];
image.getRGB(arr, 0, width, 0, 0, width, height);
int centerX = width / 2;
int centerY = height / 2;
double radians = Math.toRadians(-degrees);
double cosDeg = Math.cos(radians);
double sinDeg = Math.sin(radians);
for(int x = 0 ; x < width ; x++) {
for(int y = 0 ; y < height ; y++) {
int x2 = round(cosDeg * (x - centerX) - sinDeg * (y - centerY) + centerX);
int y2 = round(sinDeg * (x - centerX) + cosDeg * (y - centerY) + centerY);
if(!(x2 < 0 || y2 < 0 || x2 >= width || y2 >= height)) {
int destOffset = x2 + y2 * width;
if(destOffset >= 0 && destOffset < dest.length) {
dest[x + y * width] = arr[destOffset];
}
}
}
}
i = new Image(javax.microedition.lcdui.Image.createRGBImage(dest, width, height, true));
}
i.transform = transform;
return i;
}
private int round(double d) {
double f = Math.floor(d);
double c = Math.ceil(d);
if(c - d < d - f) {
return (int)c;
}
return (int)f;
}
/**
* Creates a new image instance with the alpha channel of opaque/translucent
* pixels within the image using the new alpha value. Transparent (alpha == 0)
* pixels remain transparent. All other pixels will have the new alpha value.
*
* @param alpha New value for the entire alpha channel
* @return Translucent/Opaque image based on the alpha value and the pixels of
* this image
*/
public Image modifyAlpha(byte alpha) {
int w = image.getWidth();
int h = image.getHeight();
int size = w * h;
int[] arr = new int[size];
image.getRGB(arr, 0, w, 0, 0, w, h);
int alphaInt = (((int)alpha) << 24) & 0xff000000;
for(int iter = 0 ; iter < size ; iter++) {
if((arr[iter] & 0xff000000) != 0) {
arr[iter] = (arr[iter] & 0xffffff) | alphaInt;
}
}
Image i = new Image(arr, w, h);
i.opaqueTested = true;
i.opaque = false;
return i;
}
/**
* Creates a new image instance with the alpha channel of opaque/translucent
* pixels within the image using the new alpha value. Transparent (alpha == 0)
* pixels remain transparent. All other pixels will have the new alpha value.
*
* @param alpha New value for the entire alpha channel
* @param removeColor pixels matching this color are made transparent (alpha channel ignored)
* @return Translucent/Opaque image based on the alpha value and the pixels of
* this image
*/
public Image modifyAlpha(byte alpha, int removeColor) {
removeColor = removeColor & 0xffffff;
int w = image.getWidth();
int h = image.getHeight();
int size = w * h;
int[] arr = new int[size];
image.getRGB(arr, 0, w, 0, 0, w, h);
int alphaInt = (((int)alpha) << 24) & 0xff000000;
for(int iter = 0 ; iter < size ; iter++) {
if((arr[iter] & 0xff000000) != 0) {
arr[iter] = (arr[iter] & 0xffffff) | alphaInt;
if(removeColor == (0xffffff & arr[iter])) {
arr[iter] = 0;
}
}
}
Image i = new Image(arr, w, h);
i.opaqueTested = true;
i.opaque = false;
return i;
}
/**
* Returns a mirror instance of this image
*
* @return a mirror instance of this image
* @deprecated this method is no longer supported due to issues when mixing it with
* other methods such as rotate. Future versions of the API will provide an alternative
*/
public Image mirror() {
Image i = new Image(image);
if(transform != 0) {
switch(transform) {
case Sprite.TRANS_MIRROR:
i.transform = 0;
break;
case Sprite.TRANS_MIRROR_ROT180:
i.transform = Sprite.TRANS_ROT180;
break;
case Sprite.TRANS_MIRROR_ROT270:
i.transform = Sprite.TRANS_ROT270;
break;
case Sprite.TRANS_MIRROR_ROT90:
i.transform = Sprite.TRANS_ROT90;
break;
case Sprite.TRANS_NONE:
i.transform = Sprite.TRANS_MIRROR;
break;
case Sprite.TRANS_ROT180:
i.transform = Sprite.TRANS_MIRROR_ROT180;
break;
case Sprite.TRANS_ROT270:
i.transform = Sprite.TRANS_MIRROR_ROT270;
break;
case Sprite.TRANS_ROT90:
i.transform = Sprite.TRANS_MIRROR_ROT90;
break;
default:
throw new IllegalStateException("Image could not be mirrored, error code: " + transform);
}
} else {
i.transform = transform;
}
return i;
}
/**
* Rotates the given image array fast assuming this is a "right" angle
* divides by 90 degrees
*/
private int fastRotate(int degrees) {
// if we have a preexisting rotation...
switch(transform) {
case javax.microedition.lcdui.game.Sprite.TRANS_ROT90:
degrees += 90;
break;
case javax.microedition.lcdui.game.Sprite.TRANS_ROT180:
degrees += 180;
break;
case javax.microedition.lcdui.game.Sprite.TRANS_ROT270:
degrees += 270;
break;
}
switch((degrees % 360) / 90) {
case 0:
return 0;
// 90 degree angle
case 1:
return javax.microedition.lcdui.game.Sprite.TRANS_ROT90;
// 180 degree angle
case 2:
return javax.microedition.lcdui.game.Sprite.TRANS_ROT180;
// 270 degree angle
case 3:
return javax.microedition.lcdui.game.Sprite.TRANS_ROT270;
default:
throw new IllegalArgumentException("Fast rotate can't handle degrees = " + degrees);
}
}
/**
* Converts a newly loaded masked image into a translucent image. A masked image is an image file
* of even height that is two separate opaque images the top part is the actual image containing
* the opaque content. The bottom part is a mask that would be ovelayed as the alpha channel of
* the top part of the image. The red channel of the bottom part would just be assigned to the alpha
* portion of the top part thus allowing an image to contain translucency while being portable to
* different devices.
*
* @return Translucent image instance
* @deprecated translucency masks are no longer supported or necessary, use resources for portability
* and unification
*/
public Image extractTranslucentMask() {
int w = image.getWidth();
int h = image.getHeight();
int[] arr = new int[w * h];
image.getRGB(arr, 0, w, 0, 0, w, h);
int offset = h * w / 2;
for(int iter = 0 ; iter < offset ; iter++) {
// extract the red component from the bottom portion of the image
int alpha = arr[iter + offset] & 0xff0000;
// shift the alpha 8 bits to the left
// apply the alpha to the top portion of the image
arr[iter] = (arr[iter] & 0xffffff) | (alpha << 8);
}
return new Image(javax.microedition.lcdui.Image.createRGBImage(arr, w, h / 2, true));
}
/**
* creates an image from the given path based on MIDP's createImage(path)
*
* @param path
* @throws java.io.IOException
* @return newly created image object
*/
public static Image createImage(String path) throws IOException {
try {
return new Image(javax.microedition.lcdui.Image.createImage(path));
} catch(OutOfMemoryError err) {
// Images have a major bug on many phones where they sometimes throw
// an OOM with no reason. A system.gc followed by the same call over
// solves the problem. This has something to do with the fact that
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?