package com.javaxyq.util; import java.awt.Image; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DirectColorModel; import java.awt.image.WritableRaster; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; import java.util.Scanner; import java.util.Vector; import com.javaxyq.core.Toolkit; import com.javaxyq.io.RandomAcessInputStream; /** * was(tcp/tca)������ * * @author ����ΰ * @date */ public class WASDecoder { static final int TYPE_ALPHA = 0x00;// ǰ2λ static final int TYPE_ALPHA_PIXEL = 0x20;// ǰ3λ 0010 0000 static final int TYPE_ALPHA_REPEAT = 0x00;// ǰ3λ static final int TYPE_FLAG = 0xC0;// 2����ǰ2λ 1100 0000 static final int TYPE_PIXELS = 0x40;// ����ǰ2λ 0100 0000 static final int TYPE_REPEAT = 0x80;// 1000 0000 static final int TYPE_SKIP = 0xC0; // 1100 0000 /** �ļ�ͷ��� */ static final String WAS_FILE_TAG = "SP"; static final int TCP_HEADER_SIZE = 12; // Reference Pixel(���ҵ�) private int refPixelX; private int refPixelY; /** ������������ */ private int animCount; /** ������֡�� */ private int frameCount; /** �ļ�ͷ��С */ private int headerSize; /** ԭʼ��ɫ�� */ private short[] originPalette; /** ��ǰ��ɫ�� */ private short[] palette; /** ������ */ private int width; /** ����߶� */ private int height; private int[] schemeIndexs; private Section[] sections; private List<WASFrame> frames; private RandomAcessInputStream randomIn; public WASDecoder() { palette = new short[256]; originPalette = new short[256]; frames = new ArrayList<WASFrame>(); } /** * ������ɫ���� */ public void coloration(int[] schemeIndexs) { for (int i = 0; i < schemeIndexs.length; i++) { this.coloration(i, schemeIndexs[i]); } this.schemeIndexs = schemeIndexs; } public void loadColorationProfile(String filename) { InputStream is = Toolkit.getInputStream(filename); if (is != null) { Scanner scanner = new Scanner(is); scanner.useDelimiter("(\r\n)|(\n\r)|[\n\r=]"); // section String strLine = scanner.next(); String[] values = strLine.split(" ");// StringUtils.split(strLine); int sectionCount = Integer.parseInt(values[0]); // section ���� int[] sectionBounds = new int[sectionCount + 1]; for (int i = 0; i < sectionBounds.length; i++) { sectionBounds[i] = Integer.parseInt(values[i + 1]); } // create section Section[] sections = new Section[sectionCount]; for (int i = 0; i < sections.length; i++) { Section section = new Section(sectionBounds[i], sectionBounds[i + 1]); int schemeCount = Integer.parseInt(scanner.next()); for (int s = 0; s < schemeCount; s++) { String[] strSchemes = new String[3]; strSchemes[0] = scanner.next(); strSchemes[1] = scanner.next(); strSchemes[2] = scanner.next(); ColorationScheme scheme = new ColorationScheme(strSchemes); section.addScheme(scheme); } sections[i] = section; } setSections(sections); } } public int[] getSchemeIndexs() { return schemeIndexs; } public Section[] getSections() { return sections; } public void setSections(Section[] sections) { this.sections = sections; } public int getSectionCount() { return this.sections.length; } public int getSchemeCount(int section) { return this.sections[section].getSchemeCount(); } public short[] getOriginPalette() { return originPalette; } /** * �޸�ij�����ε���ɫ * * @param sectionIndex * @param schemeIndex */ public void coloration(int sectionIndex, int schemeIndex) { if (this.sections == null) { return; } Section section = this.sections[sectionIndex]; ColorationScheme scheme = section.getScheme(schemeIndex); for (int i = section.getStart(); i < section.getEnd(); i++) { this.palette[i] = scheme.mix(this.originPalette[i]); } } // public void setColorSections(Section[] sections) { // this.sections = sections; // } /** * ��ͼ�����ݻ���Image�� */ public void draw(int[] pixels, WritableRaster raster, int x, int y, int w, int h) { int[] iArray = new int[4]; for (int y1 = 0; y1 < h && y1 + y < height; y1++) { for (int x1 = 0; x1 < w && x1 + x < width; x1++) { // red 5 iArray[0] = ((pixels[y1*w +x1] >>> 11) & 0x1F) << 3; // green 6 iArray[1] = ((pixels[y1*w +x1] >>> 5) & 0x3f) << 2; // blue 5 iArray[2] = (pixels[y1*w +x1] & 0x1F) << 3; // alpha 5 iArray[3] = ((pixels[y1*w +x1] >>> 16) & 0x1f) << 3; // iArray[3] = ((pixels[y1][x1] >>> 16) & 0x1f) *0xff/0x1f; // if(iArray[3]>0)iArray[3] += 7; try { raster.setPixel(x1 + x, y1 + y, iArray); } catch (Exception e) { System.out.printf("%s: x=%s,y=%s,pixel=[%s,%s,%s,%s]\n", e.getMessage(), x1 + x, y1 + y, iArray[0], iArray[1], iArray[2], iArray[3]); // e.printStackTrace(); } } } } private int[] convert(int[] pixels) { int[] data = new int[pixels.length*4]; for (int i = 0; i < pixels.length; i++) { // red 5 data[i*4] = ((pixels[i] >>> 11) & 0x1F) << 3; // green 6 data[i*4+1] = ((pixels[i] >>> 5) & 0x3f) << 2; // blue 5 data[i*4+2] = (pixels[i] & 0x1F) << 3; // alpha 5 data[i*4+3] = ((pixels[i] >>> 16) & 0x1f) << 3; } return data; } public short[] getPalette() { return palette; } public int getRefPixelX() { return refPixelX; } public int getRefPixelY() { return refPixelY; } public BufferedImage getFrame(int index) { WASFrame frame = this.frames.get(index); try { if (frame.getPixels() == null) { frame.setPixels(parse(frame)); } } catch (IOException e) { e.printStackTrace(); return null; } if (this.frameCount == 1) {// ������֡������ƫ������ return createImage(refPixelX, refPixelY, frame.getWidth(), frame.getHeight(), frame.getPixels()); } else { return createImage(frame.getX(), frame.getY(), frame.getWidth(), frame.getHeight(), frame.getPixels()); } } /** * parse frame every time * * @param index * @return */ public BufferedImage getFrameImage(int index) { WASFrame frame = this.frames.get(index); try { if (this.frameCount == 1) { return createImage(refPixelX, refPixelY, frame.getWidth(), frame.getHeight(), parse(frame)); } else { return createImage(frame.getX(), frame.getY(), frame.getWidth(), frame.getHeight(), parse(frame)); } } catch (IOException e) { e.printStackTrace(); return null; } } public BufferedImage getFullFrame(int index) { WASFrame frame = this.frames.get(index); try { if (frame.getPixels() == null) { frame.setPixels(parse(frame)); } } catch (IOException e) { e.printStackTrace(); return null; } return createImage(refPixelX, refPixelY, frame.getWidth(), frame.getHeight(), frame.getPixels()); } private int[] parse(WASFrame frame) throws IOException { return this .parse(randomIn, frame.getFrameOffset(), frame.getLineOffsets(), frame.getWidth(), frame.getHeight()); } public Vector<Image> getFrames() { // TODO return null; } public int getDelay(int index) { return this.frames.get(index).getDelay(); } public int getHeight() { return height; } public int getWidth() { return width; } public int getAnimCount() { return animCount; } public int getFrameCount() { return frameCount; } public void load(InputStream in) throws IllegalStateException, IOException { randomIn = prepareInputStream(in); // was ��Ϣ headerSize = randomIn.readUnsignedShort(); animCount = randomIn.readUnsignedShort(); frameCount = randomIn.readUnsignedShort(); width = randomIn.readUnsignedShort(); height = randomIn.readUnsignedShort(); refPixelX = randomIn.readUnsignedShort(); refPixelY = randomIn.readUnsignedShort(); // ��ȡ֡��ʱ��Ϣ int len = headerSize - TCP_HEADER_SIZE; if (len < 0) { throw new IllegalStateException("֡��ʱ��Ϣ����: " + len); } int[] delays = new int[len]; for (int i = 0; i < len; i++) { delays[i] = randomIn.read(); } // ��ȡ��ɫ�� randomIn.seek(headerSize + 4); for (int i = 0; i < 256; i++) { originPalette[i] = randomIn.readUnsignedShort(); } // ���Ƶ�ɫ�� System.arraycopy(originPalette, 0, palette, 0, 256); // ֡ƫ���б� int[] frameOffsets = new int[animCount * frameCount]; randomIn.seek(headerSize + 4 + 512); for (int i = 0; i < animCount; i++) { for (int n = 0; n < frameCount; n++) { frameOffsets[i * frameCount + n] = randomIn.readInt(); } } // ֡��Ϣ int frameX, frameY, frameWidth, frameHeight; for (int i = 0; i < animCount; i++) { for (int n = 0; n < frameCount; n++) { int offset = frameOffsets[i * frameCount + n]; if (offset == 0) continue;// blank frame randomIn.seek(offset + headerSize + 4); frameX = randomIn.readInt(); frameY = randomIn.readInt(); frameWidth = randomIn.readInt(); frameHeight = randomIn.readInt(); // ����������ƫ�� int[] lineOffsets = new int[frameHeight]; for (int l = 0; l < frameHeight; l++) { lineOffsets[l] = randomIn.readInt(); } // ����֡���� int delay = 1; if (i < delays.length) { delay = delays[i]; } WASFrame frame = new WASFrame(frameX, frameY, frameWidth, frameHeight, delay, offset, lineOffsets); this.frames.add(frame); // ����֡���� // int[][] pixels = parse(randomIn, offset, lineOffsets, // frameWidth, frameHeight); // createImage(frameX, frameY, frameWidth, frameHeight, pixels); } } } private static final int DCM_565_ALPHA_MASK = 0x1f0000; private static final int DCM_565_RED_MASK = 0xf800; private static final int DCM_565_GRN_MASK = 0x07E0; private static final int DCM_565_BLU_MASK = 0x001F; public BufferedImage createImage(int x, int y, int frameWidth, int frameHeight, int[] pixels) { // use sprite's width & height BufferedImage image = new BufferedImage(this.width, this.height, BufferedImage.TYPE_INT_ARGB); draw(pixels, image.getRaster(), refPixelX - x, refPixelY - y, frameWidth, frameHeight); return image; // return createDirectImage(x, y, frameWidth, frameHeight, pixels); } public BufferedImage createDirectImage(int x, int y, int frameWidth, int frameHeight, int[] pixels) { ColorModel colorModel; WritableRaster raster; // colorModel = new DirectColorModel(21, DCM_565_RED_MASK, DCM_565_GRN_MASK, DCM_565_BLU_MASK, DCM_565_ALPHA_MASK); colorModel = new DirectColorModel(32, 0xff0000, 0xff00, 0xff, 0xff000000); raster = colorModel.createCompatibleWritableRaster(width, height); x = refPixelX - x; y = refPixelY - y; frameWidth = Math.min(frameWidth,width-x); frameHeight = Math.min(frameHeight,height-y); //raster.setDataElements(x, y, frameWidth, frameHeight, pixels); raster.setPixels(x, y, frameWidth, frameHeight, convert(pixels)); boolean isRasterPremultiplied = true; BufferedImage image = new BufferedImage(colorModel, raster, isRasterPremultiplied, null); return image; } private RandomAcessInputStream prepareInputStream(InputStream in) throws IOException, IllegalStateException { byte[] buf; RandomAcessInputStream randomIn; buf = new byte[2]; in.mark(10); in.read(buf, 0, 2); String flag = new String(buf, 0, 2); if (!WAS_FILE_TAG.equals(flag)) { throw new IllegalStateException("�ļ�ͷ��־����:" + print(buf)); } if (in instanceof RandomAcessInputStream) { in.reset(); randomIn = (RandomAcessInputStream) in; } else { byte[] buf2 = new byte[in.available() + buf.length]; System.arraycopy(buf, 0, buf2, 0, buf.length); int a = 0, count = buf.length; while (in.available() > 0) { a = in.read(buf2, count, in.available()); count += a; } // construct a new seekable stream randomIn = new RandomAcessInputStream(buf2); } // skip header randomIn.seek(2); return randomIn; } private String print(byte[] buf) { String output = "["; for (byte b : buf) { output += b; output += ","; } output += "]"; return output; } public void load(String filename) throws Exception { // InputStream fileIn = getClass().getResourceAsStream(filename); // File file = new File(filename); // InputStream fileIn = new FileInputStream(file); load(Toolkit.getInputStream(filename)); } public void load(File file) throws IllegalStateException, FileNotFoundException, IOException { load(new FileInputStream(file)); } private int[] parse(RandomAcessInputStream in, int frameOffset, int[] lineOffsets, int frameWidth, int frameHeight) throws IOException { int[] pixels = new int[frameHeight*frameWidth]; int b, x, c; int index; int count; for (int y = 0; y < frameHeight; y++) { x = 0; in.seek(lineOffsets[y] + frameOffset + headerSize + 4); while (x < frameWidth) { b = in.read(); switch ((b & TYPE_FLAG)) { case TYPE_ALPHA: if ((b & TYPE_ALPHA_PIXEL) > 0) { index = in.read(); c = palette[index]; // palette[index]=0; pixels[y*frameWidth+ x++] = c + ((b & 0x1F) << 16); } else if (b != 0) {// ??? count = b & 0x1F;// count b = in.read();// alpha index = in.read(); c = palette[index]; // palette[index]=0; for (int i = 0; i < count; i++) { pixels[y*frameWidth+ x++] = c + ((b & 0x1F) << 16); } } else {// block end if (x > frameWidth) { System.err.println("block end error: [" + y + "][" + x + "/" + frameWidth + "]"); continue; } else if (x == 0) { // System.err.println("x==0"); } else { x = frameWidth;// set the x value to break the // 'while' sentences } } break; case TYPE_PIXELS: count = b & 0x3F; for (int i = 0; i < count; i++) { index = in.read(); pixels[y*frameWidth+ x++] = palette[index] + (0x1F << 16); // palette[index]=0; } break; case TYPE_REPEAT: count = b & 0x3F; index = in.read(); c = palette[index]; // palette[index]=0; for (int i = 0; i < count; i++) { pixels[y*frameWidth+ x++] = c + (0x1F << 16); } break; case TYPE_SKIP: count = b & 0x3F; x += count; break; } } if (x > frameWidth) System.err.println("block end error: [" + y + "][" + x + "/" + frameWidth + "]"); } return pixels; } public void resetPalette() { System.arraycopy(originPalette, 0, palette, 0, 256); } }