Jsp实现动态验证码(由5个类组成的gif动验证码)

本文介绍了一种基于Java的GIF验证码生成方法,并详细解释了如何通过GifValidateCode类生成动态验证码图片。此外,还提供了code.jsp页面的具体实现方式及如何在用户注册页面集成验证码功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、先将“gif验证码辅助类(4个)”,复制到src文件夹下(最好在该文件夹下建一个util包)
2、再在这个文件夹下添加一个类叫GifValidateCode。类它是用来
jsp页面直接调用GifValidateCode类的getValidateCode()方法来生成图片的。

3、用code.jsp页面来构造GIF图片。

4、在其他(登录或注册)页面以图片的形式引用code.jsp页面 。

 以下只是一个主要类(GifValidateCode类)、一个jsp页面和一个html页面。 

[java]  view plain  copy
  1. import <a href="http://lib.csdn.net/base/javase" class='replace_word' title="Java SE知识库" target='_blank' style='color:#df3434; font-weight:bold;'>Java</a>.awt.*;  
  2. import java.io.*;  
  3. import java.util.Date;  
  4. import java.util.*;  
  5. import java.awt.image.*;  
  6.   
  7.   
  8. public class GifValidateCode {  
  9.     //定义验证码字符。去除了O和I等容易混淆的字母(也可写成)  
  10.     String[] s = {"A""B""C""D""E""F""G""H""G""K","M""N""P""Q""R""S",  
  11.       "T""U""V""W","X""Y""Z""a""b""c""d""e""f""g","h""i""j",   
  12.       "k""m""n""p""q""r""s""t""u""v""w""x""y""z""1""2""3",  
  13.       "4""5""6""7""8""9""地""在""要""工""上""是""中""国""不""这"};  
  14.   
  15.     //定义生成的验证码的宽度和高度  
  16.     int width = 160;  
  17.     int height = 35;  
  18.   
  19.     /** 
  20.      * 获得(生成)GIF验证码 
  21.      * @param os 
  22.      * @return String 系统自动生成的验证码的内容 
  23.      */  
  24.     public String getValidateCode(OutputStream os) {  
  25.         BufferedImage frame = null;  
  26.         @SuppressWarnings("unused")  
  27.   Graphics2D teg = null;  
  28.         @SuppressWarnings("unused")  
  29.   AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,1);  
  30.         AnimatedGifEncoder agf = new AnimatedGifEncoder();  
  31.         agf.start(os);  
  32.         agf.setQuality(10);  
  33.         agf.setDelay(100);  
  34.         agf.setRepeat(0);  
  35.   
  36.         // 生成6个随机字符  
  37.         String rands[] = new String[6];  
  38.         for (int i = 0; i < 6; i++) {  
  39.             rands[i] = s[this.randomInt(0, s.length)];  
  40.         }  
  41.   
  42.         //分别使用6种字体  
  43.         Font[] font = new Font[6];  
  44.         font[0] = new Font("Gungsuh", Font.BOLD, 24);  
  45.         font[1] = new Font("宋体", Font.BOLD, 24);  
  46.         font[2] = new Font("Times New Roman", Font.BOLD, 24);  
  47.         font[3] = new Font("隶书", Font.BOLD, 24);  
  48.         font[4] = new Font("Arial Unicode MS", Font.BOLD, 24);  
  49.         font[5] = new Font("方正舒体", Font.BOLD, 24);  
  50.   
  51.         //生成各种颜色  
  52.         Color bgcolor = new Color(255,255,255);  
  53.         Color linecolor = getRandColor(200250);  
  54.         Color fontcolor[] = new Color[6];  
  55.         Random random = new Random();  
  56.         for (int i = 0; i < 6; i++) {  
  57.             fontcolor[i] = new Color(20 + random.nextInt(110),  
  58.               20 + random.nextInt(110), 20 + random.nextInt(110));  
  59.         }  
  60.         //生成Gif信息类  
  61.         for (int i = 0; i < font.length; i++) {  
  62.             frame = this.getImage(bgcolor, linecolor, fontcolor, rands, font, i);  
  63.             agf.addFrame(frame);  
  64.             frame.flush();  
  65.         }  
  66.        agf.finish();  
  67.        String fonts = rands[0] + rands[1]+rands[2]+rands[3]+rands[4]+rands[5];  
  68.        return fonts;  
  69.     }  
  70.     /* 
  71.      * // 随机产生150个干扰点 
  72.  g.setColor(Color.gray); 
  73.  Random rand = new Random(); 
  74.  for (int i = 0; i < 150; i++) { 
  75.   g.setColor(new Color(0x123456));//设置干扰点的颜色 
  76.   int x = rand.nextInt(width); 
  77.   int y = rand.nextInt(height); 
  78.   g.drawOval(x, y, 1, 1); //可以使用干扰线等其他的方式只是调用不同的方法而已 
  79.  } 
  80.  Random rnd = new Random(new Date().getTime()); 
  81.   for(int i=0;i<10;i++){       
  82.            // g.setColor(getRandomColor(100, 155));    //随机线条的颜色 
  83.             int x1 = rnd.nextInt(width);    //线条两端坐标值   
  84.             int y1 = rnd.nextInt(height);   
  85.             int x2 = rnd.nextInt(width);     
  86.             int y2 = rnd.nextInt(height);     
  87.             g.drawLine(x1, y1, x2, y2); //画线条     
  88.         }   
  89.      * */  
  90.       
  91.     //out.clear();  
  92.     //out = pageContext.pushBody();  
  93.   
  94.     /** 
  95.      * 获得图片缓冲 
  96.      * @param bgcolor  背景颜色 
  97.      * @param linecolor 背景线的颜色 
  98.      * @param fontcolor  字体颜色 
  99.      * @param str 
  100.      * @param font 字体 
  101.      * @param flag 
  102.      * @return BufferedImage 
  103.      */  
  104.     private BufferedImage getImage(Color bgcolor, Color linecolor,Color[] fontcolor,   
  105.       String[] str, Font[] font,int flag) {  
  106.         BufferedImage image = new BufferedImage(width, height,  
  107.                                                 BufferedImage.TYPE_INT_RGB);  
  108.         //或得图形上下文  
  109.         Graphics2D g2d = image.createGraphics();  
  110.         //利用指定颜色填充背景  
  111.         g2d.setColor(bgcolor);  
  112.         g2d.fillRect(00, width, height);  
  113.         //画背景线 3*3  (数字越大格子越密)  
  114.         g2d.setColor(linecolor);  
  115.         for (int i = 0; i < height / 3; i++)  
  116.             g2d.drawLine(0, i * 3, width, i * 3);  
  117.         for (int i = 0; i < width / 3; i++)  
  118.             g2d.drawLine(i * 30, i * 3, height);  
  119.         // 画背景LOGO  
  120.         /*AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 
  121.                 0.2f); 
  122.         g2d.setComposite(ac); 
  123.         g2d.setFont(new Font("隶书", Font.ITALIC + Font.BOLD, 26)); 
  124.         g2d.setColor(Color.red); 
  125.         g2d.drawString("HAHA小组", 19, 25);*/  
  126.   
  127.         //以下生成验证码  
  128.         //透明度从0 循环到1 步长为0.2 。一共6个字母  
  129.         //int[] height ={23,31,27,22,25,29};  
  130.           
  131.         int[] height = new int[6];  
  132.           
  133.         Random rand = new Random();  
  134.           
  135.         for(int i=0; i<6; i++){  
  136.             height[i] = rand.nextInt(15) + 20;  
  137.         }  
  138.         AlphaComposite ac3 = null;  
  139.         for (int i = 0; i < str.length; i++) {  
  140.             g2d.setFont(font[i]);  
  141.             ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,  
  142.                                              getAlpha(flag, i));  
  143.             g2d.setComposite(ac3);  
  144.             g2d.setColor(fontcolor[i]);  
  145.             g2d.drawString(str[i], 25 * i + 8, height[i]);  
  146.         }  
  147.           
  148.         // 随机产生20个干扰点  
  149.      for (int i = 0; i < 200; i++) {  
  150.       g2d.setColor(new Color(0x123456));//设置干扰点的随机颜色  
  151.       int x = rand.nextInt(width);  
  152.       int y = rand.nextInt(this.height);  
  153.         
  154.       g2d.drawOval(x, y, 11); //可以使用干扰线等其他的方式只是调用不同的方法而已  
  155.      }  
  156.        
  157.      // 画15条干扰线  
  158.      Random rnd = new Random(new Date().getTime());  
  159.      for(int i=0;i<15;i++){   
  160.         
  161.    g2d.setColor(getRandColor(100155));  //设置干扰线的随机颜色  
  162.          int x1 = rnd.nextInt(width);    //线条两端坐标值    
  163.          int y1 = rnd.nextInt(this.height);    
  164.          int x2 = rnd.nextInt(width);      
  165.          int y2 = rnd.nextInt(this.height);      
  166.          g2d.drawLine(x1, y1, x2, y2); //画线条      
  167.      }    
  168.        
  169.         g2d.dispose();  
  170.         return image;  
  171.     }  
  172.   
  173.     /** 
  174.      * 获得循环透明度,从0到1 步长为0.2 
  175.      * @param i 
  176.      * @param j 
  177.      * @return float 
  178.      */  
  179.     private float getAlpha(int i, int j) {  
  180.         if ((i + j) > 5)  
  181.             return ((i + j) * 0.2f - 1.2f);  
  182.         else   
  183.             return (i + j) * 0.2f;          
  184.     }  
  185.   
  186.     /** 
  187.      * 获得随机颜色 
  188.      * @param fc 给定范围获得随机颜色 
  189.      * @param bc 给定范围获得随机颜色 
  190.      * @return Color 
  191.      */  
  192.     private Color getRandColor(int fc, int bc) {   
  193.         Random random = new Random();  
  194.         if (fc > 255)  
  195.             fc = 255;  
  196.         if (bc > 255)  
  197.             bc = 255;  
  198.         int r = fc + random.nextInt(bc - fc);  
  199.         int g = fc + random.nextInt(bc - fc);  
  200.         int b = fc + random.nextInt(bc - fc);  
  201.         return new Color(r, g, b);  
  202.     }  
  203.   
  204.     /** 
  205.      * 产生随机数 
  206.      * 返回[from,to)之间的一个随机整数 
  207.      * @param from 起始值 
  208.      * @param to 结束值 
  209.      * @return  [from,to)之间的一个随机整数 
  210.      */  
  211.     Random r = new Random();  
  212.     private int randomInt(int from, int to) {  
  213.         return from + r.nextInt(to - from);  
  214.     }  
  215. }  

下面是一个code.jsp页面的全部代码

[java] view plain copy
  1. <%@ page contentType="text/html" pageEncoding="GBK"  
  2.  import="java.util.*,javax.imageio.*,java.io.*,java.awt.*,  
  3.  java.awt.image.*,com.accp.shi.validatecode.*"%>  
  4. <%  
  5.  GifValidateCode gvc = new GifValidateCode();  
  6.  OutputStream stream = response.getOutputStream();  // 获得输出流  
  7.  String code = gvc.getValidateCode(stream);  
  8.  out.clear();  //释放在jsp中使用的对象  
  9.  out = pageContext.pushBody();  //释放在jsp中使用的对象  
  10. %>  

以下是一个html页面,是用于用户注册用的(根据实际情况可添加一些选项)

[xhtml] view plain copy
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">  
  2. <html>  
  3. <mce:script type="text/<a href="http://lib.csdn.net/base/javascript" class='replace_word' title="JavaScript知识库" target='_blank' style='color:#df3434; font-weight:bold;'>JavaScript</a>"><!--  
  4.  function changeValidateCode()  
  5.  {  
  6.   var imgCode = document.getElementById("imgCode");  
  7.   imgCode.src = "code.jsp?s="+new Date().getTime(); //当点击换一张时可清空缓存中的原有页面,所以添加了一个时间作为参数传过去  
  8.  }  
  9. // --></mce:script>  
  10. <head>  
  11. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">  
  12. <title>Insert title here</title>  
  13. </head>  
  14. <body>  
  15. <form action="">  
  16.  用户名:<input type="text" name="txtName"><br>  
  17.  密 码:<input type="password" name="txtPassword"><br>  
  18.  <img alt="验证码" src="code.jsp" mce_src="code.jsp" id="imgCode"><a href="javascript:changeValidateCode()" mce_href="javascript:changeValidateCode()">看不清,换一张</a><br>  
  19.  <input type="submit" value="注 册">   
  20. </form>  
  21. </body>  
  22. </html>  

下面是4个辅助类

之一:AnimatedGifEncoder.java类

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

之二:GifDecoder.java类

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

之三:LZWEncoder.java类

[c-sharp]  view plain  copy
  1. package com.accp.bookshop.util;  
  2.   
  3. import java.io.OutputStream;  
  4. import java.io.IOException;  
  5.   
  6. //==============================================================================  
  7. //  Adapted from Jef Poskanzer's <a href="http://lib.csdn.net/base/java" class='replace_word' title="Java 知识库" target='_blank' style='color:#df3434; font-weight:bold;'>Java </a>port by way of J. M. G. Elliott.  
  8. //  K Weiner 12/00  
  9.   
  10. class LZWEncoder {  
  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.     LZWEncoder(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. }  

之四:NeuQuant.java类

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值