KJAVA在这里人气不算很旺,不过这磨灭不了我们这群热爱着J2ME开发的人们的激情。
?
关于这个截屏程序,是需要附加到你的项目中的,因为j2me的手机没听说双线程的。
?
此截屏程序的原理:
把缓冲画笔所在的画布img_buffer转成PNG格式保存到指定路径下,image转png需要一些插值加文件头的操作。
?
这段代码网上有,我也是copy过来进行创新的。
?
你需要做的是:
1.在你的canvas里定义截屏类的对象,初始值null。
2.在你的canvas里定义一个boolean变量,初始值true。
3.在你的canvas里的初始化或者构造方法里new 一个截屏类的对象。
4.在你的canvas里run方法里如同下面代码一样改造,repaint()方法就是重绘方法,c就是截屏类的实例,c.save()方法是保存图片的方法。
public void run() { while (true) { startTime = System.currentTimeMillis();// if(b_isPaint)// { repaint(); //重绘// }// else// {// mainForm.paint(gg);// c.save(img_buffer); //c是截屏类实例,save方法是保存图片方法,img_buffer是当前缓冲。// b_isPaint = true;// } timeTaken = System.currentTimeMillis() - startTime; if (timeTaken < 1000 / DefaultProperties.FPS) { try { Thread.sleep(1000 / DefaultProperties.FPS - timeTaken); } catch (Exception e) { e.printStackTrace(); } } } }
?
5.你想要以何种触发事件触发这个截屏方法,如果想要触摸屏点击触发,参考以下方法。其他触发方法照之改之。
protected void pointerPressed(int x, int y) {// if(x < 30 && x > 0 && y < 30 && y > 0)// {// b_isPaint = false;// color = 0;// }// if(b_isPaint) mainForm.pointerPressed(x, y);//程序主触屏事件 }
?
6.在你的程序里添加截屏类(CGAMG.java)? 第45行写你要保存的路径。
import javax.microedition.lcdui.*;import java.io.*;import javax.microedition.io.file.FileConnection;import javax.microedition.io.Connector;public class CGame extends Canvas { public void paint(Graphics g) { } //Image2Bytes by AnderLu //生成的byte[]数组可直接用于外部存储为.png格式的图片文件看图软件可直接打开 public static int IDATPOS; public static int haha = 0; public static byte[] HEADChunk = { (byte) 0x89, (byte) 0x50, (byte) 0x4E, (byte) 0x47, (byte) 0x0D, (byte) 0x0A, (byte) 0x1A, (byte) 0x0A, }; public static byte[] tRNSChunk = { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x74, (byte) 0x52, (byte) 0x4E, (byte) 0x53, (byte) 0x00, (byte) 0x40, (byte) 0xE6, (byte) 0xD8, (byte) 0x66, }; public static byte[] IENDChunk = { //PNGIEND (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x49, (byte) 0x45, (byte) 0x4E, (byte) 0x44, (byte) 0xAE, (byte) 0x42, (byte) 0x60, (byte) 0x82 }; Image img; public void save(Image im) { byte data[] = Image2Bytes(im); this.img = Image.createImage(data, 0, data.length); saveFile("file:///E:/jieping/" + haha +".png", data); //路径,haha变量递增 保存名为1.png,2.png haha++; } /**保存文件 * @path:路径 * @fileData:文件数据 * @return: 0:出现异常,1:保存成功 */ public int saveFile(String path, byte[] fileData) { FileConnection fc = null; try { fc = (FileConnection) Connector.open(path, Connector.READ_WRITE); if (!fc.exists()) { fc.create(); } OutputStream os = fc.openOutputStream(); os.write(fileData); os.flush(); os.close(); fc.close(); return 1; } catch (IOException ex) { ex.printStackTrace(); return 0; } } public byte[] Image2Bytes(Image img) { try { int w = img.getWidth(); int h = img.getHeight(); int offset = 0; byte buffer[] = new byte[(w * 4 + 1) * h + offset]; getImageBufferForImageARGB8888(img, buffer, w, h, offset); System.gc(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream dout = new DataOutputStream(baos); WritePng(dout, w, h, buffer, null, false, offset); byte[] data = baos.toByteArray(); writeCRC(data, 8); //更新IHDR CRC writeCRC(data, 33); //更新PLTE CRC writeCRC(data, IDATPOS); //更新IDAT CRC buffer = null; System.gc(); return data; } catch (IOException ex) { ex.printStackTrace(); return null; } } public static void writeCRC(byte[] data, int chunkpos) { int chunklen = ((data[chunkpos] & 0xFF) << 24) | ((data[chunkpos + 1] & 0xFF) << 16) | ((data[chunkpos + 2] & 0xFF) << 8) | (data[chunkpos + 3] & 0xFF); int sum = CRCChecksum(data, chunkpos + 4, 4 + chunklen) ^ 0xffffffff; int val = sum; int pos = chunkpos + 8 + chunklen; data[pos] = (byte) ((val & 0xFF000000) >> 24); data[pos + 1] = (byte) ((val & 0xFF0000) >> 16); data[pos + 2] = (byte) ((val & 0xFF00) >> 8); data[pos + 3] = (byte) (val & 0xFF); } public static int[] crc_table; //CRC 表 public static int CRCChecksum(byte[] buf, int off, int len) { int c = 0xffffffff; int n; if (crc_table == null) { int mkc; int mkn, mkk; crc_table = new int[256]; for (mkn = 0; mkn < 256; mkn++) { mkc = mkn; for (mkk = 0; mkk < 8; mkk++) { if ((mkc & 1) == 1) { mkc = 0xedb88320 ^ (mkc >>> 1); } else { mkc = mkc >>> 1; } } crc_table[mkn] = mkc; } } for (n = off; n < len + off; n++) { c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >>> 8); } return c; } public static long adler32(long adler, byte[] buf, int index, int len) { int BASE = 65521; int NMAX = 5552; //TODO remove this function at all if (buf == null) { return 1L; } long s1 = adler & 0xffff; long s2 = (adler >> 16) & 0xffff; int k; while (len > 0) { k = len < NMAX ? len : NMAX; len -= k; while (k >= 16) { s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; s1 += buf[index++] & 0xff; s2 += s1; k -= 16; } if (k != 0) { do { s1 += buf[index++] & 0xff; s2 += s1; } while (--k != 0); } s1 %= BASE; s2 %= BASE; } return (s2 << 16) | s1; } public static void WritePng(DataOutputStream output, int width, int height, byte[] buffer, byte[] colors, boolean Transparent, int offset) throws IOException { int adler = (int) adler32(1l, buffer, offset, buffer.length - offset); byte[] lenNlen = { //压缩块的LEN和NLEN信息 (byte) 0, (byte) 0xfa, (byte) 0x7e, (byte) 0x05, (byte) 0x81 }; IDATPOS = 0; output.write(HEADChunk); IDATPOS += HEADChunk.length; //写IHDR output.writeInt(13); //len output.writeInt(1229472850); //IHDR type code output.writeInt(width); //写宽度 output.writeInt(height); //写高度 output.writeByte(8); //1Bitdepth if (colors == null) { output.writeByte(6); //2ColorType } else { output.writeByte(3); //2ColorType } output.writeByte(0); //3CompressionMethod output.writeByte(0); //4Filter method output.writeByte(0); //5Interlace method output.writeInt(0); //写crc IDATPOS += 25; //写PLTE if (colors != null) { output.writeInt(colors.length); //len output.writeInt(1347179589); //type code output.write(colors); //data output.writeInt(0); //crc IDATPOS += colors.length + 12; } //写TRNS if (Transparent) { output.write(tRNSChunk); IDATPOS += tRNSChunk.length; } //写IDAT byte[] dpixels = buffer; int bufferlen = dpixels.length - offset; int blocklen = 32506; int blocknum = 1; if ((dpixels.length % blocklen) == 0) { blocknum = bufferlen / blocklen; } else { blocknum = (bufferlen / blocklen) + 1; } int IDATChunkLen = (bufferlen + 6 + blocknum * 5); output.writeInt(IDATChunkLen); //len output.writeInt(1229209940); //idat type code output.writeShort((short) 0x78da); //78da for (int i = 0; i < blocknum; i++) { int off = i * blocklen; int len = bufferlen - off; if (len >= blocklen) { len = blocklen; lenNlen[0] = (byte) 0; } else { lenNlen[0] = (byte) 1; } int msb = (len & 0xff); int lsb = (len >>> 8); lenNlen[1] = (byte) msb; lenNlen[2] = (byte) lsb; lenNlen[3] = (byte) (msb ^ 0xff); lenNlen[4] = (byte) (lsb ^ 0xff); output.write(lenNlen); output.write(dpixels, off + offset, len); } output.writeInt(adler); //IDAT adler output.writeInt(0); //IDAT crc output.write(IENDChunk); } public static void getImageBufferForImageARGB8888(Image img, byte[] rawByte, int w, int h, int off) { int n = off; int[] raw = new int[w]; for (int j = 0; j < h; j++) { img.getRGB(raw, 0, w, 0, j, w, 1); for (int i = 0; i < raw.length; i++) { int ARGB = raw[i]; int a = (ARGB & 0xff000000) >> 24; int r = (ARGB & 0xff0000) >> 16; int g = (ARGB & 0xff00) >> 8; int b = ARGB & 0xff; if (i % w == 0) { n += 1; } rawByte[n] = (byte) r; rawByte[n + 1] = (byte) g; rawByte[n + 2] = (byte) b; rawByte[n + 3] = (byte) a; n += 4; } } raw = null; System.gc(); }}
?
注意:截屏命名是以1、2、3、4数字++命名的,如1.png,2.png等等,该程序设计的触发截屏事件是点击屏幕左上角,这个根据具体需要随意改了,并且图片保存命名规则也需要完善下。
?
曾尝试过截屏的时候弄点提示,但这是万万不可的,在屏幕上出现任何提示都将会被截屏记录下来,所以我在写这个功能的时候,很是认真的考虑了截屏的完整性及安全性,只要触发了,程序会自动屏蔽所有操作等待截屏操作结束,结束后恢复,也就是说机器慢的,触发截屏了,你在点或者做其他的程序界面的操作,那都是不可能的,截屏生成保存文件这个过程结束后才可以。
?
附件:截屏类(其实就是把image对象转成png并保存到指定路径的方法)
另外我记得在真彩色png图中,PLTE, tRNS等块应该是可以省略的。