需要脚本演示、定制部署或海外获客方案?访问 Facebook18 官网
首页 / twitter引流推广

特推怎么保存视频啊(推特 保存)

2023-01-13twitter引流推广静态 HTML 文章

未标题-1-4 (1).png

GIF 原义是“图像互换格式”,是 CompuServe 公司在1987年开发出的图像文件格式,可以说是互联网界的老古董了。

GIF 格式可以存储多幅彩色图像,如果将这些图像连续播放出来,就能够组成蕞简单的动画。所以常被用来存储“动态图片”,通常时间短,体积小,内容简单,成像相对清晰。

GIF存储格式

一个GIF文件主要由以下几部分组成:

文件头图像帧信息注释

文件头

GIF格式文件头和一般文件头差别不大,也包含有:

格式声明逻辑屏幕描述块全局调色盘

格式声明

Signature 为“GIF”3 个字符;Version 为“87a”或“89a”3 个字符。

逻辑屏幕描述块

前两字节为像素单位的宽、高,用以标识图片的视觉尺寸。

Packet里是调色盘信息,分别来看:

Global Color Table Flag为全局颜色表标志,即为1时表明全局颜色表有定义。

Color Resolution 代表颜色表中每种基色位长,为221时,每个颜色用8bit表示,即我们熟悉的RGB表示法,一个颜色三字节。

Sort Flag 表示是否对颜色表里的颜色进行优先度排序,把常用的排在前面,这个主要是为了适应一些颜色解析度低的早期渲染器,现在已经很少使用了。

Global Color Table 表示颜色表的长度,计算规则是值+1作为2的幂,得到的数字就是颜色表的项数,取蕞大值221时,项数=256,也就是说GIF格式蕞多支持256色的位图,再乘以Color Resolution算出的字节数,就是调色盘的总长度。

这四个字段一起定义了调色盘的信息。

Background color Index 定义了图像透明区域的背景色在调色盘里的索引。

Pixel Aspect Ratio 定义了像素宽高比,一般为0。

帧信息描述

帧信息描述就是每一帧的图像信息和相关标志位,直观地说,帧信息应该由一系列的点阵数据组成,点阵中存储着一系列的颜色值。点阵数据本身的存储也是可以进行压缩的,GIF图所采用的是LZW压缩算法。

这是ImageMagick官方范例里的一张GIF图。

根据直观感受,这张图片的每一帧应该是这样的。

但实际上,进行过压缩优化的图片,每一帧是这样的。

首先,对于各帧之间没有变化的区域进行了排除,避免存储重复的信息。

其次,对于需要存储的区域做了透明化处理,只存储有变化的像素,没变化的像素只存储一个透明值。

我们再来看帧信息的具体定义,主要包括:

帧分隔符帧数据说明点阵数据帧数据扩展 { StringBuilder id = new StringBuilder; for { id.append read); } if .startsWith) { header.status = STATUS_FORMAT_ERROR; return; } } /** * Reads Logical Screen Descriptor. */ private void readLSD { // Logical screen size. header.width = readShort; header.height = readShort; /* * Logical Screen Descriptor packed field: * 7 6 5 4 3 2 1 0 * +—————+ * 4 | | | | | * * Global Color Table Flag 1 Bit * Color Resolution 3 Bits * Sort Flag 1 Bit * Size of Global Color Table 3 Bits */ int packed = read; header.gctFlag = != 0; header.gctSize = Math.pow + 1); // Background color index. header.bgIndex = read; // Pixel aspect ratio header.pixelAspect = read; } /** * Reads color table as 256 RGB integer values. * * @param nColors int number of colors to read. * @return int array containing 256 colors . */ @Nullable private int[] readColorTable { int nBytes = 3 * nColors; int[] tab = null; byte[] c = new byte[nBytes]; try { rawData.get; // TODO: what bounds checks are we avoiding if we know the number of colors? // Max size to avoid bounds checks. tab = new int[MAX_BLOCK_SIZE]; int i = 0; int j = 0; while { int r = c[j++]) & MASK_INT_LOWEST_BYTE; int g = c[j++]) & MASK_INT_LOWEST_BYTE; int b = c[j++]) & MASK_INT_LOWEST_BYTE; tab[i++] = 0xFF000000 | | | b; } } catch { if ) { Log.d; } header.status = STATUS_FORMAT_ERROR; } return tab; } /** * Reads next frame image. */ private void readBitmap { // image position & size. header.currentFrame.ix = readShort; header.currentFrame.iy = readShort; header.currentFrame.iw = readShort; header.currentFrame.ih = readShort; /* * Image Descriptor packed field: * 7 6 5 4 3 2 1 0 * +—————+ * 9 | | | | | | * * Local Color Table Flag 1 Bit * Interlace Flag 1 Bit * Sort Flag 1 Bit * Reserved 2 Bits * Size of Local Color Table 3 Bits */ int packed = read; boolean lctFlag = != 0; int lctSize = Math.pow + 1); header.currentFrame.interlace = != 0; if { header.currentFrame.lct = readColorTable; } else { // No local color table. header.currentFrame.lct = null; } // Save this as the decoding position pointer. header.currentFrame.bufferFrameStart = rawData.position; // False decode pixel data to advance buffer. skipImageData; if ) { return; } header.frameCount++; // Add image to frame. header.frames.add; }

Glide渲染Gif主要是通过GifDrawable这个类,该类实现了Animatable接口,当调用start方法后开始循环播放,在draw方法里进行绘制bitmap。

@Override public void start { isStarted = true; resetLoopCount; if { startRunning; } } private void startRunning { // 当 Gif 只有一帧的时候,会直接调用绘制方法 if == 1) { invalidateSelf; } else if { isRunning = true; // Gif 不止一帧的时候,就开启了订阅 state.frameLoader.subscribe; invalidateSelf; } } @Override public void draw { if { return; } if { Gravity.apply, getIntrinsicHeight, getBounds, getDestRect); applyGravity = false; } Bitmap currentFrame = state.frameLoader.getCurrentFrame; canvas.drawBitmap, getPaint); }

Gif图片中的每一帧的bitmap就是GifFrameLoader里GifDecoder解析出来的,GifDrawable调用start方法后,会在GifFrameLoader注册监听,每一帧图片解析完后会回调再进行绘制

void subscribe { if { throw new IllegalStateException; } if ) { throw new IllegalStateException; } boolean start = callbacks.isEmpty; callbacks.add; if { start; } }start { loadNextFrame; } private void loadNextFrame { if { return; } if { Preconditions.checkArgument; gifDecoder.resetFrameIndex; startFromFirstFrame = false; } if { DelayTarget temp = pendingTarget; pendingTarget = null; onFrameReady; return; } isLoadPending = true; // Get the delay before incrementing the pointer because the delay indicates the amount of time // we want to spend on the current frame. int delay = gifDecoder.getNextDelay; long targetTime = SystemClock.uptimeMillis + delay; gifDecoder.advance; next = new DelayTarget, targetTime); requestBuilder.apply)).load.into; }

Glide 加载 Gif 的原理比较简单,就是将 Gif 解码成多张图片进行无限轮播,每帧切换都是一次图片加载请求,再加载到新的一帧数据之后会对旧的一帧数据进行清除,然后再继续下一帧数据的加载请求,以此类推,使用 Handler 发送消息实现循环播放。

android-gif-drawable

也是用sdk内部的Gifdrawable来进行渲染的,与glide类似,该类也是继承了Animatable接口,在适当的时候调用start方法就会开始循环绘制,然后在draw方法里进行bitmap绘制

/** * Starts the animation. Does nothing if GIF is not animated. * This method is thread-safe. */@Overridepublic void start {synchronized {if {return;}mIsRunning = true;}final long lastFrameRemainder = mNativeInfoHandle.restoreRemainder;startAnimation;}void startAnimation {if {mNextFrameRenderTime = 0;mInvalidationHandler.sendEmptyMessageAtTime;} else {cancelPendingRenderTask;mRenderTaskSchedule = mExecutor.schedule, TimeUnit.MILLISECONDS);}}public void draw {final boolean clearColorFilter;if == null) {mPaint.setColorFilter;clearColorFilter = true;} else {clearColorFilter = false;}if {canvas.drawBitmap;} else {mTransform.onDraw;}if {mPaint.setColorFilter;}}

与glide不同的是,android-gif-drawable的bitmap解析是在native层进行的,并且Bitmap对象只会存在一个

Java_pl_droidsonroids_gif_GifInfoHandle_renderFrame {GifInfo *info = gifInfo;if return -1;long renderStartTime = getRealTime;void *pixels;if != 0) {return 0;}DDGifSlurp;if {prepareCanvas;}const uint_fast32_t frameDuration = getBitmap;unlockPixels;return calculateInvalidationDelay;}

海外精品引流脚本–最强海外引流  

官网:www.facebook18.com

唯一TG:https://t.me/Facebook181818

Facebook.png

查看演示与获取方案

读完本篇后,可通过下方入口查看演示视频、联系客服或访问主站。