• GIFDecoder源码分析


    源码见:ddxxll2008/gifdecoder_java

    run()

    public void run(){
    		if(in != null){
    			readStream();
    		}else if(gifData != null){
    			readByte();
    		}
    	}
    	
    	private int readByte(){
    		in = new ByteArrayInputStream(gifData);
    		gifData = null;
    		return readStream();
    	}
    

    GifDecoder的入口是run函数,里面包含了readStream()和readByte()两个方法,但是readByte()里也返回了一个readStream(),所以从readStream()方法进行分析。

    readStream

    private int readStream(){
    		init();
    		if(in != null){
    			readHeader();
    			if(!err()){
    				readContents();
    				if(frameCount < 0){
    					status = STATUS_FORMAT_ERROR;
    					action.parseOk(false,-1);
    				}else{
    					status = STATUS_FINISH;
    					action.parseOk(true,-1);
    				}
    			}
    			try {
    				in.close();
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}else {
    			status = STATUS_OPEN_ERROR;
    			action.parseOk(false,-1);
    		}
    		return status;
    	}
    	
    

    readStream()里先进行一些参数的初始化,然后读取Gif头文件。

    private void readHeader() {
    		String id = "";
    		for (int i = 0; i < 6; i++) {
    			id += (char) read();
    		}
    		if (!id.startsWith("GIF")) {
    			status = STATUS_FORMAT_ERROR;
    			return;
    		}
    		readLSD();
    		if (gctFlag && !err()) {
    			gct = readColorTable(gctSize);
    			bgColor = gct[bgIndex];
    		}
    	}
    	
    	private void readLSD() {
    		// logical screen size
    		width = readShort();
    		height = readShort();
    		// packed fields
    		int packed = read();
    		gctFlag = (packed & 0x80) != 0; // 1 : global color table flag
    		// 2-4 : color resolution
    		// 5 : gct sort flag
    		gctSize = 2 << (packed & 7); // 6-8 : gct size
    		bgIndex = read(); // background color index
    		pixelAspect = read(); // pixel aspect ratio
    	}
    	
    	private int[] readColorTable(int ncolors) {
    		int nbytes = 3 * ncolors;
    		int[] tab = null;
    		byte[] c = new byte[nbytes];
    		int n = 0;
    		try {
    			n = in.read(c);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    		if (n < nbytes) {
    			status = STATUS_FORMAT_ERROR;
    		} else {
    			tab = new int[256]; // max size to avoid bounds checks
    			int i = 0;
    			int j = 0;
    			while (i < ncolors) {
    				int r = ((int) c[j++]) & 0xff;
    				int g = ((int) c[j++]) & 0xff;
    				int b = ((int) c[j++]) & 0xff;
    				tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b;
    			}
    		}
    		return tab;
    	}
    

    readHeader()里主要是判断是否是Gif文件,如果是的话,则在readLSD()里获得Gif的一些基本信息。readLSD()读取的信息包括长宽,颜色和颜色索引等。之后通过readColorTable(int ncolors)读取颜色表单。之后就是通过readContents()来获取Gif的内容了。

    readContents()

    private void readContents() {
    		// read GIF file content blocks
    		boolean done = false;
    		while (!(done || err())) {
    			int code = read();
    			switch (code) {
    				case 0x2C: // image separator
    					readImage();
    					break;
    				case 0x21: // extension
    					code = read();
    					switch (code) {
    						case 0xf9: // graphics control extension
    							readGraphicControlExt();
    							break;
    						case 0xff: // application extension
    							readBlock();
    							String app = "";
    							for (int i = 0; i < 11; i++) {
    								app += (char) block[i];
    							}
    							if (app.equals("NETSCAPE2.0")) {
    								readNetscapeExt();
    							} else {
    								skip(); // don't care
    							}
    							break;
    						default: // uninteresting extension
    							skip();
    					}
    					break;
    				case 0x3b: // terminator
    					done = true;
    					break;
    				case 0x00: // bad byte, but keep going and see what happens
    					break;
    				default:
    					status = STATUS_FORMAT_ERROR;
    			}
    		}
    	}
    

    在readContents()里,只要没有发生错误,就会一直读取下去,直到读取完成。这里面的readImage()方法是用来获取图片信息的。通过decodeImageData()方法来获取各个像素点的数据,之后新建一个bitmap,通过setPixels()来设置像素点的信息。然后根据此bitmap生成一个GifFrame的对象,并通过action.parseOk(true, frameCount)返回解析成功以及解析成功的帧数。全部解析完成后,帧数为-1。

    private void readImage() {
    		ix = readShort(); // (sub)image position & size
    		iy = readShort();
    		iw = readShort();
    		ih = readShort();
    		int packed = read();
    		lctFlag = (packed & 0x80) != 0; // 1 - local color table flag
    		interlace = (packed & 0x40) != 0; // 2 - interlace flag
    		// 3 - sort flag
    		// 4-5 - reserved
    		lctSize = 2 << (packed & 7); // 6-8 - local color table size
    		if (lctFlag) {
    			lct = readColorTable(lctSize); // read table
    			act = lct; // make local table active
    		} else {
    			act = gct; // make global table active
    			if (bgIndex == transIndex) {
    				bgColor = 0;
    			}
    		}
    		int save = 0;
    		if (transparency) {
    			save = act[transIndex];
    			act[transIndex] = 0; // set transparent color if specified
    		}
    		if (act == null) {
    			status = STATUS_FORMAT_ERROR; // no color table defined
    		}
    		if (err()) {
    			return;
    		}
    		decodeImageData(); // decode pixel data
    		skip();
    		if (err()) {
    			return;
    		}
    		frameCount++;
    		// create new image to receive frame data
    		image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
    		// createImage(width, height);
    		setPixels(); // transfer pixel data to image
    		if (gifFrame == null) {
    			gifFrame = new GifFrame(image, delay);
    			currentFrame = gifFrame;
    		} else {
    			GifFrame f = gifFrame;
    			while(f.nextFrame != null){
    				f = f.nextFrame;
    			}
    			f.nextFrame = new GifFrame(image, delay);
    		}
    		// frames.addElement(new GifFrame(image, delay)); // add image to frame
    		// list
    		if (transparency) {
    			act[transIndex] = save;
    		}
    		resetFrame();
    		action.parseOk(true, frameCount);
    	}
    

    readContents()里还有读取其他信息的函数,比如readGraphicControlExt(),readBlock()和readNetscapeExt()。这些都是获取一些信息用的函数。

    使用方法

    GIFDecoder里有很多方法,可以获取Gif的信息。先构造一个GifDecoder,然后调用gifDecoder.run()方法,就可以得到一个完整的GIFDecoder对象,之后便能通过GIFDecoder里的各种方法去获得Gif图片的信息了。

    //解析gif图片
    gifDecoder = new GifDecoder(fileInputStream, new GifAction() {
    	@Override
    	public void parseOk(boolean parseStatus, int frameIndex) {
    		Logger.d(parseStatus + "  " + frameIndex);
    	}
    });
    gifDecoder.run();
    
  • 相关阅读:
    老树新芽,在ES6下使用Express
    Swift3翻天覆地的改变
    NodeJs回调操作Promise化
    Node的关系型数据库ORM库:bookshelf
    基于Node的PetShop,RESTful API以及认证
    基于Node的PetShop,oauth2认证RESTful API
    Mongoose轻松搞定MongoDB,不要回调!
    Thymeleaf常用语法:表达式语法之运算符
    Thymeleaf对象的使用:日期对象
    Thymeleaf对象的使用:字符串对象
  • 原文地址:https://www.cnblogs.com/xl-phoenix/p/6541083.html
Copyright © 2020-2023  润新知