gif验证码

普通验证码:

[java]  view plain  copy
  1. package net.loyin.util;  
  2.   
  3. import java.io.IOException;  
  4. import javax.servlet.ServletException;  
  5. import javax.servlet.http.HttpServlet;  
  6. import javax.servlet.http.HttpServletRequest;  
  7. import javax.servlet.http.HttpServletResponse;  
  8. import java.awt.Color;  
  9. import java.awt.Font;  
  10. import java.awt.Graphics;  
  11. import java.awt.image.BufferedImage;  
  12. import java.io.ByteArrayOutputStream;  
  13. import java.util.Random;  
  14.   
  15. import javax.imageio.ImageIO;  
  16. import javax.servlet.ServletOutputStream;  
  17. import javax.servlet.http.HttpSession;  
  18.   
  19. /** 
  20.  * 随机生成四位验证码,并输出图像 
  21.  */  
  22. @SuppressWarnings("serial")  
  23. public class ValidateCode extends HttpServlet {  
  24.     private static final int WIDTH = 150;  
  25.     private static final int HEIGHT = 50;  
  26.     private static final String chars = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz";  
  27.     @Override  
  28.     public void service(HttpServletRequest request, HttpServletResponse response)  
  29.             throws ServletException, IOException {  
  30.         response.setContentType("image/jpeg");  
  31.   
  32.         // 防止浏览器缓冲  
  33.         response.setHeader("Pragma""No-cache");  
  34.         response.setHeader("Cache-Control""no-cache");  
  35.         response.setDateHeader("Expires"0);  
  36.         HttpSession session = request.getSession();  
  37.         BufferedImage image = new BufferedImage(WIDTH, HEIGHT,BufferedImage.TYPE_INT_RGB);  
  38.         Graphics g = image.getGraphics();  
  39.         char[] rands = getCode(4);  
  40.         drawBackground(g);  
  41.         drawRands(g, rands);  
  42.         g.dispose();  
  43.         ServletOutputStream out = response.getOutputStream();  
  44.         ByteArrayOutputStream bos = new ByteArrayOutputStream();  
  45.         ImageIO.write(image, "PNG", bos);  
  46.         byte[] buf = bos.toByteArray();  
  47.         response.setContentLength(buf.length);  
  48.         out.write(buf);  
  49.         bos.close();  
  50.         out.close();  
  51.         session.setAttribute("check"new String(rands).toLowerCase());  
  52.     }  
  53.   
  54.     /** 
  55.      * 产生随机数 
  56.      * @return 
  57.      */  
  58.     private char[] getCode(int length) {  
  59.         char[] rands = new char[length];  
  60.         for (int i = 0; i < length; i++) {  
  61.             int rand = (int) (Math.random() * chars.length());  
  62.             rands[i] = chars.charAt(rand);  
  63.         }  
  64.         return rands;  
  65.     }  
  66.   
  67.     /** 
  68.      * 绘制背景 
  69.      * @param g 
  70.      */  
  71.     private void drawBackground(Graphics g) {  
  72.         g.setColor(new Color(0xDCeeee));  
  73.         g.fillRect(00, WIDTH, HEIGHT);  
  74.         Random random=new Random();  
  75.         int len=0;  
  76.         while(len<=5){  
  77.             len=random.nextInt(15);  
  78.         }  
  79.         for (int i = 0; i < len; i++) {  
  80.             int x = (int) (random.nextInt(WIDTH));  
  81.             int y = (int) (random.nextInt(HEIGHT) );  
  82.             int red = (int) (255-random.nextInt(200));  
  83.             int green = (int) (255-random.nextInt(200) );  
  84.             int blue = (int) (255-random.nextInt(200) );  
  85.             g.setColor(new Color(red, green, blue));  
  86. //          g.drawLine(x, y, random.nextInt(WIDTH)-x, random.nextInt(HEIGHT)-y);  
  87.             g.drawOval(x, y, 22);  
  88.         }  
  89.     }  
  90.     /** 
  91.      * 绘制验证码 
  92.      * @param g 
  93.      * @param rands 
  94.      */  
  95.     private void drawRands(Graphics g, char[] rands) {  
  96.         Random random=new Random();  
  97.           
  98.         g.setFont(new Font("黑体", Font.ITALIC | Font.BOLD, 45));  
  99.         for(int i=0;i<rands.length;i++){  
  100.             int red = (int) (random.nextInt(255));  
  101.             int green = (int) (random.nextInt(255) );  
  102.             int blue = (int) (random.nextInt(255) );  
  103.             g.setColor(new Color(red, green, blue));  
  104.             g.drawString("" + rands[i], i*4040);  
  105.         }  
  106.     }  
  107.     @Override  
  108.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
  109.             throws ServletException, IOException {  
  110.         service(request, response);  
  111.     }  
  112. }  

以下是gif验证码,其中包括一些工具类与测试类,下面有效果图:

png:

gif:

[java]  view plain  copy
  1. package net.loyin.util.vcode;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.OutputStream;  
  5.   
  6. /** 
  7.  * @author: wuhongjun 
  8.  * @version:1.0 
  9.  */  
  10. public class Encoder  
  11. {  
  12.     private static final int EOF = -1;  
  13.   
  14.     private int imgW, imgH;  
  15.     private byte[] pixAry;  
  16.     private int initCodeSize;  
  17.     private int remaining;  
  18.     private int curPixel;  
  19.   
  20.     // GIFCOMPR.C       - GIF Image compression routines  
  21.     //  
  22.     // Lempel-Ziv compression based on 'compress'.  GIF modifications by  
  23.     // David Rowley (mgardi@watdcsu.waterloo.edu)  
  24.   
  25.     // General DEFINEs  
  26.   
  27.     static final int BITS = 12;  
  28.   
  29.     static final int HSIZE = 5003// 80% occupancy  
  30.   
  31.     // GIF Image compression - modified 'compress'  
  32.     //  
  33.     // Based on: compress.c - File compression ala IEEE Computer, June 1984.  
  34.     //  
  35.     // By Authors:  Spencer W. Thomas      (decvax!harpo!utah-cs!utah-gr!thomas)  
  36.     //              Jim McKie              (decvax!mcvax!jim)  
  37.     //              Steve Davies           (decvax!vax135!petsd!peora!srd)  
  38.     //              Ken Turkowski          (decvax!decwrl!turtlevax!ken)  
  39.     //              James A. Woods         (decvax!ihnp4!ames!jaw)  
  40.     //              Joe Orost              (decvax!vax135!petsd!joe)  
  41.   
  42.     int n_bits; // number of bits/code  
  43.     int maxbits = BITS; // user settable max # bits/code  
  44.     int maxcode; // maximum code, given n_bits  
  45.     int maxmaxcode = 1 << BITS; // should NEVER generate this code  
  46.   
  47.     int[] htab = new int[HSIZE];  
  48.     int[] codetab = new int[HSIZE];  
  49.   
  50.     int hsize = HSIZE; // for dynamic table sizing  
  51.   
  52.     int free_ent = 0// first unused entry  
  53.   
  54.     // block compression parameters -- after all codes are used up,  
  55.     // and compression rate changes, start over.  
  56.     boolean clear_flg = false;  
  57.   
  58.     // Algorithm:  use open addressing double hashing (no chaining) on the  
  59.     // prefix code / next character combination.  We do a variant of Knuth's  
  60.     // algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime  
  61.     // secondary probe.  Here, the modular division first probe is gives way  
  62.     // to a faster exclusive-or manipulation.  Also do block compression with  
  63.     // an adaptive reset, whereby the code table is cleared when the compression  
  64.     // ratio decreases, but after the table fills.  The variable-length output  
  65.     // codes are re-sized at this point, and a special CLEAR code is generated  
  66.     // for the decompressor.  Late addition:  construct the table according to  
  67.     // file size for noticeable speed improvement on small files.  Please direct  
  68.     // questions about this implementation to ames!jaw.  
  69.   
  70.     int g_init_bits;  
  71.   
  72.     int ClearCode;  
  73.     int EOFCode;  
  74.   
  75.     // output  
  76.     //  
  77.     // Output the given code.  
  78.     // Inputs:  
  79.     //      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes  
  80.     //              that n_bits =< wordsize - 1.  
  81.     // Outputs:  
  82.     //      Outputs code to the file.  
  83.     // Assumptions:  
  84.     //      Chars are 8 bits long.  
  85.     // Algorithm:  
  86.     //      Maintain a BITS character long buffer (so that 8 codes will  
  87.     // fit in it exactly).  Use the VAX insv instruction to insert each  
  88.     // code in turn.  When the buffer fills up empty it and start over.  
  89.   
  90.     int cur_accum = 0;  
  91.     int cur_bits = 0;  
  92.   
  93.     int masks[] =  
  94.             {  
  95.                     0x0000,  
  96.                     0x0001,  
  97.                     0x0003,  
  98.                     0x0007,  
  99.                     0x000F,  
  100.                     0x001F,  
  101.                     0x003F,  
  102.                     0x007F,  
  103.                     0x00FF,  
  104.                     0x01FF,  
  105.                     0x03FF,  
  106.                     0x07FF,  
  107.                     0x0FFF,  
  108.                     0x1FFF,  
  109.                     0x3FFF,  
  110.                     0x7FFF,  
  111.                     0xFFFF };  
  112.   
  113.     // Number of characters so far in this 'packet'  
  114.     int a_count;  
  115.   
  116.     // Define the storage for the packet accumulator  
  117.     byte[] accum = new byte[256];  
  118.   
  119.     //----------------------------------------------------------------------------  
  120.     Encoder(int width, int height, byte[] pixels, int color_depth) {  
  121.         imgW = width;  
  122.         imgH = height;  
  123.         pixAry = pixels;  
  124.         initCodeSize = Math.max(2, color_depth);  
  125.     }  
  126.   
  127.     // Add a character to the end of the current packet, and if it is 254  
  128.     // characters, flush the packet to disk.  
  129.     void char_out(byte c, OutputStream outs) throws IOException {  
  130.         accum[a_count++] = c;  
  131.         if (a_count >= 254)  
  132.             flush_char(outs);  
  133.     }  
  134.   
  135.     // Clear out the hash table  
  136.   
  137.     // table clear for block compress  
  138.     void cl_block(OutputStream outs) throws IOException {  
  139.         cl_hash(hsize);  
  140.         free_ent = ClearCode + 2;  
  141.         clear_flg = true;  
  142.   
  143.         output(ClearCode, outs);  
  144.     }  
  145.   
  146.     // reset code table  
  147.     void cl_hash(int hsize) {  
  148.         for (int i = 0; i < hsize; ++i)  
  149.             htab[i] = -1;  
  150.     }  
  151.   
  152.     void compress(int init_bits, OutputStream outs) throws IOException {  
  153.         int fcode;  
  154.         int i /* = 0 */;  
  155.         int c;  
  156.         int ent;  
  157.         int disp;  
  158.         int hsize_reg;  
  159.         int hshift;  
  160.   
  161.         // Set up the globals:  g_init_bits - initial number of bits  
  162.         g_init_bits = init_bits;  
  163.   
  164.         // Set up the necessary values  
  165.         clear_flg = false;  
  166.         n_bits = g_init_bits;  
  167.         maxcode = MAXCODE(n_bits);  
  168.   
  169.         ClearCode = 1 << (init_bits - 1);  
  170.         EOFCode = ClearCode + 1;  
  171.         free_ent = ClearCode + 2;  
  172.   
  173.         a_count = 0// clear packet  
  174.   
  175.         ent = nextPixel();  
  176.   
  177.         hshift = 0;  
  178.         for (fcode = hsize; fcode < 65536; fcode *= 2)  
  179.             ++hshift;  
  180.         hshift = 8 - hshift; // set hash code range bound  
  181.   
  182.         hsize_reg = hsize;  
  183.         cl_hash(hsize_reg); // clear hash table  
  184.   
  185.         output(ClearCode, outs);  
  186.   
  187.         outer_loop : while ((c = nextPixel()) != EOF) {  
  188.             fcode = (c << maxbits) + ent;  
  189.             i = (c << hshift) ^ ent; // xor hashing  
  190.   
  191.             if (htab[i] == fcode) {  
  192.                 ent = codetab[i];  
  193.                 continue;  
  194.             } else if (htab[i] >= 0// non-empty slot  
  195.             {  
  196.                 disp = hsize_reg - i; // secondary hash (after G. Knott)  
  197.                 if (i == 0)  
  198.                     disp = 1;  
  199.                 do {  
  200.                     if ((i -= disp) < 0)  
  201.                         i += hsize_reg;  
  202.   
  203.                     if (htab[i] == fcode) {  
  204.                         ent = codetab[i];  
  205.                         continue outer_loop;  
  206.                     }  
  207.                 } while (htab[i] >= 0);  
  208.             }  
  209.             output(ent, outs);  
  210.             ent = c;  
  211.             if (free_ent < maxmaxcode) {  
  212.                 codetab[i] = free_ent++; // code -> hashtable  
  213.                 htab[i] = fcode;  
  214.             } else  
  215.                 cl_block(outs);  
  216.         }  
  217.         // Put out the final code.  
  218.         output(ent, outs);  
  219.         output(EOFCode, outs);  
  220.     }  
  221.   
  222.     //----------------------------------------------------------------------------  
  223.     void encode(OutputStream os) throws IOException {  
  224.         os.write(initCodeSize); // write "initial code size" byte  
  225.   
  226.         remaining = imgW * imgH; // reset navigation variables  
  227.         curPixel = 0;  
  228.   
  229.         compress(initCodeSize + 1, os); // compress and write the pixel data  
  230.   
  231.         os.write(0); // write block terminator  
  232.     }  
  233.   
  234.     // Flush the packet to disk, and reset the accumulator  
  235.     void flush_char(OutputStream outs) throws IOException {  
  236.         if (a_count > 0) {  
  237.             outs.write(a_count);  
  238.             outs.write(accum, 0, a_count);  
  239.             a_count = 0;  
  240.         }  
  241.     }  
  242.   
  243.     final int MAXCODE(int n_bits) {  
  244.         return (1 << n_bits) - 1;  
  245.     }  
  246.   
  247.     //----------------------------------------------------------------------------  
  248.     // Return the next pixel from the image  
  249.     //----------------------------------------------------------------------------  
  250.     private int nextPixel() {  
  251.         if (remaining == 0)  
  252.             return EOF;  
  253.   
  254.         --remaining;  
  255.   
  256.         byte pix = pixAry[curPixel++];  
  257.   
  258.         return pix & 0xff;  
  259.     }  
  260.   
  261.     void output(int code, OutputStream outs) throws IOException {  
  262.         cur_accum &= masks[cur_bits];  
  263.   
  264.         if (cur_bits > 0)  
  265.             cur_accum |= (code << cur_bits);  
  266.         else  
  267.             cur_accum = code;  
  268.   
  269.         cur_bits += n_bits;  
  270.   
  271.         while (cur_bits >= 8) {  
  272.             char_out((byte) (cur_accum & 0xff), outs);  
  273.             cur_accum >>= 8;  
  274.             cur_bits -= 8;  
  275.         }  
  276.   
  277.         // If the next entry is going to be too big for the code size,  
  278.         // then increase it, if possible.  
  279.         if (free_ent > maxcode || clear_flg) {  
  280.             if (clear_flg) {  
  281.                 maxcode = MAXCODE(n_bits = g_init_bits);  
  282.                 clear_flg = false;  
  283.             } else {  
  284.                 ++n_bits;  
  285.                 if (n_bits == maxbits)  
  286.                     maxcode = maxmaxcode;  
  287.                 else  
  288.                     maxcode = MAXCODE(n_bits);  
  289.             }  
  290.         }  
  291.   
  292.         if (code == EOFCode) {  
  293.             // At EOF, write the rest of the buffer.  
  294.             while (cur_bits > 0) {  
  295.                 char_out((byte) (cur_accum & 0xff), outs);  
  296.                 cur_accum >>= 8;  
  297.                 cur_bits -= 8;  
  298.             }  
  299.   
  300.             flush_char(outs);  
  301.         }  
  302.     }  
  303. }  


GIF验证码

[java]  view plain  copy
  1. package net.loyin.util.vcode;  
  2.   
  3. import java.awt.Color;  
  4. import java.awt.Font;  
  5. import java.io.OutputStream;  
  6. import static net.loyin.util.vcode.Randoms.alpha;  
  7. import static net.loyin.util.vcode.Randoms.num;  
  8. /** 
  9.  * <p>验证码抽象类,暂时不支持中文</p> 
  10.  * 
  11.  * @author: wuhongjun 
  12.  * @version:1.0 
  13.  */  
  14. public abstract class Captcha  
  15. {  
  16.     protected Font font = new Font("Verdana", Font.ITALIC|Font.BOLD, 28);   // 字体  
  17.     protected int len = 5;  // 验证码随机字符长度  
  18.     protected int width = 150;  // 验证码显示跨度  
  19.     protected int height = 40;  // 验证码显示高度  
  20.     private String chars = null;  // 随机字符串  
  21.   
  22.     /** 
  23.      * 生成随机字符数组 
  24.      * @return 字符数组 
  25.      */  
  26.     protected char[] alphas()  
  27.     {  
  28.         char[] cs = new char[len];  
  29.         for(int i = 0;i<len;i++)  
  30.         {  
  31.             cs[i] = alpha();  
  32.         }  
  33.         chars = new String(cs);  
  34.         return cs;  
  35.     }  
  36.     public Font getFont()  
  37.     {  
  38.         return font;  
  39.     }  
  40.   
  41.     public void setFont(Font font)  
  42.     {  
  43.         this.font = font;  
  44.     }  
  45.   
  46.     public int getLen()  
  47.     {  
  48.         return len;  
  49.     }  
  50.   
  51.     public void setLen(int len)  
  52.     {  
  53.         this.len = len;  
  54.     }  
  55.   
  56.     public int getWidth()  
  57.     {  
  58.         return width;  
  59.     }  
  60.   
  61.     public void setWidth(int width)  
  62.     {  
  63.         this.width = width;  
  64.     }  
  65.   
  66.     public int getHeight()  
  67.     {  
  68.         return height;  
  69.     }  
  70.   
  71.     public void setHeight(int height)  
  72.     {  
  73.         this.height = height;  
  74.     }  
  75.   
  76.     /** 
  77.      * 给定范围获得随机颜色 
  78.      * @return Color 随机颜色 
  79.      */  
  80.     protected Color color(int fc, int bc)  
  81.     {  
  82.         if (fc > 255)  
  83.             fc = 255;  
  84.         if (bc > 255)  
  85.             bc = 255;  
  86.         int r = fc + num(bc - fc);  
  87.         int g = fc + num(bc - fc);  
  88.         int b = fc + num(bc - fc);  
  89.         return new Color(r, g, b);  
  90.     }  
  91.   
  92.     /** 
  93.      * 验证码输出,抽象方法,由子类实现 
  94.      * @param os 输出流 
  95.      */  
  96.     public abstract void out(OutputStream os);  
  97.   
  98.     /** 
  99.      * 获取随机字符串 
  100.      * @return string 
  101.      */  
  102.     public String text()  
  103.     {  
  104.         return chars;  
  105.     }  
  106. }  


[java]  view plain  copy
  1. package net.loyin.util.vcode;  
  2.   
  3. import java.awt.AlphaComposite;  
  4. import java.awt.Color;  
  5. import java.awt.Font;  
  6. import java.awt.Graphics2D;  
  7. import java.awt.image.BufferedImage;  
  8. import java.io.OutputStream;  
  9. import static net.loyin.util.vcode.Randoms.num;  
  10. /** 
  11.  * <p>Gif验证码类</p> 
  12.  * 
  13.  * @author: wuhongjun 
  14.  * @version:1.0 
  15.  */  
  16. public class GifCaptcha extends Captcha  
  17. {  
  18.     public GifCaptcha()  
  19.     {  
  20.     }  
  21.   
  22.     public GifCaptcha(int width,int height){  
  23.         this.width = width;  
  24.         this.height = height;  
  25.     }  
  26.   
  27.     public GifCaptcha(int width,int height,int len){  
  28.         this(width,height);  
  29.         this.len = len;  
  30.     }  
  31.   
  32.     public GifCaptcha(int width,int height,int len,Font font)  
  33.     {  
  34.         this(width,height,len);  
  35.         this.font = font;  
  36.     }  
  37.   
  38.     @Override  
  39.     public void out(OutputStream os)  
  40.     {  
  41.         try  
  42.         {  
  43.             GifEncoder gifEncoder = new GifEncoder();   // gif编码类,这个利用了洋人写的编码类,所有类都在附件中  
  44.             //生成字符  
  45.             gifEncoder.start(os);  
  46.             gifEncoder.setQuality(180);  
  47.             gifEncoder.setDelay(100);  
  48.             gifEncoder.setRepeat(0);  
  49.             BufferedImage frame;  
  50.             char[] rands =alphas();  
  51.             Color fontcolor[]=new Color[len];  
  52.             for(int i=0;i<len;i++)  
  53.             {  
  54.                 fontcolor[i]=new Color(20 + num(110), 20 + num(110), 20 + num(110));  
  55.             }  
  56.             for(int i=0;i<len;i++)  
  57.             {  
  58.                 frame=graphicsImage(fontcolor, rands, i);  
  59.                 gifEncoder.addFrame(frame);  
  60.                 frame.flush();  
  61.             }  
  62.             gifEncoder.finish();  
  63.         }finally  
  64.         {  
  65.             Streams.close(os);  
  66.         }  
  67.   
  68.     }  
  69.   
  70.     /** 
  71.      * 画随机码图 
  72.      * @param fontcolor 随机字体颜色 
  73.      * @param strs 字符数组 
  74.      * @param flag 透明度使用 
  75.      * @return BufferedImage 
  76.      */  
  77.     private BufferedImage graphicsImage(Color[] fontcolor,char[] strs,int flag)  
  78.     {  
  79.         BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);  
  80.         //或得图形上下文  
  81.         //Graphics2D g2d=image.createGraphics();  
  82.         Graphics2D g2d = (Graphics2D)image.getGraphics();  
  83.         //利用指定颜色填充背景  
  84.         g2d.setColor(Color.WHITE);  
  85.         g2d.fillRect(00, width, height);  
  86.         AlphaComposite ac3;  
  87.         int h  = height - ((height - font.getSize()) >>1) ;  
  88.         int w = width/len;  
  89.         g2d.setFont(font);  
  90.         for(int i=0;i<len;i++)  
  91.         {  
  92.             ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));  
  93.             g2d.setComposite(ac3);  
  94.             g2d.setColor(fontcolor[i]);  
  95.             g2d.drawOval(num(width), num(height), 5+num(10), 5+num(10));  
  96.             g2d.drawString(strs[i]+"", (width-(len-i)*w)+(w-font.getSize())+1, h-4);  
  97.         }  
  98.         g2d.dispose();  
  99.         return image;  
  100.     }  
  101.   
  102.     /** 
  103.      * 获取透明度,从0到1,自动计算步长 
  104.      * @return float 透明度 
  105.      */  
  106.     private float getAlpha(int i,int j)  
  107.     {  
  108.         int num = i+j;  
  109.         float r = (float)1/len,s = (len+1) * r;  
  110.         return num > len ? (num *r - s) : num * r;  
  111.     }  
  112.   
  113. }  

[java]  view plain  copy
  1. package net.loyin.util.vcode;  
  2.   
  3.   
  4. import java.awt.*;  
  5. import java.awt.image.BufferedImage;  
  6. import java.awt.image.DataBufferInt;  
  7. import java.io.BufferedInputStream;  
  8. import java.io.FileInputStream;  
  9. import java.io.IOException;  
  10. import java.io.InputStream;  
  11. import java.net.URL;  
  12. import java.util.ArrayList;  
  13.   
  14. /** 
  15.  * <p></p> 
  16.  * 
  17.  * @author: wuhongjun 
  18.  * @version:1.0 
  19.  */  
  20. public class GifDecoder  
  21. {  
  22.     /** 
  23.      * File read status: No errors. 
  24.      */  
  25.     public static final int STATUS_OK = 0;  
  26.   
  27.     /** 
  28.      * File read status: Error decoding file (may be partially decoded) 
  29.      */  
  30.     public static final int STATUS_FORMAT_ERROR = 1;  
  31.   
  32.     /** 
  33.      * File read status: Unable to open source. 
  34.      */  
  35.     public static final int STATUS_OPEN_ERROR = 2;  
  36.   
  37.     protected BufferedInputStream in;  
  38.     protected int status;  
  39.   
  40.     protected int width; // full image width  
  41.     protected int height; // full image height  
  42.     protected boolean gctFlag; // global color table used  
  43.     protected int gctSize; // size of global color table  
  44.     protected int loopCount = 1// iterations; 0 = repeat forever  
  45.   
  46.     protected int[] gct; // global color table  
  47.     protected int[] lct; // local color table  
  48.     protected int[] act; // active color table  
  49.   
  50.     protected int bgIndex; // background color index  
  51.     protected int bgColor; // background color  
  52.     protected int lastBgColor; // previous bg color  
  53.     protected int pixelAspect; // pixel aspect ratio  
  54.   
  55.     protected boolean lctFlag; // local color table flag  
  56.     protected boolean interlace; // interlace flag  
  57.     protected int lctSize; // local color table size  
  58.   
  59.     protected int ix, iy, iw, ih; // current image rectangle  
  60.     protected Rectangle lastRect; // last image rect  
  61.     protected BufferedImage image; // current frame  
  62.     protected BufferedImage lastImage; // previous frame  
  63.   
  64.     protected byte[] block = new byte[256]; // current data block  
  65.     protected int blockSize = 0// block size  
  66.   
  67.     // last graphic control extension info  
  68.     protected int dispose = 0;  
  69.     // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev  
  70.     protected int lastDispose = 0;  
  71.     protected boolean transparency = false// use transparent color  
  72.     protected int delay = 0// delay in milliseconds  
  73.     protected int transIndex; // transparent color index  
  74.   
  75.     protected static final int MaxStackSize = 4096;  
  76.     // max decoder pixel stack size  
  77.   
  78.     // LZW decoder working arrays  
  79.     protected short[] prefix;  
  80.     protected byte[] suffix;  
  81.     protected byte[] pixelStack;  
  82.     protected byte[] pixels;  
  83.   
  84.     protected ArrayList<GifFrame> frames; // frames read from current file  
  85.     protected int frameCount;  
  86.   
  87.     static class GifFrame {  
  88.         public GifFrame(BufferedImage im, int del) {  
  89.             image = im;  
  90.             delay = del;  
  91.         }  
  92.         public BufferedImage image;  
  93.         public int delay;  
  94.     }  
  95.   
  96.     /** 
  97.      * Gets display duration for specified frame. 
  98.      * 
  99.      * @param n int index of frame 
  100.      * @return delay in milliseconds 
  101.      */  
  102.     public int getDelay(int n) {  
  103.         //  
  104.         delay = -1;  
  105.         if ((n >= 0) && (n < frameCount)) {  
  106.             delay = (frames.get(n)).delay;  
  107.         }  
  108.         return delay;  
  109.     }  
  110.   
  111.     /** 
  112.      * Gets the number of frames read from file. 
  113.      * @return frame count 
  114.      */  
  115.     public int getFrameCount() {  
  116.         return frameCount;  
  117.     }  
  118.   
  119.     /** 
  120.      * Gets the first (or only) image read. 
  121.      * 
  122.      * @return BufferedImage containing first frame, or null if none. 
  123.      */  
  124.     public BufferedImage getImage() {  
  125.         return getFrame(0);  
  126.     }  
  127.   
  128.     /** 
  129.      * Gets the "Netscape" iteration count, if any. 
  130.      * A count of 0 means repeat indefinitiely. 
  131.      * 
  132.      * @return iteration count if one was specified, else 1. 
  133.      */  
  134.     public int getLoopCount() {  
  135.         return loopCount;  
  136.     }  
  137.   
  138.     /** 
  139.      * Creates new frame image from current data (and previous 
  140.      * frames as specified by their disposition codes). 
  141.      */  
  142.     protected void setPixels() {  
  143.         // expose destination image's pixels as int array  
  144.         int[] dest = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();  
  145.   
  146.         // fill in starting image contents based on last image's dispose code  
  147.         if (lastDispose > 0) {  
  148.             if (lastDispose == 3) {  
  149.                 // use image before last  
  150.                 int n = frameCount - 2;  
  151.                 if (n > 0) {  
  152.                     lastImage = getFrame(n - 1);  
  153.                 } else {  
  154.                     lastImage = null;  
  155.                 }  
  156.             }  
  157.   
  158.             if (lastImage != null) {  
  159.                 int[] prev =  
  160.                         ((DataBufferInt) lastImage.getRaster().getDataBuffer()).getData();  
  161.                 System.arraycopy(prev, 0, dest, 0, width * height);  
  162.                 // copy pixels  
  163.   
  164.                 if (lastDispose == 2) {  
  165.                     // fill last image rect area with background color  
  166.                     Graphics2D g = image.createGraphics();  
  167.                     Color c = null;  
  168.                     if (transparency) {  
  169.                         c = new Color(0000);  // assume background is transparent  
  170.                     } else {  
  171.                         c = new Color(lastBgColor); // use given background color  
  172.                     }  
  173.                     g.setColor(c);  
  174.                     g.setComposite(AlphaComposite.Src); // replace area  
  175.                     g.fill(lastRect);  
  176.                     g.dispose();  
  177.                 }  
  178.             }  
  179.         }  
  180.   
  181.         // copy each source line to the appropriate place in the destination  
  182.         int pass = 1;  
  183.         int inc = 8;  
  184.         int iline = 0;  
  185.         for (int i = 0; i < ih; i++) {  
  186.             int line = i;  
  187.             if (interlace) {  
  188.                 if (iline >= ih) {  
  189.                     pass++;  
  190.                     switch (pass) {  
  191.                         case 2 :  
  192.                             iline = 4;  
  193.                             break;  
  194.                         case 3 :  
  195.                             iline = 2;  
  196.                             inc = 4;  
  197.                             break;  
  198.                         case 4 :  
  199.                             iline = 1;  
  200.                             inc = 2;  
  201.                     }  
  202.                 }  
  203.                 line = iline;  
  204.                 iline += inc;  
  205.             }  
  206.             line += iy;  
  207.             if (line < height) {  
  208.                 int k = line * width;  
  209.                 int dx = k + ix; // start of line in dest  
  210.                 int dlim = dx + iw; // end of dest line  
  211.                 if ((k + width) < dlim) {  
  212.                     dlim = k + width; // past dest edge  
  213.                 }  
  214.                 int sx = i * iw; // start of line in source  
  215.                 while (dx < dlim) {  
  216.                     // map color and insert in destination  
  217.                     int index = ((int) pixels[sx++]) & 0xff;  
  218.                     int c = act[index];  
  219.                     if (c != 0) {  
  220.                         dest[dx] = c;  
  221.                     }  
  222.                     dx++;  
  223.                 }  
  224.             }  
  225.         }  
  226.     }  
  227.   
  228.     /** 
  229.      * Gets the image contents of frame n. 
  230.      * 
  231.      * @return BufferedImage representation of frame, or null if n is invalid. 
  232.      */  
  233.     public BufferedImage getFrame(int n) {  
  234.         BufferedImage im = null;  
  235.         if ((n >= 0) && (n < frameCount)) {  
  236.             im = (frames.get(n)).image;  
  237.         }  
  238.         return im;  
  239.     }  
  240.   
  241.     /** 
  242.      * Gets image size. 
  243.      * 
  244.      * @return GIF image dimensions 
  245.      */  
  246.     public Dimension getFrameSize() {  
  247.         return new Dimension(width, height);  
  248.     }  
  249.   
  250.     /** 
  251.      * Reads GIF image from stream 
  252.      * 
  253.      * @param is BufferedInputStream containing GIF file. 
  254.      * @return read status code (0 = no errors) 
  255.      */  
  256.     public int read(BufferedInputStream is) {  
  257.         init();  
  258.         try{  
  259.             if (is != null) {  
  260.                 in = is;  
  261.                 readHeader();  
  262.                 if (!err()) {  
  263.                     readContents();  
  264.                     if (frameCount < 0) {  
  265.                         status = STATUS_FORMAT_ERROR;  
  266.                     }  
  267.                 }  
  268.             } else {  
  269.                 status = STATUS_OPEN_ERROR;  
  270.             }  
  271.         }finally  
  272.         {  
  273.             try{  
  274.             is.close();  
  275.             }catch(Exception e){}  
  276.         }  
  277.         return status;  
  278.     }  
  279.   
  280.     /** 
  281.      * Reads GIF image from stream 
  282.      * 
  283.      * @param is InputStream containing GIF file. 
  284.      * @return read status code (0 = no errors) 
  285.      */  
  286.     public int read(InputStream is) {  
  287.         init();  
  288.         try{  
  289.             if (is != null) {  
  290.                 if (!(is instanceof BufferedInputStream))  
  291.                     is = new BufferedInputStream(is);  
  292.                 in = (BufferedInputStream) is;  
  293.                 readHeader();  
  294.                 if (!err()) {  
  295.                     readContents();  
  296.                     if (frameCount < 0) {  
  297.                         status = STATUS_FORMAT_ERROR;  
  298.                     }  
  299.                 }  
  300.             } else {  
  301.                 status = STATUS_OPEN_ERROR;  
  302.             }  
  303.         }finally  
  304.         {  
  305.             try{is.close();}catch(Exception e){}  
  306.         }  
  307.         return status;  
  308.     }  
  309.   
  310.     /** 
  311.      * Reads GIF file from specified file/URL source 
  312.      * (URL assumed if name contains ":/" or "file:") 
  313.      * 
  314.      * @param name String containing source 
  315.      * @return read status code (0 = no errors) 
  316.      */  
  317.     public int read(String name) {  
  318.         status = STATUS_OK;  
  319.         try {  
  320.             name = name.trim().toLowerCase();  
  321.             if ((name.contains("file:")) || (name.indexOf(":/") > 0)) {  
  322.                 URL url = new URL(name);  
  323.                 in = new BufferedInputStream(url.openStream());  
  324.             } else {  
  325.                 in = new BufferedInputStream(new FileInputStream(name));  
  326.             }  
  327.             status = read(in);  
  328.         } catch (IOException e) {  
  329.             status = STATUS_OPEN_ERROR;  
  330.         }  
  331.         return status;  
  332.     }  
  333.   
  334.     /** 
  335.      * Decodes LZW image data into pixel array. 
  336.      * Adapted from John Cristy's ImageMagick. 
  337.      */  
  338.     protected void decodeImageData() {  
  339.         int NullCode = -1;  
  340.         int npix = iw * ih;  
  341.         int available,  
  342.                 clear,  
  343.                 code_mask,  
  344.                 code_size,  
  345.                 end_of_information,  
  346.                 in_code,  
  347.                 old_code,  
  348.                 bits,  
  349.                 code,  
  350.                 count,  
  351.                 i,  
  352.                 datum,  
  353.                 data_size,  
  354.                 first,  
  355.                 top,  
  356.                 bi,  
  357.                 pi;  
  358.   
  359.         if ((pixels == null) || (pixels.length < npix)) {  
  360.             pixels = new byte[npix]; // allocate new pixel array  
  361.         }  
  362.         if (prefix == null) prefix = new short[MaxStackSize];  
  363.         if (suffix == null) suffix = new byte[MaxStackSize];  
  364.         if (pixelStack == null) pixelStack = new byte[MaxStackSize + 1];  
  365.   
  366.         //  Initialize GIF data stream decoder.  
  367.   
  368.         data_size = read();  
  369.         clear = 1 << data_size;  
  370.         end_of_information = clear + 1;  
  371.         available = clear + 2;  
  372.         old_code = NullCode;  
  373.         code_size = data_size + 1;  
  374.         code_mask = (1 << code_size) - 1;  
  375.         for (code = 0; code < clear; code++) {  
  376.             prefix[code] = 0;  
  377.             suffix[code] = (byte) code;  
  378.         }  
  379.   
  380.         //  Decode GIF pixel stream.  
  381.   
  382.         datum = bits = count = first = top = pi = bi = 0;  
  383.   
  384.         for (i = 0; i < npix;) {  
  385.             if (top == 0) {  
  386.                 if (bits < code_size) {  
  387.                     //  Load bytes until there are enough bits for a code.  
  388.                     if (count == 0) {  
  389.                         // Read a new data block.  
  390.                         count = readBlock();  
  391.                         if (count <= 0)  
  392.                             break;  
  393.                         bi = 0;  
  394.                     }  
  395.                     datum += (((int) block[bi]) & 0xff) << bits;  
  396.                     bits += 8;  
  397.                     bi++;  
  398.                     count--;  
  399.                     continue;  
  400.                 }  
  401.   
  402.                 //  Get the next code.  
  403.   
  404.                 code = datum & code_mask;  
  405.                 datum >>= code_size;  
  406.                 bits -= code_size;  
  407.   
  408.                 //  Interpret the code  
  409.   
  410.                 if ((code > available) || (code == end_of_information))  
  411.                     break;  
  412.                 if (code == clear) {  
  413.                     //  Reset decoder.  
  414.                     code_size = data_size + 1;  
  415.                     code_mask = (1 << code_size) - 1;  
  416.                     available = clear + 2;  
  417.                     old_code = NullCode;  
  418.                     continue;  
  419.                 }  
  420.                 if (old_code == NullCode) {  
  421.                     pixelStack[top++] = suffix[code];  
  422.                     old_code = code;  
  423.                     first = code;  
  424.                     continue;  
  425.                 }  
  426.                 in_code = code;  
  427.                 if (code == available) {  
  428.                     pixelStack[top++] = (byte) first;  
  429.                     code = old_code;  
  430.                 }  
  431.                 while (code > clear) {  
  432.                     pixelStack[top++] = suffix[code];  
  433.                     code = prefix[code];  
  434.                 }  
  435.                 first = ((int) suffix[code]) & 0xff;  
  436.   
  437.                 //  Add a new string to the string table,  
  438.   
  439.                 if (available >= MaxStackSize)  
  440.                     break;  
  441.                 pixelStack[top++] = (byte) first;  
  442.                 prefix[available] = (short) old_code;  
  443.                 suffix[available] = (byte) first;  
  444.                 available++;  
  445.                 if (((available & code_mask) == 0)  
  446.                         && (available < MaxStackSize)) {  
  447.                     code_size++;  
  448.                     code_mask += available;  
  449.                 }  
  450.                 old_code = in_code;  
  451.             }  
  452.   
  453.             //  Pop a pixel off the pixel stack.  
  454.   
  455.             top--;  
  456.             pixels[pi++] = pixelStack[top];  
  457.             i++;  
  458.         }  
  459.   
  460.         for (i = pi; i < npix; i++) {  
  461.             pixels[i] = 0// clear missing pixels  
  462.         }  
  463.   
  464.     }  
  465.   
  466.     /** 
  467.      * Returns true if an error was encountered during reading/decoding 
  468.      */  
  469.     protected boolean err() {  
  470.         return status != STATUS_OK;  
  471.     }  
  472.   
  473.     /** 
  474.      * Initializes or re-initializes reader 
  475.      */  
  476.     protected void init() {  
  477.         status = STATUS_OK;  
  478.         frameCount = 0;  
  479.         frames = new ArrayList<GifFrame>();  
  480.         gct = null;  
  481.         lct = null;  
  482.     }  
  483.   
  484.     /** 
  485.      * Reads a single byte from the input stream. 
  486.      */  
  487.     protected int read() {  
  488.         int curByte = 0;  
  489.         try {  
  490.             curByte = in.read();  
  491.         } catch (IOException e) {  
  492.             status = STATUS_FORMAT_ERROR;  
  493.         }  
  494.         return curByte;  
  495.     }  
  496.   
  497.     /** 
  498.      * Reads next variable length block from input. 
  499.      * 
  500.      * @return number of bytes stored in "buffer" 
  501.      */  
  502.     protected int readBlock() {  
  503.         blockSize = read();  
  504.         int n = 0;  
  505.         if (blockSize > 0) {  
  506.             try {  
  507.                 int count = 0;  
  508.                 while (n < blockSize) {  
  509.                     count = in.read(block, n, blockSize - n);  
  510.                     if (count == -1)  
  511.                         break;  
  512.                     n += count;  
  513.                 }  
  514.             } catch (IOException ignored) {}  
  515.   
  516.             if (n < blockSize) {  
  517.                 status = STATUS_FORMAT_ERROR;  
  518.             }  
  519.         }  
  520.         return n;  
  521.     }  
  522.   
  523.     /** 
  524.      * Reads color table as 256 RGB integer values 
  525.      * 
  526.      * @param ncolors int number of colors to read 
  527.      * @return int array containing 256 colors (packed ARGB with full alpha) 
  528.      */  
  529.     protected int[] readColorTable(int ncolors) {  
  530.         int nbytes = 3 * ncolors;  
  531.         int[] tab = null;  
  532.         byte[] c = new byte[nbytes];  
  533.         int n = 0;  
  534.         try {  
  535.             n = in.read(c);  
  536.         } catch (IOException ignored) {}  
  537.         if (n < nbytes) {  
  538.             status = STATUS_FORMAT_ERROR;  
  539.         } else {  
  540.             tab = new int[256]; // max size to avoid bounds checks  
  541.             int i = 0;  
  542.             int j = 0;  
  543.             while (i < ncolors) {  
  544.                 int r = ((int) c[j++]) & 0xff;  
  545.                 int g = ((int) c[j++]) & 0xff;  
  546.                 int b = ((int) c[j++]) & 0xff;  
  547.                 tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;  
  548.             }  
  549.         }  
  550.         return tab;  
  551.     }  
  552.   
  553.     /** 
  554.      * Main file parser.  Reads GIF content blocks. 
  555.      */  
  556.     protected void readContents() {  
  557.         // read GIF file content blocks  
  558.         boolean done = false;  
  559.         while (!(done || err())) {  
  560.             int code = read();  
  561.             switch (code) {  
  562.   
  563.                 case 0x2C : // image separator  
  564.                     readImage();  
  565.                     break;  
  566.   
  567.                 case 0x21 : // extension  
  568.                     code = read();  
  569.                     switch (code) {  
  570.                         case 0xf9 : // graphics control extension  
  571.                             readGraphicControlExt();  
  572.                             break;  
  573.   
  574.                         case 0xff : // application extension  
  575.                             readBlock();  
  576.                             String app = "";  
  577.                             for (int i = 0; i < 11; i++) {  
  578.                                 app += (char) block[i];  
  579.                             }  
  580.                             if (app.equals("NETSCAPE2.0")) {  
  581.                                 readNetscapeExt();  
  582.                             }  
  583.                             else  
  584.                                 skip(); // don't care  
  585.                             break;  
  586.   
  587.                         default : // uninteresting extension  
  588.                             skip();  
  589.                     }  
  590.                     break;  
  591.   
  592.                 case 0x3b : // terminator  
  593.                     done = true;  
  594.                     break;  
  595.   
  596.                 case 0x00 : // bad byte, but keep going and see what happens  
  597.                     break;  
  598.   
  599.                 default :  
  600.                     status = STATUS_FORMAT_ERROR;  
  601.             }  
  602.         }  
  603.     }  
  604.   
  605.     /** 
  606.      * Reads Graphics Control Extension values 
  607.      */  
  608.     protected void readGraphicControlExt() {  
  609.         read(); // block size  
  610.         int packed = read(); // packed fields  
  611.         dispose = (packed & 0x1c) >> 2// disposal method  
  612.         if (dispose == 0) {  
  613.             dispose = 1// elect to keep old image if discretionary  
  614.         }  
  615.         transparency = (packed & 1) != 0;  
  616.         delay = readShort() * 10// delay in milliseconds  
  617.         transIndex = read(); // transparent color index  
  618.         read(); // block terminator  
  619.     }  
  620.   
  621.     /** 
  622.      * Reads GIF file header information. 
  623.      */  
  624.     protected void readHeader() {  
  625.         String id = "";  
  626.         for (int i = 0; i < 6; i++) {  
  627.             id += (char) read();  
  628.         }  
  629.         if (!id.startsWith("GIF")) {  
  630.             status = STATUS_FORMAT_ERROR;  
  631.             return;  
  632.         }  
  633.   
  634.         readLSD();  
  635.         if (gctFlag && !err()) {  
  636.             gct = readColorTable(gctSize);  
  637.             bgColor = gct[bgIndex];  
  638.         }  
  639.     }  
  640.   
  641.     /** 
  642.      * Reads next frame image 
  643.      */  
  644.     protected void readImage() {  
  645.         ix = readShort(); // (sub)image position & size  
  646.         iy = readShort();  
  647.         iw = readShort();  
  648.         ih = readShort();  
  649.   
  650.         int packed = read();  
  651.         lctFlag = (packed & 0x80) != 0// 1 - local color table flag  
  652.         interlace = (packed & 0x40) != 0// 2 - interlace flag  
  653.         // 3 - sort flag  
  654.         // 4-5 - reserved  
  655.         lctSize = 2 << (packed & 7); // 6-8 - local color table size  
  656.   
  657.         if (lctFlag) {  
  658.             lct = readColorTable(lctSize); // read table  
  659.             act = lct; // make local table active  
  660.         } else {  
  661.             act = gct; // make global table active  
  662.             if (bgIndex == transIndex)  
  663.                 bgColor = 0;  
  664.         }  
  665.         int save = 0;  
  666.         if (transparency) {  
  667.             save = act[transIndex];  
  668.             act[transIndex] = 0// set transparent color if specified  
  669.         }  
  670.   
  671.         if (act == null) {  
  672.             status = STATUS_FORMAT_ERROR; // no color table defined  
  673.         }  
  674.   
  675.         if (err()) return;  
  676.   
  677.         decodeImageData(); // decode pixel data  
  678.         skip();  
  679.   
  680.         if (err()) return;  
  681.   
  682.         frameCount++;  
  683.   
  684.         // create new image to receive frame data  
  685.         image =  
  686.                 new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);  
  687.   
  688.         setPixels(); // transfer pixel data to image  
  689.   
  690.         frames.add(new GifFrame(image, delay)); // add image to frame list  
  691.   
  692.         if (transparency) {  
  693.             act[transIndex] = save;  
  694.         }  
  695.         resetFrame();  
  696.   
  697.     }  
  698.   
  699.     /** 
  700.      * Reads Logical Screen Descriptor 
  701.      */  
  702.     protected void readLSD() {  
  703.   
  704.         // logical screen size  
  705.         width = readShort();  
  706.         height = readShort();  
  707.   
  708.         // packed fields  
  709.         int packed = read();  
  710.         gctFlag = (packed & 0x80) != 0// 1   : global color table flag  
  711.         // 2-4 : color resolution  
  712.         // 5   : gct sort flag  
  713.         gctSize = 2 << (packed & 7); // 6-8 : gct size  
  714.   
  715.         bgIndex = read(); // background color index  
  716.         pixelAspect = read(); // pixel aspect ratio  
  717.     }  
  718.   
  719.     /** 
  720.      * Reads Netscape extenstion to obtain iteration count 
  721.      */  
  722.     protected void readNetscapeExt() {  
  723.         do {  
  724.             readBlock();  
  725.             if (block[0] == 1) {  
  726.                 // loop count sub-block  
  727.                 int b1 = ((int) block[1]) & 0xff;  
  728.                 int b2 = ((int) block[2]) & 0xff;  
  729.                 loopCount = (b2 << 8) | b1;  
  730.             }  
  731.         } while ((blockSize > 0) && !err());  
  732.     }  
  733.   
  734.     /** 
  735.      * Reads next 16-bit value, LSB first 
  736.      */  
  737.     protected int readShort() {  
  738.         // read 16-bit value, LSB first  
  739.         return read() | (read() << 8);  
  740.     }  
  741.   
  742.     /** 
  743.      * Resets frame state for reading next image. 
  744.      */  
  745.     protected void resetFrame() {  
  746.         lastDispose = dispose;  
  747.         lastRect = new Rectangle(ix, iy, iw, ih);  
  748.         lastImage = image;  
  749.         lastBgColor = bgColor;  
  750.          dispose = 0;  
  751.         transparency = false;  
  752.         delay = 0;  
  753.         lct = null;  
  754.     }  
  755.   
  756.     /** 
  757.      * Skips variable length blocks up to and including 
  758.      * next zero length block. 
  759.      */  
  760.     protected void skip() {  
  761.         do {  
  762.             readBlock();  
  763.         } while ((blockSize > 0) && !err());  
  764.     }  
  765. }  

[java]  view plain  copy
  1. package net.loyin.util.vcode;  
  2. import java.awt.*;  
  3. import java.awt.image.BufferedImage;  
  4. import java.awt.image.DataBufferByte;  
  5. import java.io.BufferedOutputStream;  
  6. import java.io.ByteArrayOutputStream;  
  7. import java.io.FileOutputStream;  
  8. import java.io.IOException;  
  9. import java.io.OutputStream;  
  10.   
  11. /** 
  12.  * Class AnimatedGifEncoder - Encodes a GIF file consisting of one or 
  13.  * more frames. 
  14.  * <pre> 
  15.  * Example: 
  16.  *    AnimatedGifEncoder e = new AnimatedGifEncoder(); 
  17.  *    e.start(outputFileName); 
  18.  *    e.setDelay(1000);   // 1 frame per sec 
  19.  *    e.addFrame(image1); 
  20.  *    e.addFrame(image2); 
  21.  *    e.finish(); 
  22.  * </pre> 
  23.  * No copyright asserted on the source code of this class.  May be used 
  24.  * for any purpose, however, refer to the Unisys LZW patent for restrictions 
  25.  * on use of the associated Encoder class.  Please forward any corrections 
  26.  * to questions at fmsware.com. 
  27.  * 
  28.  * @author wuhongjun 
  29.  * @version 1.03 November 2003 
  30.  * 
  31.  */  
  32. public class GifEncoder  
  33. {  
  34.     protected int width; // image size  
  35.     protected int height;  
  36.     protected Color transparent = null// transparent color if given  
  37.     protected int transIndex; // transparent index in color table  
  38.     protected int repeat = -1// no repeat  
  39.     protected int delay = 0// frame delay (hundredths)  
  40.     protected boolean started = false// ready to output frames  
  41.     protected OutputStream out;  
  42.     protected BufferedImage image; // current frame  
  43.     protected byte[] pixels; // BGR byte array from frame  
  44.     protected byte[] indexedPixels; // converted frame indexed to palette  
  45.     protected int colorDepth; // number of bit planes  
  46.     protected byte[] colorTab; // RGB palette  
  47.     protected boolean[] usedEntry = new boolean[256]; // active palette entries  
  48.     protected int palSize = 7// color table size (bits-1)  
  49.     protected int dispose = -1// disposal code (-1 = use default)  
  50.     protected boolean closeStream = false// close stream when finished  
  51.     protected boolean firstFrame = true;  
  52.     protected boolean sizeSet = false// if false, get size from first frame  
  53.     protected int sample = 10// default sample interval for quantizer  
  54.   
  55.     /** 
  56.      * Sets the delay time between each frame, or changes it 
  57.      * for subsequent frames (applies to last frame added). 
  58.      * 
  59.      * @param ms int delay time in milliseconds 
  60.      */  
  61.     public void setDelay(int ms) {  
  62.         delay = Math.round(ms / 10.0f);  
  63.     }  
  64.   
  65.     /** 
  66.      * Sets the GIF frame disposal code for the last added frame 
  67.      * and any subsequent frames.  Default is 0 if no transparent 
  68.      * color has been set, otherwise 2. 
  69.      * @param code int disposal code. 
  70.      */  
  71.     public void setDispose(int code) {  
  72.         if (code >= 0) {  
  73.             dispose = code;  
  74.         }  
  75.     }  
  76.   
  77.     /** 
  78.      * Sets the number of times the set of GIF frames 
  79.      * should be played.  Default is 1; 0 means play 
  80.      * indefinitely.  Must be invoked before the first 
  81.      * image is added. 
  82.      * 
  83.      * @param iter int number of iterations. 
  84.      * @return 
  85.      */  
  86.     public void setRepeat(int iter) {  
  87.         if (iter >= 0) {  
  88.             repeat = iter;  
  89.         }  
  90.     }  
  91.   
  92.     /** 
  93.      * Sets the transparent color for the last added frame 
  94.      * and any subsequent frames. 
  95.      * Since all colors are subject to modification 
  96.      * in the quantization process, the color in the final 
  97.      * palette for each frame closest to the given color 
  98.      * becomes the transparent color for that frame. 
  99.      * May be set to null to indicate no transparent color. 
  100.      * 
  101.      * @param c Color to be treated as transparent on display. 
  102.      */  
  103.     public void setTransparent(Color c) {  
  104.         transparent = c;  
  105.     }  
  106.   
  107.     /** 
  108.      * Adds next GIF frame.  The frame is not written immediately, but is 
  109.      * actually deferred until the next frame is received so that timing 
  110.      * data can be inserted.  Invoking <code>finish()</code> flushes all 
  111.      * frames.  If <code>setSize</code> was not invoked, the size of the 
  112.      * first image is used for all subsequent frames. 
  113.      * 
  114.      * @param im BufferedImage containing frame to write. 
  115.      * @return true if successful. 
  116.      */  
  117.     public boolean addFrame(BufferedImage im) {  
  118.         if ((im == null) || !started) {  
  119.             return false;  
  120.         }  
  121.         boolean ok = true;  
  122.         try {  
  123.             if (!sizeSet) {  
  124.                 // use first frame's size  
  125.                 setSize(im.getWidth(), im.getHeight());  
  126.             }  
  127.             image = im;  
  128.             getImagePixels(); // convert to correct format if necessary  
  129.             analyzePixels(); // build color table & map pixels  
  130.             if (firstFrame) {  
  131.                 writeLSD(); // logical screen descriptior  
  132.                 writePalette(); // global color table  
  133.                 if (repeat >= 0) {  
  134.                     // use NS app extension to indicate reps  
  135.                     writeNetscapeExt();  
  136.                 }  
  137.             }  
  138.             writeGraphicCtrlExt(); // write graphic control extension  
  139.             writeImageDesc(); // image descriptor  
  140.             if (!firstFrame) {  
  141.                 writePalette(); // local color table  
  142.             }  
  143.             writePixels(); // encode and write pixel data  
  144.             firstFrame = false;  
  145.         } catch (IOException e) {  
  146.             ok = false;  
  147.         }  
  148.   
  149.         return ok;  
  150.     }  
  151.   
  152.     //added by alvaro  
  153.     public boolean outFlush() {  
  154.         boolean ok = true;  
  155.         try {  
  156.             out.flush();  
  157.             return ok;  
  158.         } catch (IOException e) {  
  159.             ok = false;  
  160.         }  
  161.   
  162.         return ok;  
  163.     }  
  164.   
  165.     public byte[] getFrameByteArray() {  
  166.         return ((ByteArrayOutputStream) out).toByteArray();  
  167.     }  
  168.   
  169.     /** 
  170.      * Flushes any pending data and closes output file. 
  171.      * If writing to an OutputStream, the stream is not 
  172.      * closed. 
  173.      */  
  174.     public boolean finish() {  
  175.         if (!started) return false;  
  176.         boolean ok = true;  
  177.         started = false;  
  178.         try {  
  179.             out.write(0x3b); // gif trailer  
  180.             out.flush();  
  181.             if (closeStream) {  
  182.                 out.close();  
  183.             }  
  184.         } catch (IOException e) {  
  185.             ok = false;  
  186.         }  
  187.   
  188.         return ok;  
  189.     }  
  190.   
  191.     public void reset() {  
  192.         // reset for subsequent use  
  193.         transIndex = 0;  
  194.         out = null;  
  195.         image = null;  
  196.         pixels = null;  
  197.         indexedPixels = null;  
  198.         colorTab = null;  
  199.         closeStream = false;  
  200.         firstFrame = true;  
  201.     }  
  202.   
  203.     /** 
  204.      * Sets frame rate in frames per second.  Equivalent to 
  205.      * <code>setDelay(1000/fps)</code>. 
  206.      * 
  207.      * @param fps float frame rate (frames per second) 
  208.      */  
  209.     public void setFrameRate(float fps) {  
  210.         if (fps != 0f) {  
  211.             delay = Math.round(100f / fps);  
  212.         }  
  213.     }  
  214.   
  215.     /** 
  216.      * Sets quality of color quantization (conversion of images 
  217.      * to the maximum 256 colors allowed by the GIF specification). 
  218.      * Lower values (minimum = 1) produce better colors, but slow 
  219.      * processing significantly.  10 is the default, and produces 
  220.      * good color mapping at reasonable speeds.  Values greater 
  221.      * than 20 do not yield significant improvements in speed. 
  222.      * 
  223.      * @param quality int greater than 0. 
  224.      * @return 
  225.      */  
  226.     public void setQuality(int quality) {  
  227.         if (quality < 1) quality = 1;  
  228.         sample = quality;  
  229.     }  
  230.   
  231.     /** 
  232.      * Sets the GIF frame size.  The default size is the 
  233.      * size of the first frame added if this method is 
  234.      * not invoked. 
  235.      * 
  236.      * @param w int frame width. 
  237.      * @param h int frame width. 
  238.      */  
  239.     public void setSize(int w, int h) {  
  240.         if (started && !firstFrame) return;  
  241.         width = w;  
  242.         height = h;  
  243.         if (width < 1) width = 320;  
  244.         if (height < 1) height = 240;  
  245.         sizeSet = true;  
  246.     }  
  247.   
  248.     /** 
  249.      * Initiates GIF file creation on the given stream.  The stream 
  250.      * is not closed automatically. 
  251.      * 
  252.      * @param os OutputStream on which GIF images are written. 
  253.      * @return false if initial write failed. 
  254.      */  
  255.     public boolean start(OutputStream os) {  
  256.         if (os == nullreturn false;  
  257.         boolean ok = true;  
  258.         closeStream = false;  
  259.         out = os;  
  260.         try {  
  261.             writeString("GIF89a"); // header  
  262.         } catch (IOException e) {  
  263.             ok = false;  
  264.         }  
  265.         return started = ok;  
  266.     }  
  267.   
  268.     /** 
  269.      * Initiates writing of a GIF file with the specified name. 
  270.      * 
  271.      * @param file String containing output file name. 
  272.      * @return false if open or initial write failed. 
  273.      */  
  274.     public boolean start(String file) {  
  275.         boolean ok = true;  
  276.         try {  
  277.             out = new BufferedOutputStream(new FileOutputStream(file));  
  278.             ok = start(out);  
  279.             closeStream = true;  
  280.         } catch (IOException e) {  
  281.             ok = false;  
  282.         }  
  283.         return started = ok;  
  284.     }  
  285.   
  286.     /** 
  287.      * Analyzes image colors and creates color map. 
  288.      */  
  289.     protected void analyzePixels() {  
  290.         int len = pixels.length;  
  291.         int nPix = len / 3;  
  292.         indexedPixels = new byte[nPix];  
  293.         Quant nq = new Quant(pixels, len, sample);  
  294.         // initialize quantizer  
  295.         colorTab = nq.process(); // create reduced palette  
  296.         // convert map from BGR to RGB  
  297.         for (int i = 0; i < colorTab.length; i += 3) {  
  298.             byte temp = colorTab[i];  
  299.             colorTab[i] = colorTab[i + 2];  
  300.             colorTab[i + 2] = temp;  
  301.             usedEntry[i / 3] = false;  
  302.         }  
  303.         // map image pixels to new palette  
  304.         int k = 0;  
  305.         for (int i = 0; i < nPix; i++) {  
  306.             int index =  
  307.                     nq.map(pixels[k++] & 0xff,  
  308.                             pixels[k++] & 0xff,  
  309.                             pixels[k++] & 0xff);  
  310.             usedEntry[index] = true;  
  311.             indexedPixels[i] = (byte) index;  
  312.         }  
  313.         pixels = null;  
  314.         colorDepth = 8;  
  315.         palSize = 7;  
  316.         // get closest match to transparent color if specified  
  317.         if (transparent != null) {  
  318.             transIndex = findClosest(transparent);  
  319.         }  
  320.     }  
  321.   
  322.     /** 
  323.      * Returns index of palette color closest to c 
  324.      * 
  325.      */  
  326.     protected int findClosest(Color c) {  
  327.         if (colorTab == nullreturn -1;  
  328.         int r = c.getRed();  
  329.         int g = c.getGreen();  
  330.         int b = c.getBlue();  
  331.         int minpos = 0;  
  332.         int dmin = 256 * 256 * 256;  
  333.         int len = colorTab.length;  
  334.         for (int i = 0; i < len;) {  
  335.             int dr = r - (colorTab[i++] & 0xff);  
  336.             int dg = g - (colorTab[i++] & 0xff);  
  337.             int db = b - (colorTab[i] & 0xff);  
  338.             int d = dr * dr + dg * dg + db * db;  
  339.             int index = i / 3;  
  340.             if (usedEntry[index] && (d < dmin)) {  
  341.                 dmin = d;  
  342.                 minpos = index;  
  343.             }  
  344.             i++;  
  345.         }  
  346.         return minpos;  
  347.     }  
  348.   
  349.     /** 
  350.      * Extracts image pixels into byte array "pixels" 
  351.      */  
  352.     protected void getImagePixels() {  
  353.         int w = image.getWidth();  
  354.         int h = image.getHeight();  
  355.         int type = image.getType();  
  356.         if ((w != width)  
  357.                 || (h != height)  
  358.                 || (type != BufferedImage.TYPE_3BYTE_BGR)) {  
  359.             // create new image with right size/format  
  360.             BufferedImage temp =  
  361.                     new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);  
  362.             Graphics2D g = temp.createGraphics();  
  363.             g.drawImage(image, 00null);  
  364.             image = temp;  
  365.         }  
  366.         pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();  
  367.     }  
  368.   
  369.     /** 
  370.      * Writes Graphic Control Extension 
  371.      */  
  372.     protected void writeGraphicCtrlExt() throws IOException {  
  373.         out.write(0x21); // extension introducer  
  374.         out.write(0xf9); // GCE label  
  375.         out.write(4); // data block size  
  376.         int transp, disp;  
  377.         if (transparent == null) {  
  378.             transp = 0;  
  379.             disp = 0// dispose = no action  
  380.         } else {  
  381.             transp = 1;  
  382.             disp = 2// force clear if using transparent color  
  383.         }  
  384.         if (dispose >= 0) {  
  385.             disp = dispose & 7// user override  
  386.         }  
  387.         disp <<= 2;  
  388.   
  389.         // packed fields  
  390.         out.write(0 | // 1:3 reserved  
  391.                 disp | // 4:6 disposal  
  392.                 0 | // 7   user input - 0 = none  
  393.                 transp); // 8   transparency flag  
  394.   
  395.         writeShort(delay); // delay x 1/100 sec  
  396.         out.write(transIndex); // transparent color index  
  397.         out.write(0); // block terminator  
  398.     }  
  399.   
  400.     /** 
  401.      * Writes Image Descriptor 
  402.      */  
  403.     protected void writeImageDesc() throws IOException {  
  404.         out.write(0x2c); // image separator  
  405.         writeShort(0); // image position x,y = 0,0  
  406.         writeShort(0);  
  407.         writeShort(width); // image size  
  408.         writeShort(height);  
  409.         // packed fields  
  410.         if (firstFrame) {  
  411.             // no LCT  - GCT is used for first (or only) frame  
  412.             out.write(0);  
  413.         } else {  
  414.             // specify normal LCT  
  415.             out.write(0x80 | // 1 local color table  1=yes  
  416.                     0 | // 2 interlace - 0=no  
  417.                     0 | // 3 sorted - 0=no  
  418.                     0 | // 4-5 reserved  
  419.                     palSize); // 6-8 size of color table  
  420.         }  
  421.     }  
  422.   
  423.     /** 
  424.      * Writes Logical Screen Descriptor 
  425.      */  
  426.     protected void writeLSD() throws IOException {  
  427.         // logical screen size  
  428.         writeShort(width);  
  429.         writeShort(height);  
  430.         // packed fields  
  431.         out.write((0x80 | // 1   : global color table flag = 1 (gct used)  
  432.                 0x70 | // 2-4 : color resolution = 7  
  433.                 0x00 | // 5   : gct sort flag = 0  
  434.                 palSize)); // 6-8 : gct size  
  435.   
  436.         out.write(0); // background color index  
  437.         out.write(0); // pixel aspect ratio - assume 1:1  
  438.     }  
  439.   
  440.     /** 
  441.      * Writes Netscape application extension to define 
  442.      * repeat count. 
  443.      */  
  444.     protected void writeNetscapeExt() throws IOException {  
  445.         out.write(0x21); // extension introducer  
  446.         out.write(0xff); // app extension label  
  447.         out.write(11); // block size  
  448.         writeString("NETSCAPE" + "2.0"); // app id + auth code  
  449.         out.write(3); // sub-block size  
  450.         out.write(1); // loop sub-block id  
  451.         writeShort(repeat); // loop count (extra iterations, 0=repeat forever)  
  452.         out.write(0); // block terminator  
  453.     }  
  454.   
  455.     /** 
  456.      * Writes color table 
  457.      */  
  458.     protected void writePalette() throws IOException {  
  459.         out.write(colorTab, 0, colorTab.length);  
  460.         int n = (3 * 256) - colorTab.length;  
  461.         for (int i = 0; i < n; i++) {  
  462.             out.write(0);  
  463.         }  
  464.     }  
  465.   
  466.     /** 
  467.      * Encodes and writes pixel data 
  468.      */  
  469.     protected void writePixels() throws IOException {  
  470.         Encoder encoder = new Encoder(width, height, indexedPixels, colorDepth);  
  471.         encoder.encode(out);  
  472.     }  
  473.   
  474.     /** 
  475.      *    Write 16-bit value to output stream, LSB first 
  476.      */  
  477.     protected void writeShort(int value) throws IOException {  
  478.         out.write(value & 0xff);  
  479.         out.write((value >> 8) & 0xff);  
  480.     }  
  481.   
  482.     /** 
  483.      * Writes string to output stream 
  484.      */  
  485.     protected void writeString(String s) throws IOException {  
  486.         for (int i = 0; i < s.length(); i++) {  
  487.             out.write((byte) s.charAt(i));  
  488.         }  
  489.     }  
  490. }  

[java]  view plain  copy
  1. package net.loyin.util.vcode;  
  2.   
  3. /** 
  4.  * <p></p> 
  5.  * 
  6.  * @author: wuhongjun 
  7.  * @version:1.0 
  8.  */  
  9. public class Quant  
  10. {  
  11.     protected static final int netsize = 256/* number of colours used */  
  12.   
  13.     /* four primes near 500 - assume no image has a length so large */  
  14.     /* that it is divisible by all four primes */  
  15.     protected static final int prime1 = 499;  
  16.     protected static final int prime2 = 491;  
  17.     protected static final int prime3 = 487;  
  18.     protected static final int prime4 = 503;  
  19.   
  20.     protected static final int minpicturebytes = (3 * prime4);  
  21.     /* minimum size for input image */  
  22.   
  23.     /* Program Skeleton 
  24.        ---------------- 
  25.        [select samplefac in range 1..30] 
  26.        [read image from input file] 
  27.        pic = (unsigned char*) malloc(3*width*height); 
  28.        initnet(pic,3*width*height,samplefac); 
  29.        learn(); 
  30.        unbiasnet(); 
  31.        [write output image header, using writecolourmap(f)] 
  32.        inxbuild(); 
  33.        write output image using inxsearch(b,g,r)      */  
  34.   
  35.     /* Network Definitions 
  36.        ------------------- */  
  37.   
  38.     protected static final int maxnetpos = (netsize - 1);  
  39.     protected static final int netbiasshift = 4/* bias for colour values */  
  40.     protected static final int ncycles = 100/* no. of learning cycles */  
  41.   
  42.     /* defs for freq and bias */  
  43.     protected static final int intbiasshift = 16/* bias for fractions */  
  44.     protected static final int intbias = (((int1) << intbiasshift);  
  45.     protected static final int gammashift = 10/* gamma = 1024 */  
  46.     protected static final int gamma = (((int1) << gammashift);  
  47.     protected static final int betashift = 10;  
  48.     protected static final int beta = (intbias >> betashift); /* beta = 1/1024 */  
  49.     protected static final int betagamma =  
  50.             (intbias << (gammashift - betashift));  
  51.   
  52.     /* defs for decreasing radius factor */  
  53.     protected static final int initrad = (netsize >> 3); /* for 256 cols, radius starts */  
  54.     protected static final int radiusbiasshift = 6/* at 32.0 biased by 6 bits */  
  55.     protected static final int radiusbias = (((int1) << radiusbiasshift);  
  56.     protected static final int initradius = (initrad * radiusbias); /* and decreases by a */  
  57.     protected static final int radiusdec = 30/* factor of 1/30 each cycle */  
  58.   
  59.     /* defs for decreasing alpha factor */  
  60.     protected static final int alphabiasshift = 10/* alpha starts at 1.0 */  
  61.     protected static final int initalpha = (((int1) << alphabiasshift);  
  62.   
  63.     protected int alphadec; /* biased by 10 bits */  
  64.   
  65.     /* radbias and alpharadbias used for radpower calculation */  
  66.     protected static final int radbiasshift = 8;  
  67.     protected static final int radbias = (((int1) << radbiasshift);  
  68.     protected static final int alpharadbshift = (alphabiasshift + radbiasshift);  
  69.     protected static final int alpharadbias = (((int1) << alpharadbshift);  
  70.   
  71.     /* Types and Global Variables 
  72.     -------------------------- */  
  73.   
  74.     protected byte[] thepicture; /* the input image itself */  
  75.     protected int lengthcount; /* lengthcount = H*W*3 */  
  76.   
  77.     protected int samplefac; /* sampling factor 1..30 */  
  78.   
  79.     //   typedef int pixel[4];                /* BGRc */  
  80.     protected int[][] network; /* the network itself - [netsize][4] */  
  81.   
  82.     protected int[] netindex = new int[256];  
  83.     /* for network lookup - really 256 */  
  84.   
  85.     protected int[] bias = new int[netsize];  
  86.     /* bias and freq arrays for learning */  
  87.     protected int[] freq = new int[netsize];  
  88.     protected int[] radpower = new int[initrad];  
  89.     /* radpower for precomputation */  
  90.   
  91.     /* Initialise network in range (0,0,0) to (255,255,255) and set parameters 
  92.        ----------------------------------------------------------------------- */  
  93.     public Quant(byte[] thepic, int len, int sample) {  
  94.   
  95.         int i;  
  96.         int[] p;  
  97.   
  98.         thepicture = thepic;  
  99.         lengthcount = len;  
  100.         samplefac = sample;  
  101.   
  102.         network = new int[netsize][];  
  103.         for (i = 0; i < netsize; i++) {  
  104.             network[i] = new int[4];  
  105.             p = network[i];  
  106.             p[0] = p[1] = p[2] = (i << (netbiasshift + 8)) / netsize;  
  107.             freq[i] = intbias / netsize; /* 1/netsize */  
  108.             bias[i] = 0;  
  109.         }  
  110.     }  
  111.   
  112.     public byte[] colorMap() {  
  113.         byte[] map = new byte[3 * netsize];  
  114.         int[] index = new int[netsize];  
  115.         for (int i = 0; i < netsize; i++)  
  116.             index[network[i][3]] = i;  
  117.         int k = 0;  
  118.         for (int i = 0; i < netsize; i++) {  
  119.             int j = index[i];  
  120.             map[k++] = (byte) (network[j][0]);  
  121.             map[k++] = (byte) (network[j][1]);  
  122.             map[k++] = (byte) (network[j][2]);  
  123.         }  
  124.         return map;  
  125.     }  
  126.   
  127.     /* Insertion sort of network and building of netindex[0..255] (to do after unbias) 
  128.        ------------------------------------------------------------------------------- */  
  129.     public void inxbuild() {  
  130.   
  131.         int i, j, smallpos, smallval;  
  132.         int[] p;  
  133.         int[] q;  
  134.         int previouscol, startpos;  
  135.   
  136.         previouscol = 0;  
  137.         startpos = 0;  
  138.         for (i = 0; i < netsize; i++) {  
  139.             p = network[i];  
  140.             smallpos = i;  
  141.             smallval = p[1]; /* index on g */  
  142.             /* find smallest in i..netsize-1 */  
  143.             for (j = i + 1; j < netsize; j++) {  
  144.                 q = network[j];  
  145.                 if (q[1] < smallval) { /* index on g */  
  146.                     smallpos = j;  
  147.                     smallval = q[1]; /* index on g */  
  148.                 }  
  149.             }  
  150.             q = network[smallpos];  
  151.             /* swap p (i) and q (smallpos) entries */  
  152.             if (i != smallpos) {  
  153.                 j = q[0];  
  154.                 q[0] = p[0];  
  155.                 p[0] = j;  
  156.                 j = q[1];  
  157.                 q[1] = p[1];  
  158.                 p[1] = j;  
  159.                 j = q[2];  
  160.                 q[2] = p[2];  
  161.                 p[2] = j;  
  162.                 j = q[3];  
  163.                 q[3] = p[3];  
  164.                 p[3] = j;  
  165.             }  
  166.             /* smallval entry is now in position i */  
  167.             if (smallval != previouscol) {  
  168.                 netindex[previouscol] = (startpos + i) >> 1;  
  169.                 for (j = previouscol + 1; j < smallval; j++)  
  170.                     netindex[j] = i;  
  171.                 previouscol = smallval;  
  172.                 startpos = i;  
  173.             }  
  174.         }  
  175.         netindex[previouscol] = (startpos + maxnetpos) >> 1;  
  176.         for (j = previouscol + 1; j < 256; j++)  
  177.             netindex[j] = maxnetpos; /* really 256 */  
  178.     }  
  179.   
  180.     /* Main Learning Loop 
  181.        ------------------ */  
  182.     public void learn() {  
  183.   
  184.         int i, j, b, g, r;  
  185.         int radius, rad, alpha, step, delta, samplepixels;  
  186.         byte[] p;  
  187.         int pix, lim;  
  188.   
  189.         if (lengthcount < minpicturebytes)  
  190.             samplefac = 1;  
  191.         alphadec = 30 + ((samplefac - 1) / 3);  
  192.         p = thepicture;  
  193.         pix = 0;  
  194.         lim = lengthcount;  
  195.         samplepixels = lengthcount / (3 * samplefac);  
  196.         delta = samplepixels / ncycles;  
  197.         alpha = initalpha;  
  198.         radius = initradius;  
  199.   
  200.         rad = radius >> radiusbiasshift;  
  201.         if (rad <= 1)  
  202.             rad = 0;  
  203.         for (i = 0; i < rad; i++)  
  204.             radpower[i] =  
  205.                     alpha * (((rad * rad - i * i) * radbias) / (rad * rad));  
  206.   
  207.         //fprintf(stderr,"beginning 1D learning: initial radius=%d\n", rad);  
  208.   
  209.         if (lengthcount < minpicturebytes)  
  210.             step = 3;  
  211.         else if ((lengthcount % prime1) != 0)  
  212.             step = 3 * prime1;  
  213.         else {  
  214.             if ((lengthcount % prime2) != 0)  
  215.                 step = 3 * prime2;  
  216.             else {  
  217.                 if ((lengthcount % prime3) != 0)  
  218.                     step = 3 * prime3;  
  219.                 else  
  220.                     step = 3 * prime4;  
  221.             }  
  222.         }  
  223.   
  224.         i = 0;  
  225.         while (i < samplepixels) {  
  226.             b = (p[pix + 0] & 0xff) << netbiasshift;  
  227.             g = (p[pix + 1] & 0xff) << netbiasshift;  
  228.             r = (p[pix + 2] & 0xff) << netbiasshift;  
  229.             j = contest(b, g, r);  
  230.   
  231.             altersingle(alpha, j, b, g, r);  
  232.             if (rad != 0)  
  233.                 alterneigh(rad, j, b, g, r); /* alter neighbours */  
  234.   
  235.             pix += step;  
  236.             if (pix >= lim)  
  237.                 pix -= lengthcount;  
  238.   
  239.             i++;  
  240.             if (delta == 0)  
  241.                 delta = 1;  
  242.             if (i % delta == 0) {  
  243.                 alpha -= alpha / alphadec;  
  244.                 radius -= radius / radiusdec;  
  245.                 rad = radius >> radiusbiasshift;  
  246.                 if (rad <= 1)  
  247.                     rad = 0;  
  248.                 for (j = 0; j < rad; j++)  
  249.                     radpower[j] =  
  250.                             alpha * (((rad * rad - j * j) * radbias) / (rad * rad));  
  251.             }  
  252.         }  
  253.         //fprintf(stderr,"finished 1D learning: final alpha=%f !\n",((float)alpha)/initalpha);  
  254.     }  
  255.   
  256.     /* Search for BGR values 0..255 (after net is unbiased) and return colour index 
  257.        ---------------------------------------------------------------------------- */  
  258.     public int map(int b, int g, int r) {  
  259.   
  260.         int i, j, dist, a, bestd;  
  261.         int[] p;  
  262.         int best;  
  263.   
  264.         bestd = 1000/* biggest possible dist is 256*3 */  
  265.         best = -1;  
  266.         i = netindex[g]; /* index on g */  
  267.         j = i - 1/* start at netindex[g] and work outwards */  
  268.   
  269.         while ((i < netsize) || (j >= 0)) {  
  270.             if (i < netsize) {  
  271.                 p = network[i];  
  272.                 dist = p[1] - g; /* inx key */  
  273.                 if (dist >= bestd)  
  274.                     i = netsize; /* stop iter */  
  275.                 else {  
  276.                     i++;  
  277.                     if (dist < 0)  
  278.                         dist = -dist;  
  279.                     a = p[0] - b;  
  280.                     if (a < 0)  
  281.                         a = -a;  
  282.                     dist += a;  
  283.                     if (dist < bestd) {  
  284.                         a = p[2] - r;  
  285.                         if (a < 0)  
  286.                             a = -a;  
  287.                         dist += a;  
  288.                         if (dist < bestd) {  
  289.                             bestd = dist;  
  290.                             best = p[3];  
  291.                         }  
  292.                     }  
  293.                 }  
  294.             }  
  295.             if (j >= 0) {  
  296.                 p = network[j];  
  297.                 dist = g - p[1]; /* inx key - reverse dif */  
  298.                 if (dist >= bestd)  
  299.                     j = -1/* stop iter */  
  300.                 else {  
  301.                     j--;  
  302.                     if (dist < 0)  
  303.                         dist = -dist;  
  304.                     a = p[0] - b;  
  305.                     if (a < 0)  
  306.                         a = -a;  
  307.                     dist += a;  
  308.                     if (dist < bestd) {  
  309.                         a = p[2] - r;  
  310.                         if (a < 0)  
  311.                             a = -a;  
  312.                         dist += a;  
  313.                         if (dist < bestd) {  
  314.                             bestd = dist;  
  315.                             best = p[3];  
  316.                         }  
  317.                     }  
  318.                 }  
  319.             }  
  320.         }  
  321.         return (best);  
  322.     }  
  323.     public byte[] process() {  
  324.         learn();  
  325.         unbiasnet();  
  326.         inxbuild();  
  327.         return colorMap();  
  328.     }  
  329.   
  330.     /* Unbias network to give byte values 0..255 and record position i to prepare for sort 
  331.        ----------------------------------------------------------------------------------- */  
  332.     public void unbiasnet() {  
  333.         int i;  
  334.         for (i = 0; i < netsize; i++) {  
  335.             network[i][0] >>= netbiasshift;  
  336.             network[i][1] >>= netbiasshift;  
  337.             network[i][2] >>= netbiasshift;  
  338.             network[i][3] = i; /* record colour no */  
  339.         }  
  340.     }  
  341.   
  342.     /* Move adjacent neurons by precomputed alpha*(1-((i-j)^2/[r]^2)) in radpower[|i-j|] 
  343.        --------------------------------------------------------------------------------- */  
  344.     protected void alterneigh(int rad, int i, int b, int g, int r) {  
  345.   
  346.         int j, k, lo, hi, a, m;  
  347.         int[] p;  
  348.   
  349.         lo = i - rad;  
  350.         if (lo < -1)  
  351.             lo = -1;  
  352.         hi = i + rad;  
  353.         if (hi > netsize)  
  354.             hi = netsize;  
  355.   
  356.         j = i + 1;  
  357.         k = i - 1;  
  358.         m = 1;  
  359.         while ((j < hi) || (k > lo)) {  
  360.             a = radpower[m++];  
  361.             if (j < hi) {  
  362.                 p = network[j++];  
  363.                 try {  
  364.                     p[0] -= (a * (p[0] - b)) / alpharadbias;  
  365.                     p[1] -= (a * (p[1] - g)) / alpharadbias;  
  366.                     p[2] -= (a * (p[2] - r)) / alpharadbias;  
  367.                 } catch (Exception e) {  
  368.                 } // prevents 1.3 miscompilation  
  369.             }  
  370.             if (k > lo) {  
  371.                 p = network[k--];  
  372.                 try {  
  373.                     p[0] -= (a * (p[0] - b)) / alpharadbias;  
  374.                     p[1] -= (a * (p[1] - g)) / alpharadbias;  
  375.                     p[2] -= (a * (p[2] - r)) / alpharadbias;  
  376.                 } catch (Exception e) {  
  377.                 }  
  378.             }  
  379.         }  
  380.     }  
  381.   
  382.     /* Move neuron i towards biased (b,g,r) by factor alpha 
  383.        ---------------------------------------------------- */  
  384.     protected void altersingle(int alpha, int i, int b, int g, int r) {  
  385.   
  386.         /* alter hit neuron */  
  387.         int[] n = network[i];  
  388.         n[0] -= (alpha * (n[0] - b)) / initalpha;  
  389.         n[1] -= (alpha * (n[1] - g)) / initalpha;  
  390.         n[2] -= (alpha * (n[2] - r)) / initalpha;  
  391.     }  
  392.   
  393.     /* Search for biased BGR values 
  394.        ---------------------------- */  
  395.     protected int contest(int b, int g, int r) {  
  396.   
  397.         /* finds closest neuron (min dist) and updates freq */  
  398.         /* finds best neuron (min dist-bias) and returns position */  
  399.         /* for frequently chosen neurons, freq[i] is high and bias[i] is negative */  
  400.         /* bias[i] = gamma*((1/netsize)-freq[i]) */  
  401.   
  402.         int i, dist, a, biasdist, betafreq;  
  403.         int bestpos, bestbiaspos, bestd, bestbiasd;  
  404.         int[] n;  
  405.   
  406.         bestd = ~(((int1) << 31);  
  407.         bestbiasd = bestd;  
  408.         bestpos = -1;  
  409.         bestbiaspos = bestpos;  
  410.   
  411.         for (i = 0; i < netsize; i++) {  
  412.             n = network[i];  
  413.             dist = n[0] - b;  
  414.             if (dist < 0)  
  415.                 dist = -dist;  
  416.             a = n[1] - g;  
  417.             if (a < 0)  
  418.                 a = -a;  
  419.             dist += a;  
  420.             a = n[2] - r;  
  421.             if (a < 0)  
  422.                 a = -a;  
  423.             dist += a;  
  424.             if (dist < bestd) {  
  425.                 bestd = dist;  
  426.                 bestpos = i;  
  427.             }  
  428.             biasdist = dist - ((bias[i]) >> (intbiasshift - netbiasshift));  
  429.             if (biasdist < bestbiasd) {  
  430.                 bestbiasd = biasdist;  
  431.                 bestbiaspos = i;  
  432.             }  
  433.             betafreq = (freq[i] >> betashift);  
  434.             freq[i] -= betafreq;  
  435.             bias[i] += (betafreq << gammashift);  
  436.         }  
  437.         freq[bestpos] += beta;  
  438.         bias[bestpos] -= betagamma;  
  439.         return (bestbiaspos);  
  440.     }  
  441. }  

[java]  view plain  copy
  1. package net.loyin.util.vcode;  
  2.   
  3. import java.util.Random;  
  4.   
  5. /** 
  6.  * <p>随机工具类</p> 
  7.  * 
  8.  * @author: wuhongjun 
  9.  * @version:1.0 
  10.  */  
  11. public class Randoms  
  12. {  
  13.     private static final Random RANDOM = new Random();  
  14.     //定义验证码字符.去除了O和I等容易混淆的字母  
  15.     public static final char ALPHA[]={'A','B','C','D','E','F','G','H','J','K','L','M','N','P','Q','R','S','T','U','V','W','X','Y','Z'  
  16.             ,'a','b','c','d','e','f','g','h','i','j','k','m','n','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7','8','9'};  
  17.   
  18.     /** 
  19.      * 产生两个数之间的随机数 
  20.      * @param min 小数 
  21.      * @param max 比min大的数 
  22.      * @return int 随机数字 
  23.      */  
  24.     public static int num(int min, int max)  
  25.     {  
  26.         return min + RANDOM.nextInt(max - min);  
  27.     }  
  28.   
  29.     /** 
  30.      * 产生0--num的随机数,不包括num 
  31.      * @param num 数字 
  32.      * @return int 随机数字 
  33.      */  
  34.     public static int num(int num)  
  35.     {  
  36.         return RANDOM.nextInt(num);  
  37.     }  
  38.   
  39.     public static char alpha()  
  40.     {  
  41.         return ALPHA[num(0, ALPHA.length)];  
  42.     }  
  43. }  

[java]  view plain  copy
  1. package net.loyin.util.vcode;  
  2.   
  3. import java.awt.AlphaComposite;  
  4. import java.awt.Color;  
  5. import java.awt.Font;  
  6. import java.awt.Graphics2D;  
  7. import java.awt.image.BufferedImage;  
  8. import java.io.IOException;  
  9. import java.io.OutputStream;  
  10. import static net.loyin.util.vcode.Randoms.num;  
  11. import javax.imageio.ImageIO;  
  12. /** 
  13.  * <p>png格式验证码</p> 
  14.  * 
  15.  * @author: wuhongjun 
  16.  * @version:1.0 
  17.  */  
  18. public class SpecCaptcha extends Captcha  
  19. {  
  20.     public SpecCaptcha()  
  21.     {  
  22.     }  
  23.     public SpecCaptcha(int width, int height)  
  24.     {  
  25.         this.width = width;  
  26.         this.height = height;  
  27.     }  
  28.     public SpecCaptcha(int width, int height, int len){  
  29.         this(width,height);  
  30.         this.len = len;  
  31.     }  
  32.     public SpecCaptcha(int width, int height, int len, Font font){  
  33.         this(width,height,len);  
  34.         this.font = font;  
  35.     }  
  36.     /** 
  37.      * 生成验证码 
  38.      * @throws java.io.IOException IO异常 
  39.      */  
  40.     @Override  
  41.     public void out(OutputStream out){  
  42.         graphicsImage(alphas(), out);  
  43.     }  
  44.   
  45.     /** 
  46.      * 画随机码图 
  47.      * @param strs 文本 
  48.      * @param out 输出流 
  49.      */  
  50.     private boolean graphicsImage(char[] strs, OutputStream out){  
  51.         boolean ok = false;  
  52.         try  
  53.         {  
  54.             BufferedImage bi = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);  
  55.             Graphics2D g = (Graphics2D)bi.getGraphics();  
  56.             AlphaComposite ac3;  
  57.             Color color ;  
  58.             int len = strs.length;  
  59.             g.setColor(Color.WHITE);  
  60.             g.fillRect(0,0,width,height);  
  61.             // 随机画干扰的蛋蛋  
  62.             for(int i=0;i<15;i++){  
  63.                 color = color(150250);  
  64.                 g.setColor(color);  
  65.                 g.drawOval(num(width), num(height), 5+num(10), 5+num(10));// 画蛋蛋,有蛋的生活才精彩  
  66.                 color = null;  
  67.             }  
  68.             g.setFont(font);  
  69.             int h  = height - ((height - font.getSize()) >>1),  
  70.                 w = width/len,  
  71.                 size = w-font.getSize()+1;  
  72.             /* 画字符串 */  
  73.             for(int i=0;i<len;i++)  
  74.             {  
  75.                 ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f);// 指定透明度  
  76.                 g.setComposite(ac3);  
  77.                 color = new Color(20 + num(110), 20 + num(110), 20 + num(110));// 对每个字符都用随机颜色  
  78.                 g.setColor(color);  
  79.                 g.drawString(strs[i]+"",(width-(len-i)*w)+size, h-4);  
  80.                 color = null;  
  81.                 ac3 = null;  
  82.             }  
  83.             ImageIO.write(bi, "png", out);  
  84.             out.flush();  
  85.             ok = true;  
  86.         }catch (IOException e){  
  87.             ok = false;  
  88.         }finally  
  89.         {  
  90.             Streams.close(out);  
  91.         }  
  92.         return ok;  
  93.     }  
  94. }  

[java]  view plain  copy
  1. package net.loyin.util.vcode;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5. import java.io.OutputStream;  
  6.   
  7. public class Streams {  
  8.     /** 
  9.      * 关闭输入流 
  10.      *  
  11.      * @param in 
  12.      *            输入流 
  13.      */  
  14.     public static void close(InputStream in) {  
  15.         if (in != null) {  
  16.             try {  
  17.                 in.close();  
  18.             } catch (IOException ioex) {  
  19.                 // ignore  
  20.             }  
  21.         }  
  22.     }  
  23.   
  24.     /** 
  25.      * 关闭输出流 
  26.      *  
  27.      * @param out 
  28.      *            输出流 
  29.      */  
  30.     public static void close(OutputStream out) {  
  31.         if (out != null) {  
  32.             try {  
  33.                 out.flush();  
  34.             } catch (IOException ioex) {  
  35.                 // ignore  
  36.             }  
  37.             try {  
  38.                 out.close();  
  39.             } catch (IOException ioex) {  
  40.                 // ignore  
  41.             }  
  42.         }  
  43.     }  
  44. }  

[java]  view plain  copy
  1. package net.loyin.util.vcode;  
  2.   
  3. import java.io.FileOutputStream;  
  4.   
  5. public class TestClz {  
  6.     public static void main(String[] args) {  
  7.         try{  
  8.          Captcha captcha = new SpecCaptcha(150,40,5);// png格式验证码  
  9.             captcha.out(new FileOutputStream("E:/1.png"));  
  10.             captcha = new GifCaptcha(150,40,5);//   gif格式动画验证码  
  11.             captcha.out(new FileOutputStream("E:/1.gif"));  
  12.         }catch(Exception e){  
  13.             e.printStackTrace();  
  14.         }  
  15.     }  
  16. }  
Node.js 图形 GIF 验证码通常是指在 Node.js 环境下生成并用于验证用户身份的动态图片验证码,它包含一组随机图像、字母、数字组合,有时还会包括动画效果。在 Node.js 中,可以借助一些库如 `sharp` (处理图片) 和 `验证码生成器库` (如 `speakeasy`, `qrcode-generator`) 来实现这个功能: 1. **安装依赖**:首先需要安装必要的模块,例如 `sharp` 用于处理图像,`speakeasy` 或类似的库用于生成验证码文本。 ```bash npm install sharp speakeasy ``` 2. **生成验证码**:创建一个函数,通过指定长度生成随机字符,并将其转换为 GIF 图片。例如,`speakeasy` 库允许你生成 QR 码样式验证码。 ```javascript const speakeasy = require('speakeasy'); const sharp = require('sharp'); function generateGifCode(length) { const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; let code = ''; for (let i = 0; i < length; i++) { code += chars[Math.floor(Math.random() * chars.length)]; } return code; } function createGif验证码(width, height, code) { // 使用sharp库生成二维码或自定义图案,将验证码作为内容 return sharp({ create: { width, height, channels: 1 }, }) .resize(width, height) .toBuffer() .then((buffer) => { const qr = speakeasy.generateBarcode({ type: 'gif', text: code }); return qr.replace(/data:image\/png/, `data:image/gif`); }); } ``` 3. **渲染验证码到文件**:将生成的 Base64 编码的 GIF 内容保存到磁盘上供前端显示。 ```javascript createGif验证码(100, 50, generateGifCode(6)) .then((base64Image) => { fs.writeFileSync('captcha.gif', Buffer.from(base64Image, 'base64')); }) .catch(console.error); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值