TextView图文混排Gif

2024-02-25 13:58
文章标签 gif textview 图文混排

本文主要是介绍TextView图文混排Gif,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.gif解析器

import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;import java.io.InputStream;
import java.util.Vector;public class GifDecoder {/*** File read status: No errors.*/public static final int STATUS_OK = 0;/*** File read status: Error decoding file (may be partially decoded)*/public static final int STATUS_FORMAT_ERROR = 1;/*** File read status: Unable to open source.*/public static final int STATUS_OPEN_ERROR = 2;/** max decoder pixel stack size */protected static final int MAX_STACK_SIZE = 4096;protected InputStream in;protected int status;protected int width; // full image widthprotected int height; // full image heightprotected boolean gctFlag; // global color table usedprotected int gctSize; // size of global color tableprotected int loopCount = 1; // iterations; 0 = repeat foreverprotected int[] gct; // global color tableprotected int[] lct; // local color tableprotected int[] act; // active color tableprotected int bgIndex; // background color indexprotected int bgColor; // background colorprotected int lastBgColor; // previous bg colorprotected int pixelAspect; // pixel aspect ratioprotected boolean lctFlag; // local color table flagprotected boolean interlace; // interlace flagprotected int lctSize; // local color table sizeprotected int ix, iy, iw, ih; // current image rectangleprotected int lrx, lry, lrw, lrh;protected Bitmap image; // current frameprotected Bitmap lastBitmap; // previous frameprotected byte[] block = new byte[256]; // current data blockprotected int blockSize = 0; // block size last graphic control extension infoprotected int dispose = 0; // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prevprotected int lastDispose = 0;protected boolean transparency = false; // use transparent colorprotected int delay = 0; // delay in millisecondsprotected int transIndex; // transparent color index// LZW decoder working arraysprotected short[] prefix;protected byte[] suffix;protected byte[] pixelStack;protected byte[] pixels;protected Vector<GifFrame> frames; // frames read from current fileprotected int frameCount;private static class GifFrame {public GifFrame(Bitmap im, int del) {image = im;delay = del;}public Bitmap image;public int delay;}/*** Gets display duration for specified frame.* * @param n*          int index of frame* @return delay in milliseconds*/public int getDelay(int n) {delay = -1;if ((n >= 0) && (n < frameCount)) {delay = frames.elementAt(n).delay;}return delay;}/*** Gets the number of frames read from file.* * @return frame count*/public int getFrameCount() {return frameCount;}/*** Gets the first (or only) image read.* * @return BufferedBitmap containing first frame, or null if none.*/public Bitmap getBitmap() {return getFrame(0);}/*** Gets the "Netscape" iteration count, if any. A count of 0 means repeat indefinitiely.* * @return iteration count if one was specified, else 1.*/public int getLoopCount() {return loopCount;}/*** Creates new frame image from current data (and previous frames as specified by their disposition codes).*/protected void setPixels() {// expose destination image's pixels as int arrayint[] dest = new int[width * height];// fill in starting image contents based on last image's dispose codeif (lastDispose > 0) {if (lastDispose == 3) {// use image before lastint n = frameCount - 2;if (n > 0) {lastBitmap = getFrame(n - 1);} else {lastBitmap = null;}}if (lastBitmap != null) {lastBitmap.getPixels(dest, 0, width, 0, 0, width, height);// copy pixelsif (lastDispose == 2) {// fill last image rect area with background colorint c = 0;if (!transparency) {c = lastBgColor;}for (int i = 0; i < lrh; i++) {int n1 = (lry + i) * width + lrx;int n2 = n1 + lrw;for (int k = n1; k < n2; k++) {dest[k] = c;}}}}}// copy each source line to the appropriate place in the destinationint pass = 1;int inc = 8;int iline = 0;for (int i = 0; i < ih; i++) {int line = i;if (interlace) {if (iline >= ih) {pass++;switch (pass) {case 2:iline = 4;break;case 3:iline = 2;inc = 4;break;case 4:iline = 1;inc = 2;break;default:break;}}line = iline;iline += inc;}line += iy;if (line < height) {int k = line * width;int dx = k + ix; // start of line in destint dlim = dx + iw; // end of dest lineif ((k + width) < dlim) {dlim = k + width; // past dest edge}int sx = i * iw; // start of line in sourcewhile (dx < dlim) {// map color and insert in destinationint index = ((int) pixels[sx++]) & 0xff;int c = act[index];if (c != 0) {dest[dx] = c;}dx++;}}}image = Bitmap.createBitmap(dest, width, height, Config.ARGB_4444);}/*** Gets the image contents of frame n.* * @return BufferedBitmap representation of frame, or null if n is invalid.*/public Bitmap getFrame(int n) {if (frameCount <= 0)return null;n = n % frameCount;return ((GifFrame) frames.elementAt(n)).image;}/*** Reads GIF image from stream* * @param is*          containing GIF file.* @return read status code (0 = no errors)*/public int read(InputStream is) {init();if (is != null) {in = is;readHeader();if (!err()) {readContents();if (frameCount < 0) {status = STATUS_FORMAT_ERROR;}}} else {status = STATUS_OPEN_ERROR;}try {is.close();} catch (Exception e) {}return status;}/*** Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick.*/protected void decodeBitmapData() {int nullCode = -1;int npix = iw * ih;int available, clear, code_mask, code_size, end_of_information, in_code, old_code, bits, code, count, i, datum, data_size, first, top, bi, pi;if ((pixels == null) || (pixels.length < npix)) {pixels = new byte[npix]; // allocate new pixel array}if (prefix == null) {prefix = new short[MAX_STACK_SIZE];}if (suffix == null) {suffix = new byte[MAX_STACK_SIZE];}if (pixelStack == null) {pixelStack = new byte[MAX_STACK_SIZE + 1];}// Initialize GIF data stream decoder.data_size = read();clear = 1 << data_size;end_of_information = clear + 1;available = clear + 2;old_code = nullCode;code_size = data_size + 1;code_mask = (1 << code_size) - 1;for (code = 0; code < clear; code++) {prefix[code] = 0; // XXX ArrayIndexOutOfBoundsExceptionsuffix[code] = (byte) code;}// Decode GIF pixel stream.datum = bits = count = first = top = pi = bi = 0;for (i = 0; i < npix;) {if (top == 0) {if (bits < code_size) {// Load bytes until there are enough bits for a code.if (count == 0) {// Read a new data block.count = readBlock();if (count <= 0) {break;}bi = 0;}datum += (((int) block[bi]) & 0xff) << bits;bits += 8;bi++;count--;continue;}// Get the next code.code = datum & code_mask;datum >>= code_size;bits -= code_size;// Interpret the codeif ((code > available) || (code == end_of_information)) {break;}if (code == clear) {// Reset decoder.code_size = data_size + 1;code_mask = (1 << code_size) - 1;available = clear + 2;old_code = nullCode;continue;}if (old_code == nullCode) {pixelStack[top++] = suffix[code];old_code = code;first = code;continue;}in_code = code;if (code == available) {pixelStack[top++] = (byte) first;code = old_code;}while (code > clear) {pixelStack[top++] = suffix[code];code = prefix[code];}first = ((int) suffix[code]) & 0xff;// Add a new string to the string table,if (available >= MAX_STACK_SIZE) {break;}pixelStack[top++] = (byte) first;prefix[available] = (short) old_code;suffix[available] = (byte) first;available++;if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) {code_size++;code_mask += available;}old_code = in_code;}// Pop a pixel off the pixel stack.top--;pixels[pi++] = pixelStack[top];i++;}for (i = pi; i < npix; i++) {pixels[i] = 0; // clear missing pixels}}/*** Returns true if an error was encountered during reading/decoding*/protected boolean err() {return status != STATUS_OK;}/*** Initializes or re-initializes reader*/protected void init() {status = STATUS_OK;frameCount = 0;frames = new Vector<GifFrame>();gct = null;lct = null;}/*** Reads a single byte from the input stream.*/protected int read() {int curByte = 0;try {curByte = in.read();} catch (Exception e) {status = STATUS_FORMAT_ERROR;}return curByte;}/*** Reads next variable length block from input.* * @return number of bytes stored in "buffer"*/protected int readBlock() {blockSize = read();int n = 0;if (blockSize > 0) {try {int count = 0;while (n < blockSize) {count = in.read(block, n, blockSize - n);if (count == -1) {break;}n += count;}} catch (Exception e) {e.printStackTrace();}if (n < blockSize) {status = STATUS_FORMAT_ERROR;}}return n;}/*** Reads color table as 256 RGB integer values* * @param ncolors*          int number of colors to read* @return int array containing 256 colors (packed ARGB with full alpha)*/protected 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 checksint 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;}/*** Main file parser. Reads GIF content blocks.*/protected void readContents() {// read GIF file content blocksboolean done = false;while (!(done || err())) {int code = read();switch (code) {case 0x2C: // image separatorreadBitmap();break;case 0x21: // extensioncode = read();switch (code) {case 0xf9: // graphics control extensionreadGraphicControlExt();break;case 0xff: // application extensionreadBlock();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;case 0xfe:// comment extensionskip();break;case 0x01:// plain text extensionskip();break;default: // uninteresting extensionskip();}break;case 0x3b: // terminatordone = true;break;case 0x00: // bad byte, but keep going and see what happens break;default:status = STATUS_FORMAT_ERROR;}}}/*** Reads Graphics Control Extension values*/protected void readGraphicControlExt() {read(); // block sizeint packed = read(); // packed fieldsdispose = (packed & 0x1c) >> 2; // disposal methodif (dispose == 0) {dispose = 1; // elect to keep old image if discretionary}transparency = (packed & 1) != 0;delay = readShort() * 10; // delay in millisecondstransIndex = read(); // transparent color indexread(); // block terminator}/*** Reads GIF file header information.*/protected 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];}}/*** Reads next frame image*/protected void readBitmap() {ix = readShort(); // (sub)image position & sizeiy = readShort();iw = readShort();ih = readShort();int packed = read();lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlacelctSize = (int) Math.pow(2, (packed & 0x07) + 1);// 3 - sort flag// 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color// table sizeinterlace = (packed & 0x40) != 0;if (lctFlag) {lct = readColorTable(lctSize); // read tableact = lct; // make local table active} else {act = gct; // make global table activeif (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;}decodeBitmapData(); // decode pixel dataskip();if (err()) {return;}frameCount++;// create new image to receive frame dataimage = Bitmap.createBitmap(width, height, Config.ARGB_4444);setPixels(); // transfer pixel data to imageframes.addElement(new GifFrame(image, delay)); // add image to frame// listif (transparency) {act[transIndex] = save;}resetFrame();}/*** Reads Logical Screen Descriptor*/protected void readLSD() {// logical screen sizewidth = readShort();height = readShort();// packed fieldsint packed = read();gctFlag = (packed & 0x80) != 0; // 1 : global color table flag// 2-4 : color resolution// 5 : gct sort flaggctSize = 2 << (packed & 7); // 6-8 : gct sizebgIndex = read(); // background color indexpixelAspect = read(); // pixel aspect ratio}/*** Reads Netscape extenstion to obtain iteration count*/protected void readNetscapeExt() {do {readBlock();if (block[0] == 1) {// loop count sub-blockint b1 = ((int) block[1]) & 0xff;int b2 = ((int) block[2]) & 0xff;loopCount = (b2 << 8) | b1;}} while ((blockSize > 0) && !err());}/*** Reads next 16-bit value, LSB first*/protected int readShort() {// read 16-bit value, LSB firstreturn read() | (read() << 8);}/*** Resets frame state for reading next image.*/protected void resetFrame() {lastDispose = dispose;lrx = ix;lry = iy;lrw = iw;lrh = ih;lastBitmap = image;lastBgColor = bgColor;dispose = 0;transparency = false;delay = 0;lct = null;}/*** Skips variable length blocks up to and including next zero length block.*/protected void skip() {do {readBlock();} while ((blockSize > 0) && !err());}
}

2.AnimatedGifDrawable 动画Drawable

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;import java.io.InputStream;/*** * @author tracyZhang  https://github.com/TracyZhangLei* @since  2014-4-4**/public class AnimatedGifDrawable extends AnimationDrawable {private final Context context;private int mCurrentIndex = 0;private UpdateListener mListener;public AnimatedGifDrawable(Context context,InputStream source, UpdateListener listener) {mListener = listener;this.context = context;GifDecoder decoder = new GifDecoder();decoder.read(source);// Iterate through the gif frames, add each as animation framefor (int i = 0; i < decoder.getFrameCount(); i++) {Bitmap bitmap = decoder.getFrame(i);Matrix matrix = new Matrix();int width = bitmap.getWidth();int height = bitmap.getHeight();// 缩放图片的尺寸int i1 = dip2px(context, 28);float scaleWidth = (float) i1/width;float scaleHeight = (float) i1/height;matrix.postScale(scaleWidth, scaleHeight);Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,width, height, matrix, true);BitmapDrawable drawable = new BitmapDrawable(context.getResources(),resizedBitmap);// Explicitly set the bounds in order for the frames to displaydrawable.setBounds(0, 0, resizedBitmap.getWidth(), resizedBitmap.getHeight());addFrame(drawable, decoder.getDelay(i));if (i == 0) {// Also set the bounds for this container drawablesetBounds(0, 0, resizedBitmap.getWidth(), resizedBitmap.getHeight());}}}/*** Naive method to proceed to next frame. Also notifies listener.*/public void nextFrame() {mCurrentIndex = (mCurrentIndex + 1) % getNumberOfFrames();if (mListener != null) mListener.update();}/*** Return display duration for current frame*/public int getFrameDuration() {return getDuration(mCurrentIndex);}/*** Return drawable for current frame*/public Drawable getDrawable() {return getFrame(mCurrentIndex);}/*** Interface to notify listener to update/redraw * Can't figure out how to invalidate the drawable (or span in which it sits) itself to force redraw*/public interface UpdateListener {void update();}/*** dip转换px** @param context* @param dpValue* @return float*/public static int dip2px(Context context, float dpValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}
}

3.AnimatedImageSpan 将字符串中指定文字转换成图片

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.text.style.DynamicDrawableSpan;/*** * @author tracyZhang  https://github.com/TracyZhangLei* @since  2014-4-4**/
public class AnimatedImageSpan extends DynamicDrawableSpan {private Drawable mDrawable;public AnimatedImageSpan(Drawable d) {super();mDrawable = d;// Use handler for 'ticks' to proceed to next frame final Handler mHandler = new Handler();mHandler.post(new Runnable() {public void run() {((AnimatedGifDrawable)mDrawable).nextFrame();// Set next with a delay depending on the duration for this frame mHandler.postDelayed(this, ((AnimatedGifDrawable)mDrawable).getFrameDuration());}});}/** Return current frame from animated drawable. Also acts as replacement for super.getCachedDrawable(),* since we can't cache the 'image' of an animated image.*/@Overridepublic Drawable getDrawable() {return ((AnimatedGifDrawable)mDrawable).getDrawable();}/** Copy-paste of super.getSize(...) but use getDrawable() to get the image/frame to calculate the size,* in stead of the cached drawable.*/@Overridepublic int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {Drawable d = getDrawable();Rect rect = d.getBounds();if (fm != null) {fm.ascent = -rect.bottom; fm.descent = 0; fm.top = fm.ascent;fm.bottom = 0;}return rect.right;}/** Copy-paste of super.draw(...) but use getDrawable() to get the image/frame to draw, in stead of* the cached drawable.*/@Overridepublic void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {Drawable b = getDrawable();canvas.save();int transY = bottom - b.getBounds().bottom;if (mVerticalAlignment == ALIGN_BASELINE) {transY -= paint.getFontMetricsInt().descent;}canvas.translate(x, transY);b.draw(canvas);canvas.restore();}}

4.使用方法

 TextView gifTextview = (TextView) findViewById(R.id.gifTextview);SpannableStringBuilder stringBuilder = new SpannableStringBuilder();AssetManager am = getAssets();try {InputStream is = am.open("emo/anim_flag_hungary.gif");if (is == null) return;stringBuilder.append("anim_flag_hungary");stringBuilder.append("jkfsdjfksk哈哈");WeakReference<AnimatedImageSpan> localImageSpanRef = new WeakReference<>(new AnimatedImageSpan(new AnimatedGifDrawable(this, is, new AnimatedGifDrawable.UpdateListener(){@Overridepublic void update() {//update the textviewgifTextview.postInvalidate();}})));stringBuilder.setSpan(localImageSpanRef.get(), 0, stringBuilder.length()-"anim_flag_hungary".length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);gifTextview.setGravity(Gravity.CENTER_VERTICAL);gifTextview.setText(stringBuilder);is.close();} catch (IOException e) {e.printStackTrace();}

如果有不懂的,欢迎随时提问,你的支持是我前进的动力哦!

这篇关于TextView图文混排Gif的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/745689

相关文章

【虚拟机/服务器】配置ngx_http_empty_gif_module记录

下载Nginx源码 查看Nginx内置模块 1、在可视化界面中 可以看到 ngx_http_empty_gif_module.c 是Nginx的内置模块,不需要再进行安装 2、在bash命令行中 tar nginx 解压后进入nginx目录,./configure --help | grep empty_gif 即可查看我想要的 ngx_http_empty_gif_module

TextView 的介绍和使用

TextView类的结构 textView是用来显示字符串的组件,在手机上就是显示一块文本的区域。 它继承自 View, 直接子类有:Button.CHeckedTextView,Chronometer, DigitalClock, EditText 简接子类:AutoCompleteTextView, CheckBox, CompoundButton, Ex

使用Python调用ImageMagick将序列帧生成GIF

目标 使用Python来调用ImageMagick,将文件夹内所有的图片作为序列帧合并为一个GIF。 我事先使用Blender渲染了一组图片(操作很简单, 可见《尝试在blender中渲染一个最简单的动画》) 1. 使用ImageMagick将序列帧生成GIF 最基础的命令是比较简单的: convert 第1帧图片 第2帧图片 ...第n帧图片 结果GIF Animation

Android TextView设置跑马灯失效

1.关于问题 TextView失效在网上有详细的解决方案,大部分时候都能够很好的解决问题 下面给出网上的解决方案: <TextViewandroid:layout_width="100dp"android:layout_height="22dp"tools:text="水浇地放松放松开发的开始放假考试的飞机开了撒酒疯恐龙时代解封了开始的"android:ellipsize="marquee"

YLGIFImage 高效读取GIF图片

https://github.com/liyong03/YLGIFImage Asynchronized GIF image class and Image viewer supporting play/stop GIF images. 异步加载GIF图片的类,支持GIF图片的播放与暂停。 It just use very less memory. Following GIF usually

wsksvg - 支持SVG、JPEG、GIF、PNG、WebP格式图片的优化

前言 上一篇文章介绍了 wsksvg 插件的开发思路和灵感,而本篇则详细阐述了 wsksvg 扩展功能,以及技术的介绍。通过 wsksvg 插件,开发者可以高效地优化 PNG、JPG、JPEG、WEBP 和 GIF 图像,同时对 SVG 文件进行深入处理,包括优化、生成 Vue 和 React 组件以及转换为 Base64 编码格式。这些功能不仅简化了图像管理流程,也提升了应用的性能和用户体验。

猫猫学iOS 之微博项目实战(11)发送微博自定义TextView实现带占位文字

猫猫分享,必须精品 原创文章,欢迎转载。转载请注明:翟乃玉的博客 地址:http://blog.csdn.net/u013357243 一:效果 二:代码: 由于系统自带的UITextField:和UITextView:不能满足我们的需求,所以我们需要自己设计一个。 UITextField: 1.文字永远是一行,不能显示多行文字 2.有placehoder属性设置占位文字 3

android 改造TextView使上下左右Drawble宽高可调

1、首先在attrs.xml中声明自定义属性 <declare-styleable name="DrawableEditView"><!-- 设置top图片的宽度 --><attr name="edit_drawableTopWidth" format="dimension" /><!-- 设置top图片的高度 --><attr name="edit_drawableTopHeight" f

textView代码设置文字居中失效 textView设置文字居中两种方法

1.TextView的高度占据整个父控件的高度,然后设置TextView的Grayvity Center就可以了。 2.如果第一个方法不行,那么,textView的高度设置为warp_content,然后设置父布局为CENTER_VERTICAL 代码: LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(Lay

Android中自定义TextView的形状

基本步骤: 在drawable文件夹下建立一个shape.xml shape.xml: <?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="oval"><!-- 填充的颜色 --><solid an