Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores
* CA 94065 USA or visit www.oracle.com if you need additional information or
* have any questions.
*/
package com.codename1.ui;
import com.codename1.io.Log;
import com.codename1.ui.geom.Dimension;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* An indexed image is an image "compressed" in memory to occupy as little memory
* as possible in this sense it is slower to draw and only a single indexed image
* can be drawn at any given time. However, this allows images with low color counts
* to use as little as one byte per pixel which can save up to 4 times of the memory
* overhead.
*
* @deprecated This class should no longer be referenced directly. Use Image.createIndexed instead
* @author Shai Almog
*/
class IndexedImage extends Image {
private int width;
private int height;
// package protected for access by the resource editor
byte[] imageDataByte;
int[] palette;
/**
* Creates an indexed image with byte data
*
* @param width image width
* @param height image height
* @param palette the color palette to use with the byte data
* @param data byte data containing palette offsets to map to ARGB colors
* @deprecated use Image.createIndexed instead
*/
public IndexedImage(int width, int height, int[] palette, byte[] data) {
super(null);
this.width = width;
this.height = height;
this.palette = palette;
this.imageDataByte = data;
initOpaque();
}
private void initOpaque() {
if(palette != null) {
int plen = palette.length;
for(int iter = 0 ; iter < plen ; iter++) {
if((palette[iter] & 0xff000000) != 0xff000000) {
setOpaque(false);
return;
}
}
setOpaque(true);
} else {
setOpaque(false);
}
}
/**
* Converts an image to a package image after which the original image can be GC'd
*/
private IndexedImage(int width, int height, int[] palette, int[] rgb) {
super(null);
this.width = width;
this.height = height;
this.palette = palette;
// byte based package image
imageDataByte = new byte[width * height];
int ilen = imageDataByte.length;
for(int iter = 0 ; iter < ilen ; iter++) {
imageDataByte[iter] = (byte)paletteOffset(rgb[iter]);
}
initOpaque();
}
/**
* Finds the offset within the palette of the given rgb value
*
* @param value ARGB value from the image
* @return offset within the palette array
*/
private int paletteOffset(int rgb) {
int plen = palette.length;
for(int iter = 0 ; iter < plen ; iter++) {
if(rgb == palette[iter]) {
return iter;
}
}
throw new IllegalStateException("Invalid palette request in paletteOffset");
}
/**
* Packs the image loaded by MIDP
*
* @param imageName a name to load using Image.createImage()
* @return a packed image
* @throws IOException when create fails
*/
public static Image pack(String imageName) throws IOException {
return pack(Image.createImage(imageName));
}
/**
* {@inheritDoc}
*/
public Image subImage(int x, int y, int width, int height, boolean processAlpha) {
byte[] arr = new byte[width * height];
int alen = arr.length;
for(int iter = 0 ; iter < alen ; iter++) {
int destY = iter / width;
int destX = iter % width;
int offset = x + destX + ((y + destY) * this.width);
arr[iter] = imageDataByte[offset];
}
return new IndexedImage(width, height, palette, arr);
}
/**
* Unsupported in the current version, this method will be implemented in a future release
*/
public Image rotate(int degrees) {
throw new RuntimeException("The rotate method is not supported by indexed images at the moment");
}
/**
* {@inheritDoc}
*/
public Image modifyAlpha(byte alpha) {
int[] newPalette = new int[palette.length];
System.arraycopy(palette, 0, newPalette, 0, palette.length);
int alphaInt = (((int)alpha) << 24) & 0xff000000;
int plen = palette.length;
for(int iter = 0 ; iter < plen ; iter++) {
if((palette[iter] & 0xff000000) != 0) {
newPalette[iter] = (palette[iter] & 0xffffff) | alphaInt;
}
}
return new IndexedImage(width, height, newPalette, imageDataByte);
}
/**
* This method is unsupported in this image type
*/
public Graphics getGraphics() {
throw new RuntimeException("Indexed image objects are immutable");
}
/**
* {@inheritDoc}
*/
void getRGB(int[] rgbData,
int offset,
int x,
int y,
int width,
int height){
// need to support scanlength???
int startPoint = y * this.width + x;
for(int rows = 0 ; rows < height ; rows++) {
int currentRow = rows * width;
for(int columns = 0 ; columns < width ; columns++) {
int i = imageDataByte[startPoint + columns] & 0xff;
rgbData[offset + currentRow + columns] = palette[i];
}
startPoint += this.width;
}
}
/**
* Packs the source rgba image and returns null if it fails
*
* @param rgb array containing ARGB data
* @param width width of the image in the rgb array
* @param height height of the image
* @return a packed image or null
*/
public static IndexedImage pack(int[] rgb, int width, int height) {
int arrayLength = width * height;
// using a Vector is slower for a small scale device and this is mission critical code
int[] tempPalette = new int[256];
int paletteLocation = 0;
for(int iter = 0 ; iter < arrayLength ; iter++) {
int current = rgb[iter];
if(!contains(tempPalette, paletteLocation, current)) {
if(paletteLocation > 255) {
return null;
}
tempPalette[paletteLocation] = current;
paletteLocation++;
}
}
// we need to "shrink" the palette array
if(paletteLocation != tempPalette.length) {
int[] newArray = new int[paletteLocation];
System.arraycopy(tempPalette, 0, newArray, 0, paletteLocation);
tempPalette = newArray;
}
IndexedImage i = new IndexedImage(width, height, tempPalette, rgb);
return i;
}
/**
* Tries to pack the given image and would return the packed image or source
* image if packing failed
*
* @param sourceImage the image which would be converted to a packed image if possible
* @return the source image if packing failed or a newly packed image if it succeeded
*/
public static Image pack(final Image sourceImage) {
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
int[] rgb = sourceImage.getRGBCached();
Image i = pack(rgb, width, height);
if(i == null) {
return sourceImage;
}
return i;
}
/**
* Searches the array up to "length" and returns true if value is within the
* array up to that point.
*/
private static boolean contains(int[] array, int length, int value) {
for(int iter = 0 ; iter < length ; iter++) {
if(array[iter] == value) {
return true;
}
}
return false;
}
static int[] lineCache;
/**
* {@inheritDoc}
*/
protected void drawImage(Graphics g, Object nativeGraphics, int x, int y) {
if(lineCache == null || lineCache.length < width * 3) {
lineCache = new int[width * 3];
}
// for performance we can calculate the visible drawing area so we don't have to
// calculate the whole array
int clipY = g.getClipY();
int clipBottomY = g.getClipHeight() + clipY;
int firstLine = 0;
int lastLine = height;
if(clipY > y) {
firstLine = clipY - y;
}
if(clipBottomY < y + height) {
lastLine = clipBottomY - y;
}
for(int line = firstLine ; line < lastLine ; line += 3) {
int currentPos = line * width;
int rowsToDraw = Math.min(3, height - line);
int amount = width * rowsToDraw;
for(int position = 0 ; position < amount ; position++) {
int i = imageDataByte[position + currentPos] & 0xff;
lineCache[position] = palette[i];
}
g.drawRGB(lineCache, 0, x, y + line, width, rowsToDraw, true);
}
}
/**
* {@inheritDoc}
*/
public int getWidth() {
return width;
}
/**
* {@inheritDoc}
*/
public int getHeight() {
return height;
}
/**
* {@inheritDoc}
*/
public void scale(int width, int height) {
IndexedImage p = (IndexedImage)scaled(width, height);
this.imageDataByte = p.imageDataByte;
this.width = width;
this.height = height;
}
/**
* {@inheritDoc}
*/
public Image scaled(int width, int height) {
int srcWidth = getWidth();
int srcHeight = getHeight();
// no need to scale
if(srcWidth == width && srcHeight == height){
return this;
}
Dimension d = new Dimension(width, height);
Image i = getCachedImage(d);
// currently we only support byte data...
i = new IndexedImage(width, height, palette, scaleArray(imageDataByte, width, height));
cacheImage(d, i);
return i;
}
byte[] scaleArray(byte[] sourceArray, int width, int height) {
int srcWidth = getWidth();
int srcHeight = getHeight();
// no need to scale
if(srcWidth == width && srcHeight == height){
return sourceArray;
}
byte[] destinationArray = new byte[width * height];
//Horizontal Resize
int yRatio = (srcHeight << 16) / height;
int xRatio = (srcWidth << 16) / width;
int xPos = xRatio / 2;
int yPos = yRatio / 2;
for (int x = 0; x < width; x++) {
int srcX = xPos >> 16;
for(int y = 0 ; y < height ; y++) {
int srcY = yPos >> 16;
int destPixel = x + y * width;
int srcPixel = srcX + srcY * srcWidth;
if((destPixel >= 0 && destPixel < destinationArray.length) &&
(srcPixel >= 0 && srcPixel < sourceArray.length)) {
destinationArray[destPixel] = sourceArray[srcPixel];
}
yPos += yRatio;
}
yPos = yRatio / 2;
xPos += xRatio;
}
return destinationArray;
}
/**
* {@inheritDoc}
*/
int[] getRGBImpl() {
int rlen = width * height;
int[] rgb = new int[rlen];
for(int iter = 0 ; iter < rlen ; iter++) {
int i = imageDataByte[iter] & 0xff;
rgb[iter] = palette[i];
}
return rgb;
}
/**
* Retrieves the palette for the indexed image drawing
*
* @return the palette data
*/
public final int[] getPalette() {
return palette;
}
/**
* Retrieves the image data as offsets into the palette array
*
* @return the image data
*/
public final byte[] getImageDataByte() {
return imageDataByte;
}
/**
* This method allows us to store a package image into a persistent stream easily
* thus allowing us to store the image in RMS.
*
* @return a byte array that can be loaded using the load method
*/
public byte[] toByteArray() {
try {
ByteArrayOutputStream array = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(array);
out.writeShort(width);
out.writeShort(height);
out.writeByte(palette.length);
int plen = palette.length;
for (int iter = 0; iter < plen; iter++) {
out.writeInt(palette[iter]);
}
out.write(imageDataByte);
out.close();
return array.toByteArray();
} catch (IOException ex) {
// will never happen since IO is purely in memory
ex.printStackTrace();
return null;
}
}
/**
* Loads a packaged image that was stored in a stream using the toByteArray method
*
* @param data previously stored image data
* @return newly created packed image
*/
public static IndexedImage load(byte[] data) {
try {
DataInputStream input = new DataInputStream(new ByteArrayInputStream(data));
int width = input.readShort();
int height = input.readShort();
int[] palette = new int[input.readByte() & 0xff];
int plen = palette.length;
for (int iter = 0; iter < plen; iter++) {
palette[iter] = input.readInt();
}
byte[] arr = new byte[width * height];
input.readFully(arr);
return new IndexedImage(width, height, palette, arr);
} catch (IOException ex) {
Log.e(ex);
return null;
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean requiresDrawImage() {
return true;
}
}