开发者的天空

 

 

搜索
开发者的天空 论坛 移动编程和手机应用开发 使用J2ME实现手机截屏功能
查看: 1665|回复: 1
go

[JavaME] 使用J2ME实现手机截屏功能  

Rank: 75Rank: 75Rank: 75

发表于 2010-7-12 21:13 |显示全部帖子
在电脑上,我们可以很方便的通过键盘的PrintScreen键了截取当前屏幕,使用程序来截取当前屏幕并保存的代码也有很多。但是在手机上,并没有PrintScreen这样的键,还好我们可以使用编程来实现截屏的功能。在实际使用的时候,我们需要将这个程序附加到实际的项目中,因为到现在为止我还没有听说那个j2me手机是双线程的。


工作原理:
把缓冲画笔所在的画布img_buffer转成PNG格式保存到指定路径下,image转png需要一些插值加文件头的操作。

具体实现
下面的代码也是我从网上找来的,并根据自己的需要稍稍修改了一下。

你需要做的是:

1.在你的canvas里定义截屏类的对象,初始值null。

2.在你的canvas里定义一个boolean变量,初始值true。

3.在你的canvas里的初始化或者构造方法里new 一个截屏类的对象。

4.在你的canvas里run方法里如同下面代码一样改造,repaint()方法就是重绘方法,c就是截屏类的实例,c.save()方法是保存图片的方法。
  1. public void run() {
  2.                 while (true) {
  3.                         startTime = System.currentTimeMillis();
  4. //                        if(b_isPaint)
  5. //                        {
  6.                                 repaint();        //重绘
  7. //                        }
  8. //                        else
  9. //                        {
  10. //                                mainForm.paint(gg);
  11. //                                c.save(img_buffer);        //c是截屏类实例,save方法是保存图片方法,img_buffer是当前缓冲。
  12. //                                b_isPaint = true;
  13. //                        }
  14.                         timeTaken = System.currentTimeMillis() - startTime;
  15.                         if (timeTaken < 1000 / DefaultProperties.FPS) {
  16.                                 try {
  17.                                         Thread.sleep(1000 / DefaultProperties.FPS - timeTaken);
  18.                                 } catch (Exception e) {
  19.                                         e.printStackTrace();
  20.                                 }
  21.                         }
  22.                 }
  23.         }
复制代码
5.你想要以何种触发事件触发这个截屏方法,如果想要触摸屏点击触发,参考以下方法。其他触发方法照之改之
  1. protected void pointerPressed(int x, int y) {  
  2. //      if(x < 30 && x > 0 && y < 30 && y > 0)  
  3. //      {  
  4. //          b_isPaint = false;  
  5. //          color = 0;  
  6. //      }  
  7. //      if(b_isPaint)  
  8.              mainForm.pointerPressed(x, y);//程序主触屏事件  
  9.      }  
复制代码
6.在你的程序里添加截屏类(CGAMG.java)  第45行写你要保存的路径。
  1. import javax.microedition.lcdui.*;
  2. import java.io.*;
  3. import javax.microedition.io.file.FileConnection;
  4. import javax.microedition.io.Connector;

  5. public class CGame extends Canvas {
  6.         public void paint(Graphics g)
  7.         {
  8.         }
  9.     //Image2Bytes by AnderLu
  10.     //生成的byte[]数组可直接用于外部存储为.png格式的图片文件看图软件可直接打开
  11.     public static int IDATPOS;
  12.     public static int haha = 0;
  13.     public static byte[] HEADChunk = {
  14.                                      (byte) 0x89, (byte) 0x50,
  15.                                      (byte) 0x4E, (byte) 0x47,
  16.                                      (byte) 0x0D, (byte) 0x0A,
  17.                                      (byte) 0x1A, (byte) 0x0A,
  18.     };
  19.     public static byte[] tRNSChunk = {
  20.                                      (byte) 0x00, (byte) 0x00,
  21.                                      (byte) 0x00, (byte) 0x01,
  22.                                      (byte) 0x74, (byte) 0x52,
  23.                                      (byte) 0x4E, (byte) 0x53,
  24.                                      (byte) 0x00,
  25.                                      (byte) 0x40, (byte) 0xE6,
  26.                                      (byte) 0xD8, (byte) 0x66,
  27.     };
  28.     public static byte[] IENDChunk = {
  29.                                      //PNGIEND
  30.                                      (byte) 0x00, (byte) 0x00,
  31.                                      (byte) 0x00, (byte) 0x00,
  32.                                      (byte) 0x49, (byte) 0x45,
  33.                                      (byte) 0x4E, (byte) 0x44,
  34.                                      (byte) 0xAE, (byte) 0x42,
  35.                                      (byte) 0x60, (byte) 0x82
  36.     };
  37.     Image img;
  38.     public void save(Image im)
  39.     {
  40.         byte data[] = Image2Bytes(im);
  41.         this.img = Image.createImage(data, 0, data.length);

  42.         
  43.         saveFile("file:///E:/jieping/" + haha +".png", data);        //路径,haha变量递增 保存名为1.png,2.png
  44.         haha++;
  45.     }


  46.     /**保存文件
  47.      * @path:路径
  48.      * @fileData:文件数据
  49.      * @return: 0:出现异常,1:保存成功
  50.      */
  51.     public int saveFile(String path, byte[] fileData) {
  52.         FileConnection fc = null;
  53.         try {
  54.             fc = (FileConnection) Connector.open(path, Connector.READ_WRITE);
  55.             if (!fc.exists()) {
  56.                 fc.create();
  57.             }
  58.             OutputStream os = fc.openOutputStream();
  59.             os.write(fileData);
  60.             os.flush();
  61.             os.close();
  62.             fc.close();
  63.             return 1;

  64.         } catch (IOException ex) {
  65.             ex.printStackTrace();
  66.             return 0;
  67.         }
  68.     }

  69.     public byte[] Image2Bytes(Image img) {
  70.         try {
  71.             int w = img.getWidth();
  72.             int h = img.getHeight();
  73.             int offset = 0;
  74.             byte buffer[] = new byte[(w * 4 + 1) * h + offset];
  75.             getImageBufferForImageARGB8888(img, buffer, w, h, offset);
  76.             System.gc();
  77.             ByteArrayOutputStream baos = new ByteArrayOutputStream();
  78.             DataOutputStream dout = new DataOutputStream(baos);
  79.             WritePng(dout, w, h, buffer, null, false, offset);
  80.             byte[] data = baos.toByteArray();
  81.             writeCRC(data, 8); //更新IHDR CRC
  82.             writeCRC(data, 33); //更新PLTE CRC
  83.             writeCRC(data, IDATPOS); //更新IDAT CRC
  84.             buffer = null;
  85.             System.gc();
  86.             return data;
  87.         } catch (IOException ex) {
  88.             ex.printStackTrace();
  89.             return null;
  90.         }
  91.     }

  92.     public static void writeCRC(byte[] data, int chunkpos) {
  93.         int chunklen = ((data[chunkpos] & 0xFF) << 24)
  94.                        | ((data[chunkpos + 1] & 0xFF) << 16)
  95.                        | ((data[chunkpos + 2] & 0xFF) << 8)
  96.                        | (data[chunkpos + 3] & 0xFF);

  97.         int sum = CRCChecksum(data, chunkpos + 4, 4 + chunklen) ^ 0xffffffff;
  98.         int val = sum;
  99.         int pos = chunkpos + 8 + chunklen;
  100.         data[pos] = (byte) ((val & 0xFF000000) >> 24);
  101.         data[pos + 1] = (byte) ((val & 0xFF0000) >> 16);
  102.         data[pos + 2] = (byte) ((val & 0xFF00) >> 8);
  103.         data[pos + 3] = (byte) (val & 0xFF);
  104.     }

  105.     public static int[] crc_table; //CRC 表
  106.     public static int CRCChecksum(byte[] buf, int off, int len) {
  107.         int c = 0xffffffff;
  108.         int n;
  109.         if (crc_table == null) {
  110.             int mkc;
  111.             int mkn, mkk;
  112.             crc_table = new int[256];
  113.             for (mkn = 0; mkn < 256; mkn++) {
  114.                 mkc = mkn;
  115.                 for (mkk = 0; mkk < 8; mkk++) {
  116.                     if ((mkc & 1) == 1) {
  117.                         mkc = 0xedb88320 ^ (mkc >>> 1);
  118.                     } else {
  119.                         mkc = mkc >>> 1;
  120.                     }
  121.                 }
  122.                 crc_table[mkn] = mkc;
  123.             }
  124.         }
  125.         for (n = off; n < len + off; n++) {
  126.             c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >>> 8);
  127.         }
  128.         return c;
  129.     }

  130.     public static long adler32(long adler, byte[] buf, int index, int len) {
  131.         int BASE = 65521;
  132.         int NMAX = 5552;
  133.         //TODO remove this function at all
  134.         if (buf == null) {
  135.             return 1L;
  136.         }

  137.         long s1 = adler & 0xffff;
  138.         long s2 = (adler >> 16) & 0xffff;
  139.         int k;

  140.         while (len > 0) {
  141.             k = len < NMAX ? len : NMAX;
  142.             len -= k;
  143.             while (k >= 16) {
  144.                 s1 += buf[index++] & 0xff;
  145.                 s2 += s1;
  146.                 s1 += buf[index++] & 0xff;
  147.                 s2 += s1;
  148.                 s1 += buf[index++] & 0xff;
  149.                 s2 += s1;
  150.                 s1 += buf[index++] & 0xff;
  151.                 s2 += s1;
  152.                 s1 += buf[index++] & 0xff;
  153.                 s2 += s1;
  154.                 s1 += buf[index++] & 0xff;
  155.                 s2 += s1;
  156.                 s1 += buf[index++] & 0xff;
  157.                 s2 += s1;
  158.                 s1 += buf[index++] & 0xff;
  159.                 s2 += s1;
  160.                 s1 += buf[index++] & 0xff;
  161.                 s2 += s1;
  162.                 s1 += buf[index++] & 0xff;
  163.                 s2 += s1;
  164.                 s1 += buf[index++] & 0xff;
  165.                 s2 += s1;
  166.                 s1 += buf[index++] & 0xff;
  167.                 s2 += s1;
  168.                 s1 += buf[index++] & 0xff;
  169.                 s2 += s1;
  170.                 s1 += buf[index++] & 0xff;
  171.                 s2 += s1;
  172.                 s1 += buf[index++] & 0xff;
  173.                 s2 += s1;
  174.                 s1 += buf[index++] & 0xff;
  175.                 s2 += s1;
  176.                 k -= 16;
  177.             }
  178.             if (k != 0) {
  179.                 do {
  180.                     s1 += buf[index++] & 0xff;
  181.                     s2 += s1;
  182.                 } while (--k != 0);
  183.             }
  184.             s1 %= BASE;
  185.             s2 %= BASE;
  186.         }
  187.         return (s2 << 16) | s1;
  188.     }

  189.     public static void WritePng(DataOutputStream output, int width, int height,
  190.                                 byte[] buffer, byte[] colors,
  191.                                 boolean Transparent, int offset) throws
  192.             IOException {
  193.         int adler = (int) adler32(1l, buffer, offset, buffer.length - offset);
  194.         byte[] lenNlen = { //压缩块的LEN和NLEN信息
  195.                          (byte) 0,
  196.                          (byte) 0xfa, (byte) 0x7e,
  197.                          (byte) 0x05, (byte) 0x81
  198.         };
  199.         IDATPOS = 0;
  200.         output.write(HEADChunk);
  201.         IDATPOS += HEADChunk.length;
  202.         //写IHDR
  203.         output.writeInt(13); //len
  204.         output.writeInt(1229472850); //IHDR type code
  205.         output.writeInt(width); //写宽度
  206.         output.writeInt(height); //写高度
  207.         output.writeByte(8); //1Bitdepth
  208.         if (colors == null) {
  209.             output.writeByte(6); //2ColorType
  210.         } else {
  211.             output.writeByte(3); //2ColorType
  212.         }
  213.         output.writeByte(0); //3CompressionMethod
  214.         output.writeByte(0); //4Filter method
  215.         output.writeByte(0); //5Interlace method
  216.         output.writeInt(0); //写crc
  217.         IDATPOS += 25;
  218.         //写PLTE
  219.         if (colors != null) {
  220.             output.writeInt(colors.length); //len
  221.             output.writeInt(1347179589); //type code
  222.             output.write(colors); //data
  223.             output.writeInt(0); //crc
  224.             IDATPOS += colors.length + 12;
  225.         }
  226.         //写TRNS
  227.         if (Transparent) {
  228.             output.write(tRNSChunk);
  229.             IDATPOS += tRNSChunk.length;
  230.         }
  231.         //写IDAT
  232.         byte[] dpixels = buffer;
  233.         int bufferlen = dpixels.length - offset;
  234.         int blocklen = 32506;
  235.         int blocknum = 1;
  236.         if ((dpixels.length % blocklen) == 0) {
  237.             blocknum = bufferlen / blocklen;
  238.         } else {
  239.             blocknum = (bufferlen / blocklen) + 1;
  240.         }
  241.         int IDATChunkLen = (bufferlen + 6 + blocknum * 5);
  242.         output.writeInt(IDATChunkLen); //len
  243.         output.writeInt(1229209940); //idat type code
  244.         output.writeShort((short) 0x78da); //78da
  245.         for (int i = 0; i < blocknum; i++) {
  246.             int off = i * blocklen;
  247.             int len = bufferlen - off;
  248.             if (len >= blocklen) {
  249.                 len = blocklen;
  250.                 lenNlen[0] = (byte) 0;
  251.             } else {
  252.                 lenNlen[0] = (byte) 1;
  253.             }
  254.             int msb = (len & 0xff);
  255.             int lsb = (len >>> 8);
  256.             lenNlen[1] = (byte) msb;
  257.             lenNlen[2] = (byte) lsb;
  258.             lenNlen[3] = (byte) (msb ^ 0xff);
  259.             lenNlen[4] = (byte) (lsb ^ 0xff);
  260.             output.write(lenNlen);
  261.             output.write(dpixels, off + offset, len);
  262.         }
  263.         output.writeInt(adler); //IDAT adler
  264.         output.writeInt(0); //IDAT crc
  265.         output.write(IENDChunk);
  266.     }

  267.     public static void getImageBufferForImageARGB8888(Image img, byte[] rawByte,
  268.             int w, int h, int off) {
  269.         int n = off;
  270.         int[] raw = new int[w];
  271.         for (int j = 0; j < h; j++) {
  272.             img.getRGB(raw, 0, w, 0, j, w, 1);
  273.             for (int i = 0; i < raw.length; i++) {
  274.                 int ARGB = raw[i];
  275.                 int a = (ARGB & 0xff000000) >> 24;
  276.                 int r = (ARGB & 0xff0000) >> 16;
  277.                 int g = (ARGB & 0xff00) >> 8;
  278.                 int b = ARGB & 0xff;
  279.                 if (i % w == 0) {
  280.                     n += 1;
  281.                 }
  282.                 rawByte[n] = (byte) r;
  283.                 rawByte[n + 1] = (byte) g;
  284.                 rawByte[n + 2] = (byte) b;
  285.                 rawByte[n + 3] = (byte) a;
  286.                 n += 4;
  287.             }
  288.         }
  289.         raw = null;
  290.         System.gc();
  291.     }
  292. }
复制代码
注意:截屏命名是以1、2、3、4数字++命名的,如1.png,2.png等等,该程序设计的触发截屏事件是点击屏幕左上角,这个根据具体需要随意改了,并且图片保存命名规则也需要完善下。



曾尝试过截屏的时候弄点提示,但这是万万不可的,在屏幕上出现任何提示都将会被截屏记录下来,所以我在写这个功能的时候,很是认真的考虑了截屏的完整性及安全性,只要触发了,程序会自动屏蔽所有操作等待截屏操作结束,结束后恢复,也就是说机器慢的,触发截屏了,你在点或者做其他的程序界面的操作,那都是不可能的,截屏生成保存文件这个过程结束后才可以。

游客,如果你要查看本帖隐藏内容请回复

Rank: 1

发表于 2010-11-16 14:28 |显示全部帖子
但愿能有用……为了能在手机上应用成功,我将继续加长此文……加长……人工加长……加长……人工加长……
你需要登录后才可以回帖 登录 | 注册

Archiver|开发者的天空

GMT+8, 2012-2-8 19:52

Powered by Discuz! X1.5

© 2001-2010 Comsenz Inc.