package greenfoot.importer.scratch;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
| A Scratch image resource, loaded from the Scratch Form class.
|
| @author neil
|
public class ScratchImage
extends ScratchObject{
private ScratchObject bitsRef;
private int w;
private int h;
private int d;
private int offset;
private BufferedImage img;
private ScratchObject paletteRef;
private Color[] palette;
private boolean isResolved = false;
| Constructs a ScratchImage using the data read from the file
| @param w Width of image
| @param h Height of image
| @param d Depth (number of *bits* (not bytes) per pixel)
| @param offset Offset (TODO work out how this is used)
| @param bitsRef Reference to byte array with raw compressed data
| @param paletteRef Reference to palette (array of colours)
|
public ScratchImage(int w, int h, int d, int offset, ScratchObject bitsRef, ScratchObject paletteRef)
{
this.w = w;
this.h = h;
this.d = d;
this.offset = offset;
this.bitsRef = bitsRef;
this.paletteRef = paletteRef;
}
| Resolves the references for bits and palette, and decodes the image
|
public ScratchObject resolve(ArrayList<ScratchObject> objects)
{
if (isResolved) return this;
if (paletteRef != null) {
ScratchObject resolvedPalette = paletteRef.resolve(objects);
ScratchObject[] pal = (ScratchObject[])resolvedPalette.getValue();
palette = new Color[pal.length];
for (int i = 0;i < pal.length;i++) {
palette[i] = (Color)pal[i].resolve(objects).getValue();
}
}
img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
ScratchObject resolved = bitsRef.resolve(objects);
if (resolved.getValue() instanceof int[]) {
int[] values = (int[])resolved.getValue();
for (int pos = 0; pos < values.length;pos++) {
setBitmapEntry(pos, values[pos]);
}
}
else if (resolved.getValue() instanceof byte[]) {
ByteArrayInputStream bitsInput = new ByteArrayInputStream((byte[]) resolved.getValue());
int bitmapPos = 0;
decodeLen(bitsInput);
for (int rawN = decodeLen(bitsInput);rawN != -1;rawN = decodeLen(bitsInput)) {
int wordCount = rawN >> 2;
switch (rawN & 0x3) {
case 0:
bitmapPos += wordCount;
break;
case 1: {
int b = bitsInput.read();
int x = (b << 24) | (b << 16) | (b << 8) | b;
int end = bitmapPos + wordCount;
while (bitmapPos < end){
setBitmapEntry(bitmapPos++, x);
}
}
break;
case 2: {
int x = 0;
for (int i = 0; i < 4; i++) {
x <<= 8;
x |= bitsInput.read();
}
int end = bitmapPos + wordCount;
while (bitmapPos < end){
setBitmapEntry(bitmapPos++, x);
}
}
break;
case 3: {
int end = bitmapPos + wordCount;
while (bitmapPos < end){
int x = 0;
for (int i = 0; i < 4; i++) {
x <<= 8;
x |= bitsInput.read();
}
setBitmapEntry(bitmapPos++, x);
}
}
break;
}
}
}
isResolved = true;
return this;
}
private void setBitmapEntry(int pos, int val)
{
final int pixelsPerWord = 32 / d;
for (int i = 0; i < pixelsPerWord;i++) {
int index = d == 32 ? val : val & ((1 << d) - 1);
int realWidth = (w + (pixelsPerWord - 1)) / pixelsPerWord;
int x = ((pos % realWidth) * pixelsPerWord) + (pixelsPerWord - i);
int y = pos / realWidth;
if (x < w && y < h) {
if (palette != null) {
img.setRGB(x, y, palette[index].getRGB());
}
else {
if (index >> 24 == 0 && (index & 0xFFFFFF) != 0) {
index |= 0xFF000000;
}
img.setRGB(x, y, index);
}
}
val >>= d;
}
}
| Decodes a count field.
| Anything above 0xE0 has its low bits (& 0x1F) merged with the next number
|
private int decodeLen(ByteArrayInputStream bitsInput)
{
int x = 0;
int first = bitsInput.read();
if (first == -1)
return -1;
if (first == 0xFF) {
for (int i = 0; i < 4; i++) {
x <<= 8;
x |= bitsInput.read();
}
return x;
}
else if (first >= 0xE0) {
x = (first & 0x1F) << 8;
x |= bitsInput.read();
}
else {
x = first;
}
return x;
}
public int getWidth()
{
return w;
}
public int getHeight()
{
return h;
}
public BufferedImage getBufferedImage()
{
return img;
}
}
top,
use,
map,
class ScratchImage
. ScratchImage
. resolve
. setBitmapEntry
. decodeLen
. getWidth
. getHeight
. getBufferedImage
281 neLoCode
+ 12 LoComm