标题:将文字输出成会动的gif
Tag:dynamic gif,GDI+,gif89a,dot net,c sharp,fallseir.lee,飞扬·轻狂
作者:飞扬·轻狂 (fallseir·lee)
来源:http://www.livejournal.com/users/fallseir/14263.html
<%@ WebHandler Language="C#" Class="FeedSkyGif" %>
using System;
using System.Web;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Design;
using System.Drawing.Text;
using System.IO;
/// <summary>
/// 输出会动的gif
/// create by fallseir.lee(飞扬·轻狂 http://www.livejournal.com/~fallseir)
/// --20050811 18:01
/// </summary>
public class FeedSkyGif : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "image/gif";
DrawGif(context.Response.OutputStream, "f://feed0.bmp", new string[] { "hello", "feedsky.com" });
context.Response.End();
}
public bool IsReusable {
get {
return false;
}
}
/// <summary>
/// 图像扩展信息
/// </summary>
public byte[] ExtensionBlock = new byte[]{
0x21,0xFF,0x0B,0x4E,0x45,0x54,0x53,0x43,0x41,0x50,0x45,0x32,0x2E,0x30,0x03,0x01,0x00,0x00,0x00,0x21,0xF9,0x04,0x05,0x32,0x00,0x05,0x00
};
/// <summary>
/// 绘制图像
/// </summary>
/// <param name="outStream"></param>
/// <param name="bkimage"></param>
/// <param name="msgs"></param>
public void DrawGif(Stream outStream, string bkimage, string[] msgs)
{
Bitmap bmp = new Bitmap(bkimage);
Color color = Color.FromArgb(255, 0, 0);
Font font = new Font("宋体", 9, FontStyle.Regular);
MemoryStream ms = new MemoryStream();
OutImageHeader(ms,bmp);
OutImageData(ms, bmp, 0, 0, bmp.Width, bmp.Height, new string[] { "" }, color, font, 0);
for (int i = 0; i < msgs.Length; i++)
{
OutImageData(ms, bmp, 5, 21, bmp.Width - 5 - 5, bmp.Height - 21 - 5, new string[] { "msg:" , msgs[i] }, color, font, 150);
OutImageData(ms, bmp, 5, 21, bmp.Width - 5 - 5, bmp.Height - 21 - 5, new string[] { "msg:", msgs[i] }, Color.FromArgb(50,255,00,00), font, 50);
OutImageData(ms, bmp, 5, 21, bmp.Width - 5 - 5, bmp.Height - 21 - 5, new string[] { "msg:", msgs[i] }, Color.FromArgb(12, 255,00, 00), font, 50);
}
bmp.Dispose();
ms.Write(new byte[] { 0x3B }, 0, 1);
ms.WriteTo(outStream);
ms.Close();
}
/// <summary>
/// 输出头像头
/// </summary>
/// <param name="ms"></param>
/// <param name="bk"></param>
public void OutImageHeader(MemoryStream ms, Bitmap bk)
{
MemoryStream m = new MemoryStream();
bk.Save(m, ImageFormat.Gif);
byte[] buffer = m.ToArray();
byte[] header = GetHeader(buffer);
ms.Write(header, 0, header.Length);
m.Close();
}
/// <summary>
/// 输出图像数据
/// </summary>
/// <param name="ms">输出流</param>
/// <param name="bk">背景图片(使用背景图片的一部分x,y,width,height)</param>
/// <param name="x">left</param>
/// <param name="y">top</param>
/// <param name="width">width</param>
/// <param name="height">height</param>
/// <param name="msg">message string</param>
/// <param name="color">color</param>
/// <param name="font">font</param>
/// <param name="delay">delay time</param>
public void OutImageData(MemoryStream ms,Bitmap bk,float x,float y,int width,int height,string[] msgs,Color color,Font font,int delay)
{
MemoryStream m = new MemoryStream();
Bitmap b = Draw(bk.Clone(new RectangleF(x, y, width, height), PixelFormat.Format32bppPArgb), msgs, color, font, 0, 0);
b.Save(m, ImageFormat.Gif);
b.Dispose();
byte[] buffer = m.ToArray();
if (ms.Length == 0)
{
byte[] header = GetHeader(buffer);
ms.Write(header, 0, header.Length);
}
byte[] image = GetImageData(buffer,(int)x,(int)y,delay);
ms.Write(image, 0, image.Length);
m.Close();
}
//获取图像头
public byte[] GetHeader(byte[] image)
{
int size = GetHeaderSize(image);
if (size < 0) return new byte[] { };
byte[] buffer = new byte[size];
Array.Copy(image, 0, buffer, 0, size);
return buffer;
}
/// <summary>
/// 获取图像数据
/// </summary>
/// <param name="image">单张的gif数据</param>
/// <param name="x">left</param>
/// <param name="y">top</param>
/// <param name="delay">delay time</param>
/// <returns></returns>
public byte[] GetImageData(byte[] image, int x, int y,int delay)
{
int begin = GetImageBegin(image);
byte[] block=GenerateExtensionBlock();
block[23] = Convert.ToByte(delay);
int size=image.Length-begin+block.Length-1;
image[begin + 1] = Convert.ToByte(x);//left
image[begin + 3] = Convert.ToByte(y);//top
byte[] data = new byte[size];
Array.Copy(block, data, block.Length);
Array.Copy(image, begin, data, block.Length, image.Length - begin-1);
return data;
}
private byte[] GenerateExtensionBlock()
{
byte[] block =(byte[]) ExtensionBlock.Clone();
return block;
}
//获取图像头大小
private int GetHeaderSize(byte[] image)
{
if (!(image[0] == (byte)'G' && image[1] == (byte)'I' && image[2] == (byte)'F'))
{ return -1; }
int size = -1;
for (int i = 12; i < image.Length; i++)
{
if (image[i] == 0x21)
{
i++;
if (image[i] == 0xf9)
{
size = i - 1;
break;
}
}
}
return size;
}
//获取图像数据开始位置
private int GetImageBegin(byte[] image)
{
int hsize = GetHeaderSize(image);
int begin = -1;
if (hsize > 0)
{
for (int i = hsize; i < image.Length; i++)
{
if (image[i] == 0x00)
{
i++;
if (image[i] == 0x2c)
{
begin = i;
break;
}
}
}
return begin;
}
return -1;
}
public Bitmap Draw(Bitmap bmp, string[] msgs, Color color, Font font, float x, float y)
{
Graphics g = Graphics.FromImage(bmp);
for (int i = 0; i < msgs.Length; i++)
{
g.DrawString(msgs[i], font, new SolidBrush(color), x, y+i*(font.Height-1));
}
g.Dispose();
return bmp;
}
}
/* Gif Format
*
* <GIF Header><!-- 0-12 begin with GIF89a or GIF87a -->
* <Global Color Table/>
* <Blocks/>
* </GIF Header>
*
* <Blocks>
* <block>
* <Extensions>
* <Graphic Control Extension Block>
* <Comment Extension Block>
* <Plain Text Extension Block>
* </Extensions>
* <Image>
* </Image>
* </block>
* </Blocks>
*
GIF format http://www.onicos.com/staff/iz/formats/gif.html#gceb
Byte Order: Little-endian
GIF Header
Offset Length Contents
0 3 bytes "GIF"
3 3 bytes "87a" or "89a"
6 2 bytes <Logical Screen Width>
8 2 bytes <Logical Screen Height>
10 1 byte bit 0: Global Color Table Flag (GCTF)
bit 1..3: Color Resolution
bit 4: Sort Flag to Global Color Table
bit 5..7: Size of Global Color Table: 2^(1+n)
11 1 byte <Background Color Index>
12 1 byte <Pixel Aspect Ratio>
13 ? bytes <Global Color Table(0..255 x 3 bytes) if GCTF is one>
? bytes <Blocks>
1 bytes <Trailer> (0x3b)
Image Block
Offset Length Contents
0 1 byte Image Separator (0x2c)
1 2 bytes Image Left Position
3 2 bytes Image Top Position
5 2 bytes Image Width
7 2 bytes Image Height
8 1 byte bit 0: Local Color Table Flag (LCTF)
bit 1: Interlace Flag
bit 2: Sort Flag
bit 2..3: Reserved
bit 4..7: Size of Local Color Table: 2^(1+n)
? bytes Local Color Table(0..255 x 3 bytes) if LCTF is one
1 byte LZW Minimum Code Size
[ // Blocks
1 byte Block Size (s)
(s)bytes Image Data
]*
1 byte Block Terminator(0x00)
Graphic Control Extension Block
Offset Length Contents
0 1 byte Extension Introducer (0x21)
1 1 byte Graphic Control Label (0xf9)
2 1 byte Block Size (0x04)
3 1 byte bit 0..2: Reserved
bit 3..5: Disposal Method
bit 6: User Input Flag
bit 7: Transparent Color Flag
4 2 bytes Delay Time (1/100ths of a second)
6 1 byte Transparent Color Index
7 1 byte Block Terminator(0x00)
Comment Extension Block
Offset Length Contents
0 1 byte Extension Introducer (0x21)
1 1 byte Comment Label (0xfe)
[
1 byte Block Size (s)
(s)bytes Comment Data
]*
1 byte Block Terminator(0x00)
Plain Text Extension Block
Offset Length Contents
0 1 byte Extension Introducer (0x21)
1 1 byte Plain Text Label (0x01)
2 1 byte Block Size (0x0c)
3 2 bytes Text Grid Left Position
5 2 bytes Text Grid Top Position
7 2 bytes Text Grid Width
9 2 bytes Text Grid Height
10 1 byte Character Cell Width(
11 1 byte Character Cell Height
12 1 byte Text Foreground Color Index(
13 1 byte Text Background Color Index(
[
1 byte Block Size (s)
(s)bytes Plain Text Data
]*
1 byte Block Terminator(0x00)
Application Extension Block
Offset Length Contents
0 1 byte Extension Introducer (0x21)
1 1 byte Application Label (0xff)
2 1 byte Block Size (0x0b)
3 8 bytes Application Identifire
[
1 byte Block Size (s)
(s)bytes Application Data
]*
1 byte Block Terminator(0x00)
--------------------------------------------------------------------------------
GIF87a:
GIF Header
Image Block
Trailer
--------------------------------------------------------------------------------
GIF89a:
GIF Header
Graphic Control Extension
Image Block
Trailer
--------------------------------------------------------------------------------
GIF Animation
GIF Header
Application Extension
[
Graphic Control Extension
Image Block
]*
Trailer
*/