文档库 最新最全的文档下载
当前位置:文档库 › jpg编码

jpg编码

jpg编码
jpg编码

一、JPEG文件格式介绍

JPEG文件使用的数据存储方式有多种。最常用的格式称为JPEG文件交换格式(JPEG File Interchange Format,JFIF)。而JPEG文件大体上可以分成两个部分:标记码(Tag)和压缩数据。标记码由两个字节构成,其前一个字节是固定值0xFF,后一个字节则根据不同意义有不同数值。在每个标记码之前还可以添加数目不限的无意义的0xFF填充,也就说连续的多个0xFF 可以被理解为一个0xFF,并表示一个标记码的开始。而在一个完整的两字节的标记码后,就是该标记码对应的压缩数据流,记录了关于文件的诸种信息。

常用的标记有SOI、APP0、DQT、SOF0、DHT、DRI、SOS、EOI。

SOI,Start of Image,图像开始

标记代码2字节固定值0xFFD8

APP0,Application,应用程序保留标记0

标记代码2字节固定值0xFFE0

包含9个具体字段:

①数据长度2字节①~⑨9个字段的总长度

②标识符5字节固定值0x4A46494600,即字符串“JFIF0”

③版本号2字节一般是0x0102,表示JFIF的版本号1.2

④X和Y的密度单位1字节只有三个值可选

i.0:无单位;1:点数/英寸;2:点数/厘米

⑤X方向像素密度2字节取值范围未知

⑥Y方向像素密度2字节取值范围未知

⑦缩略图水平像素数目1字节取值范围未知

⑧缩略图垂直像素数目1字节取值范围未知

⑨缩略图RGB位图长度可能是3的倍数缩略图RGB位图数据

本标记段可以包含图像的一个微缩版本,存为24位的RGB像素。如果没有微缩图像(这种情况更常见),则字段⑦“缩略图水平像素数目”和字段⑧“缩略图垂直像素数目”的值均为0。

APPn,Application,应用程序保留标记n,其中n=1~15(任选)

标记代码2字节固定值0xFFE1~0xFFF

包含2个具体字段:

①数据长度2字节①~②2个字段的总长度

i.即不包括标记代码,但包括本字段

②详细信息数据长度-2字节内容不定

例如,Adobe Photoshop生成的JPEG图像中就用了APP1和APP13两个标记段分别存储了一幅图像的副本。

DQT,Define Quantization Table,定义量化表

标记代码2字节固定值0xFFDB

包含9个具体字段:

①数据长度2字节字段①和多个字段②的总长度

i.即不包括标记代码,但包括本字段

②量化表数据长度-2字节

a) 精度及量化表ID 1字节高4位:精度,只有两个可选值

0:8位;1:16位

低4位:量化表ID,取值范围为0~3 b) 表项(64×(精度+1))字节例如8位精度的量化表

其表项长度为64×(0+1)=64字节本标记段中,字段②可以重复出现,表示多个量化表,但最多只能出现4次。

SOF0,Start of Frame,帧图像开始

①标记代码2字节固定值0xFFC0

②包含9个具体字段:

③数据长度2字节①~⑥六个字段的总长度

i.即不包括标记代码,但包括本字段

④精度1字节每个数据样本的位数

i.通常是8位,一般软件都不支持12位和16位

⑤图像高度2字节图像高度(单位:像素),如果不支持DNL 就必须>0

⑥图像宽度2字节图像宽度(单位:像素),如果不支持DNL 就必须>0

⑦颜色分量数1字节只有3个数值可选

i.1:灰度图;3:YCrCb或YIQ;4:CMYK

ii.而JFIF中使用YCrCb,故这里颜色分量数恒为3

⑧颜色分量信息颜色分量数×3字节(通常为9字节)

a) 颜色分量ID 1字节

b) 水平/垂直采样因子1字节高4位:水平采样因子

低4位:垂直采样因子

c) 量化表1字节当前分量使用的量化表的ID

本标记段中,字段⑥应该重复出现,有多少个颜色分量(字段⑤),就出现多少次(一般为3次)。

DHT,Difine Huffman Table,定义哈夫曼表

标记代码2字节固定值0xFFC4

包含2个具体字段:

①数据长度2字节字段①和多个字段②的总长度

i.即不包括标记代码,但包括本字段

②哈夫曼表数据长度-2字节

a) 表ID和表类型1字节高4位:类型,只有两个值可选

0:DC直流;1:AC交流

低4位:哈夫曼表ID,注意,DC表和AC表分开编码

b) 不同位数的码字数量16字节

c) 编码内容16个不同位数的码字数量之和(字节)

本标记段中,字段②可以重复出现(一般4次),也可以致出现1次。例如,Adobe Photoshop 生成的JPEG图片文件中只有1个DHT标记段,里边包含了4个哈夫曼表;而Macromedia Fireworks生成的JPEG图片文件则有4个DHT标记段,每个DHT标记段只有一个哈夫曼表。DRI,Define Restart Interval,定义差分编码累计复位的间隔

标记代码2字节固定值0xFFDD

包含2个具体字段:

数据长度2字节固定值0x0004,①~②两个字段的总长度

即不包括标记代码,但包括本字段

MCU块的单元中的重新开始间隔

2字节设其值为n,则表示每n个MCU块就有一个

RSTn标记。第一个标记是RST0,第二个是

RST1等,RST7后再从RST0重复。

如果没有本标记段,或间隔值为0时,就表示不存在重开始间隔和标记RST

SOS,Start of Scan,扫描开始12字节

标记代码2字节固定值0xFFDA

包含2个具体字段:

①数据长度2字节①~④两个字段的总长度

即不包括标记代码,但包括本字段

②颜色分量数1字节应该和SOF中的字段⑤的值相同,即:

1:灰度图是;3:YCrCb或YIQ;4:CMYK。

而JFIF中使用YCrCb,故这里颜色分量数恒为3

③颜色分量信息

a) 颜色分量ID 1字节

b) 直流/交流系数表号1字节高4位:直流分量使用的哈夫曼树编号

低4位:交流分量使用的哈夫曼树编号

④压缩图像数据

a)谱选择开始1字节固定值0x00

b)谱选择结束1字节固定值0x3F

c)谱选择1字节在基本JPEG中总为00

本标记段中,字段③应该重复出现,有多少个颜色分量(字段②),就出现多少次(一般为3次)。本段结束后,紧接着就是真正的图像信息了。图像信息直至遇到一个标记代码就自动结束,一般就是以EOI标记表示结束。

EOI,End of Image,图像结束2字节

标记代码2字节固定值0xFFD9

这里补充说明一下,由于在JPEG文件中0xFF具有标志性的意思,所以在压缩数据流(真正的图像信息)中出现0xFF,就需要作特别处理。具体方法是,在数据0xFF后添加一个没有意义的0x00。换句话说,如果在图像数据流中遇到0xFF,应该检测其紧接着的字符,如果是1)0x00,则表示0xFF是图像流的组成部分,需要进行译码;

2)0xD9,则与0xFF组成标记EOI,则图像流结束,同时图像文件结束;

3)0xD0~0xD7,则组成RSTn标记,则要忽视整个RSTn标记,即不对当前0xFF和紧接的0xDn 两个字节进行译码,并按RST标记的规则调整译码变量;

3)0xFF,则忽视当前0xFF,对后一个0xFF再作判断;

4)其他数值,则忽视当前0xFF,并保留紧接的此数值用于译码。

二、JPEG图像的编码

一、bmp文件的读取

1:这里首先把bmp文件读取到一个数组中,并且进行预处理,预处理包括把行和列全部变成以8为单位的数据,因为进行DCT变化时,需要以8*8的数据单元为最小的单元。由于要变成以8为单元,所以可能会多余或者少一部分,对于新增的部分,需要进行对其的数据

进行填充,这里选择填充就是最后一行或者列的数据。

2:还有就是对数据单元上下倒置,就是把第一行和最后一行交换,第二行和倒数第二行交换,目的是翻转图像,这样做的目的是因为bmp文件在保存时,保存的形式是BGR的形式,但是实际上需要转化成为RGB的格式,所以整个把图像倒转过来,就实现了BGR和RGB的转化。

3:转化的主要的代码如下:

void load_bitmap(char *bitmap_name, WORD *width_original, WORD *height_original)

{

WORD widthDiv8, heightDiv8; //最近的8的整数位

BYTE nr_fillingbytes;//在bmp文件中的填充字节

colorRGB lastcolor;

WORD column;

BYTE TMPBUF[256];

WORD nrline_up, nrline_dn, nrline;

WORD dimline;

colorRGB *tmpline;

FILE *fp_bitmap = fopen(bitmap_name,"rb");

width = (WORD)TMPBUF[19]*256+TMPBUF[18];//确定位图的宽度和高度

height = (WORD)TMPBUF[23]*256+TMPBUF[22];

// 保存原始图像的数据

*width_original = width;

*height_original = height;

if (width%8 != 0) //把高度和宽度数据变成8的整数关系数

widthDiv8 = (width/8)*8+8;

else

widthDiv8 = width;

if (height%8 != 0)

heightDiv8 = (height/8)*8+8;

else

heightDiv8 = height;

//分配相应的存储空间,用于保存所有的数据。

RGB_buffer = (colorRGB *)(malloc(3*widthDiv8*heightDiv8));

if (RGB_buffer == NULL)

exitmessage("Not enough memory for the bitmap image.");

//Windows默认的扫描的最小单位是4字节,所以这里判断剩余的要扫描的数量。

if ( (width*3)%4 != 0)

nr_fillingbytes = 4 - ( (width*3)%4);

else

nr_fillingbytes = 0;

for (nrline=0; nrline

{

fread(RGB_buffer + nrline*widthDiv8, 1, width*3, fp_bitmap);

fread(TMPBUF, 1, nr_fillingbytes, fp_bitmap);

// 填充X多出来的部分

memcpy(&lastcolor, RGB_buffer + nrline*widthDiv8 + width-1, 3);

for (column=width; column

memcpy(RGB_buffer+nrline*widthDiv8+column, &lastcolor, 3);

}

width = widthDiv8;

dimline = width*3;

tmpline = (colorRGB *)malloc(dimline);

// 把图像翻转

for (nrline_up=height-1,nrline_dn=0; nrline_up>nrline_dn; nrline_up--,nrline_dn++)

{

memcpy(tmpline, RGB_buffer+nrline_up*width, dimline);

memcpy(RGB_buffer+nrline_up*width, RGB_buffer+nrline_dn*width, dimline);

memcpy(RGB_buffer+nrline_dn*width, tmpline, dimline);

}

//填充X多出来的部分

memcpy(tmpline, RGB_buffer+(height-1)*width, dimline);

for (nrline=height; nrline

memcpy(RGB_buffer+nrline*width, tmpline, dimline);

height = heightDiv8;

free(tmpline);

fclose(fp_bitmap);

}

二、压缩算法的核心数据结构和初始化

1:核心数据结构

首先就是两个量化表,色度量化表和亮度量化表,分别用std_luminance_qt[64] 和std_chrominance_qt[64]表示:这两个数组中的值都是给定的,一般就是这样的压缩比。std_luminance_qt[64]= {16, 11, 10, 16, 24, 40, 51, 61,

12, 12, 14, 19, 26, 58, 60, 55,

14, 13, 16, 24, 40, 57, 69, 56,

14, 17, 22, 29, 51, 87, 80, 62,

18, 22, 37, 56, 68, 109, 103, 77,

24, 35, 55, 64, 81, 104, 113, 92,

49, 64, 78, 87, 103, 121, 120, 101,

72, 92, 95, 98, 112, 100, 103, 99};

static BYTE std_chrominance_qt[64] = {

17, 18, 24, 47, 99, 99, 99, 99,

18, 21, 26, 66, 99, 99, 99, 99,

24, 26, 56, 99, 99, 99, 99, 99,

47, 66, 99, 99, 99, 99, 99, 99,

99, 99, 99, 99, 99, 99, 99, 99,

99, 99, 99, 99, 99, 99, 99, 99,

99, 99, 99, 99, 99, 99, 99, 99,

99, 99, 99, 99, 99, 99, 99, 99};

直流亮度的码字数量和直流亮度的码字内容,std_dc_luminance_nrcodes[17]和std_dc_luminance_values[12],std_dc_luminance_nrcodes[17]中2~17的16个值对应的是,这16个数值实际意义为:没有1位的哈夫曼码字;2位的码字各有1个;3位码字有5个;4位和5,6,7,8,9位码字各有1个;std_dc_luminance_values[12]各个数对应的权值,通过他们两个表从而确定;另一个重要的数据结构,就是Huffman表。

std_dc_luminance_nrcodes[17]={0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};

std_dc_luminance_values[12]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

Huffman表的建立方法:

1)第一个码字必定为0。

如果第一个码字位数为1,则码字为0;

如果第一个码字位数为2,则码字为00;

如此类推。

2)从第二个码字开始,

如果它和它前面的码字位数相同,则当前码字为它前面的码字加1;

如果它的位数比它前面的码字位数大,则当前码字是前面的码字加1后再在后边添若干个0,直至满足位数长度为止。

static BYTE std_dc_chrominance_nrcodes[17]={0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};

static BYTE std_dc_chrominance_values[12]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};

色度表的Huffman的建立是对应的方法。

交流亮度和色度表的创建方法也是使用相同的方法:

std_ac_luminance_nrcodes[17]={0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d };

std_ac_luminance_values[162]= {

0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,

0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,

0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,

0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,

0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,

0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,

0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,

0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,

0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,

0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,

0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,

0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,

0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,

0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,

0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,

0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,

0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,

0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,

0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,

0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,

0xf9, 0xfa };

std_ac_chrominance_nrcodes[17]={0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77};

std_ac_chrominance_values[162]={

0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,

0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,

0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,

0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,

0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,

0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,

0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,

0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,

0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,

0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,

0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,

0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,

0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,

0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,

0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,

0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,

0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,

0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,

0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,

0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,

0xf9, 0xfa };

2、核心数据结构的初始化

主要是通过码字数量表和编码值建立Huffman表,算法如上面的描述,具体的代码实现如下:首先由于要定义长短不同的码字,所以需要定义一个数据结构,用于保存这些信息,定义的结构如下:

typedef struct { BYTE length; WORD value;} bitstring;

length主要是保存数据的位数,value主要是保存数据的值,当需要往文件中书写数据时,首先比较value的值,当写满一个字节之后写入文件,具体的代码如下:

定义两个全局变量bytepos和bytenew,bytepos判断数据有没有写完一个字节,如果写完,就写入文件,bytenew=0,bytepos=7,然后接着写入剩下的数据,从而把所有的数据写入到文件中,实现长短不一的编码格式。

void writebits(bitstring bs)

{

WORD value;.//具体的数据的值

SBYTE posval;

value = bs.value;

posval = bs.length - 1;//数据码字的长度

while (posval >= 0)

{

if (value & mask[posval]) //判断当前位是否为1

bytenew |= mask[bytepos];//写入到bytenew中。

posval--;

bytepos--;

if (bytepos < 0)

{

if (bytenew == 0xFF)

{

writebyte(0xFF);

writebyte(0);

}

else

writebyte(bytenew);

bytepos = 7;

bytenew = 0;

}

}

}

继续初始化Huffman表,代码的如下:nrcodes是码字数量,std_table是码字内容。

void compute_Huffman_table(BYTE *nrcodes, BYTE *std_table, bitstring *HT)//这里通过码字数量和编码内容构建Huffman树

{

BYTE k,j;

BYTE pos_in_table;

WORD codevalue;

codevalue = 0;

pos_in_table = 0;

for (k=1; k<=16; k++)

{

for (j=1; j<=nrcodes[k]; j++) //判断每一个码字的数量

{

HT[std_table[pos_in_table]].value = codevalue;//如果是相同的码字,直接是+1

HT[std_table[pos_in_table]].length = k;//如果不是,就是K+1,

pos_in_table++;

codevalue++;

}

codevalue <<= 1;//并且codevalue向左平移1位。

}

}

通过这样的方法,在HT表中构建出需要编码所需要的Huffman树。

三、整个算法的流程

1:首先需要往文件写入标志位,tag位,代码如下:

writeword(0xFFD8); // 往文件中写入标志位

write_APP0info();

write_DQTinfo();

write_SOF0info();

write_DHTinfo();

write_SOSinfo();

//初始化码字位和中间值,进行主编码。

bytenew = 0; // 当前的位

bytepos = 7; // 这个字节中位的位置

main_encoder();

//写入剩余部分的编码

if (bytepos >= 0)

{

fillbits.length = bytepos + 1;

fillbits.value = (1<<(bytepos+1)) - 1;

writebits(fillbits);

}

writeword(0xFFD9); //写入结束位

前面的写入文件比较简单,这里主要介绍编码的主过程,首先是把图像数据分割成为小的8*8的数据单元,从RGB空间转化到YCbCr空间。

void main_encoder()

{

SWORD DCY = 0, DCCb = 0, DCCr = 0; //DC coefficients used for differential encoding

WORD xpos, ypos;

for (ypos=0; ypos

{

for (xpos=0; xpos

{

load_data_units_from_RGB_buffer(xpos, ypos);// 从RGB空间转化到YCbCr空间。

process_DU(YDU, fdtbl_Y, &DCY, YDC_HT, YAC_HT);//编码Y分量

process_DU(CbDU, fdtbl_Cb, &DCCb, CbDC_HT, CbAC_HT); //编码Cb分量

process_DU(CrDU, fdtbl_Cb, &DCCr, CbDC_HT, CbAC_HT);//编码Cr分量}

}

}

//把数据从RGB空间转化为VCbCr空间。这里在转化时,主要是使用构建的RGB和YCbCr 的空间转化表实现,空间转化表的构建如下:

void precalculate_YCbCr_tables()//确定一个RGB和YCbCr的一个索引的关系。

{

WORD R,G,B;

for (R=0; R<256; R++)

{

YRtab[R] = (SDWORD)(65536*0.299+0.5)*R;

CbRtab[R] = (SDWORD)(65536*-0.16874+0.5)*R;

CrRtab[R] = (SDWORD)(32768)*R;

}

for (G=0; G<256; G++)

{

YGtab[G] = (SDWORD)(65536*0.587+0.5)*G;

CbGtab[G] = (SDWORD)(65536*-0.33126+0.5)*G;

CrGtab[G] = (SDWORD)(65536*-0.41869+0.5)*G;

}

for (B=0; B<256; B++)

{

YBtab[B] = (SDWORD)(65536*0.114+0.5)*B;

CbBtab[B] = (SDWORD)(32768)*B;

CrBtab[B] = (SDWORD)(65536*-0.08131+0.5)*B;

}

}

通过这个中间转化表,可以直接从RGB空间索引出YCbCr的值,从而相加平移得到对应得值。

定义的转化宏如下:

#define Y(R,G,B) ((BYTE)( (YRtab[(R)]+YGtab[(G)]+YBtab[(B)])>>16 ) - 128)

#define Cb(R,G,B) ((BYTE)( (CbRtab[(R)]+CbGtab[(G)]+CbBtab[(B)])>>16 ) )

#define Cr(R,G,B) ((BYTE)( (CrRtab[(R)]+CrGtab[(G)]+CrBtab[(B)])>>16 ) )

void load_data_units_from_RGB_buffer(WORD xpos, WORD ypos) {

BYTE x, y;

BYTE pos = 0;

DWORD location;

BYTE R, G, B;

location = ypos * width + xpos;

for (y=0; y<8; y++)

{

for (x=0; x<8; x++)

{

R = RGB_buffer[location].R;

G = RGB_buffer[location].G;

B = RGB_buffer[location].B;

// convert to YCbCr

YDU[pos] = Y(R,G,B);

CbDU[pos] = Cb(R,G,B);

CrDU[pos] = Cr(R,G,B);

location++;

pos++;

}

location += width - 8;

}

}

完成转化之后就要处理模块单元,首先要对这个单元进行DCT变化,然后进行z形扫描,处理直流编码和交流编码,完成数据的编码。

首先进行DCT变化,由于DCT变化本身很复杂,并且不是jpeg编码的核心,所以这里不对其进行详细描述,然后是进行Z形扫描,Z形扫描时,使用hash的方法,首先定义一个数

据结构,通过这个数据结构查到所以值,在进行扫描。

zigzag[64]={ 0, 1, 5, 6,14,15,27,28,//类似于hash表,直接把数组转化为Z行扫描结果。

2, 4, 7,13,16,26,29,42,

3, 8,12,17,25,30,41,43,

9,11,18,24,31,40,44,53,

10,19,23,32,39,45,52,54,

20,22,33,38,46,51,55,60,

21,34,37,47,50,56,59,61,

35,36,48,49,57,58,62,63 };

在进行编码过程中SSSS的求解也是很重要的一步,这里通过构建一个对应的关系,来构建SSSS的索引表。

void set_numbers_category_and_bitcode()

{

SDWORD nr;

SDWORD nrlower, nrupper;

BYTE cat;

category_alloc = (BYTE *)malloc(65535*sizeof(BYTE));//分配存储空间

category = category_alloc + 32767; //分配负数存储空间

bitcode_alloc=(bitstring *)malloc(65535*sizeof(bitstring));

bitcode = bitcode_alloc + 32767;

nrlower = 1;

nrupper = 2;

for (cat=1; cat<=15; cat++)

{

for (nr=nrlower; nr

{

category[nr] = cat;//保存的是前缀码索引

bitcode[nr].length = cat;

bitcode[nr].value = (WORD)nr;//保存的是后缀码

}

for (nr=-(nrupper-1); nr<=-nrlower; nr++)

{

category[nr] = cat;

bitcode[nr].length = cat;

bitcode[nr].value = (WORD)(nrupper-1+nr);

}

nrlower <<= 1;//进入下一级空间

nrupper <<= 1;

}

}

通过这些,从而扫描编码内容表,从而确定最终的编码内容表。

void process_DU(SBYTE *ComponentDU,float *fdtbl,SWORD *DC,bitstring *HTDC,bitstring *HTAC)

{

bitstring EOB = HTAC[0x00];

bitstring M16zeroes = HTAC[0xF0];

BYTE i;

BYTE startpos;

BYTE end0pos;

BYTE nrzeroes;

BYTE nrmarker;

SWORD Diff;

fdct_and_quantization(ComponentDU, fdtbl, DU_DCT);//DU_DCT里面保存的就是DCT变化之后的数据

for (i=0; i<64; i++)

DU[zigzag[i]]=DU_DCT[i];//然后经过Z扫描转化为扫描后的结果,Diff = DU[0] - *DC;//先是对直流进行量化,*DC里面保存的就是上一个直流的数据。

*DC = DU[0];

if (Diff == 0)//HTDC保存的是直流的Huffman表

writebits(HTDC[0]); //Diff might be 0

else

{

writebits(HTDC[category[Diff]]);//写入前缀码

writebits(bitcode[Diff]);//写入后缀码

}

for (end0pos=63; (end0pos>0)&&(DU[end0pos]==0); end0pos--) ;//找到最后不是0的元素,后面的数据就可以不进行处理

i = 1;

while (i <= end0pos)

{

startpos = i;

for (; (DU[i]==0) && (i<=end0pos); i++) ;//从前扫描找到第一个不是0的元素

nrzeroes = i - startpos;//这里面就是0的数量

if (nrzeroes >= 16)

{

for (nrmarker=1; nrmarker<=nrzeroes/16; nrmarker++) //就要分成两个进行处理writebits(M16zeroes);

nrzeroes = nrzeroes%16;

}

writebits(HTAC[nrzeroes*16+category[DU[i]]]);//扫描交流Huffman表,确定编码内容,前面的就是NNNN的值,后面的是SSSS的值

writebits(bitcode[DU[i]]);//写入后缀码的值,振幅值。

i++;

}

if (end0pos != 63)

writebits(EOB);

}

到这里就完成了从Bmp到jpeg格式的压缩,具体的可执行代码在后面附上。

关于CAD图纸转化为jpg等图片格式的方法

关于CAD图纸转化为jpg等图片格式的方法,本人总结和归纳了四大类,其中每一大类又有不同的几种方法,望朋友们加以研究,融会贯通,找到最适合自已的方法: 第一类:打印法。(以打印设置为核心,之后转存图片格式) 方法之一:添选postscript level 1打印机,输出eps文件,Photosh op转存为图片格式。 使用指数:★★★★★ 具体步骤:如下 a、下拉菜单“文件”>>“打印机管理器”>>弹出窗口里双击“添加打印机向导”>>“简介”下一步>>“开始”下一步>>“打印机型号” 默认(生产商Adobe型号postscript level 1)下一步>>“输入PCP或P C2”下一步>>“端口”里把右上面的点为“打印到文件” 下一步>>“打印机名称”下一步>>“完成”。 b、然后准备画好的CAD图进行打印,在“打印设备”里下拉选择“Po stscript Level 1”,在右下面勾选“打印到文件”,并选择要保存的EPS文件路径。 c、确认其它打印设置,内容、颜色、线宽等,之后确定。 d、用Photoshop打开导出的EPS文件,设置相应的分辨率。文件打开后,根据自己的需要调整、修改,最后合并图层,另存为想要的图片格式就OK啦。

自我评价:目前最“专业”的方法。可以得到线条的颜色、粗细,可调分辨率等,十分OK。 方法之二:用PbulishToWeb JPG.pc3打印机,直接打印输出JPG文件。使用指数:★☆☆☆☆ 具体步骤:如下 a、准备画好的CAD图,之后点“打印图标”,弹出对话框。 b、在“打印设备”里点下拉,选择“PbulishToWeb JPG.pc3”打印机。 c、在“打印设置”里下拉选择其中一个尺寸,最后点确定。OK。 自我评价:虽说简便,但输出的文件质量不是很理想。 方法之三:将打印出的CAD图纸,用扫描仪扫描成图片。 使用指数:★★★☆☆ 具体步骤:(略) 自我评价:此法虽显笨,也常有用者(我以前就是这样)。需要强调的是结果还算比较理想。 第二类:抓图法。(以屏幕抓图功能为核心,之后保存图片格式) 方法之一:键盘特殊功能键 [Print Screen Sys Rq],按键抓图。 使用指数:★★★☆☆

CAD导出JPG图片格式的方法.

CAD导出JPG图片格式的方法汇总 方法一:渲染到文件 在渲染窗口的“目标”选项的下拉框里选择文件。像素大小可选,我这最高是4096X3072,文件格式可选但没有JPG格式,一般选TTF格式,然后在图片软件中打开,另存为JPG。 方法二:输出到文件 在文件菜单中选“输出”。文件格式可选但没有JPG格式,一般选WMF格式,输出文件奇小,自动转换为白色背景。可以在图片软件中打开,另存为JPG。 方法三:打印到文件(★推荐) 点打印按钮,在打印对话框里选PublishToWeb.JPG.pc3打印机。像素大小有很多标准尺寸可选,我这最高是1600X1280,文件格式可选JPG格式。此方法和打印一样,有很多打印时可选的选项。输出文件自动转换为白色背景。 另有: 解决的方法就是“虚拟打印”!下面一步步的来: 1、打开“文件(file)”菜单下的“打印机管理器(plottermanager)”。 2、运行“打印机添加向导(Add-A-Plotter Wizard)。 3、点击“下一步(next)”,在右边的选项中选择“我的电脑(My Computer)”,继续“下一步”,进入“打印机型号(Plotter Mod el)”选择页面。 4、在左边的“厂商(Manufacturers)”中选择“光栅文件格式(Raster File Formats)”,这是我们可以看到在右边的“型号(Model)”中列出了很多种我们熟悉的图形格式,我习惯于使用JPG格式,选择“独立的JPEG 编组(Independent JPEG Group JFIF)”,点击“下一步(next)”,直到完成。这样我们以后就可以将CAD 图形输出位JPG格式了。接下来我们来看看该如何使用它。 5、用CAD做好一幅图后,我们打开“文件(file)”菜单下的“打印(plotter...)”。在打印对话框中,在打印机类型中选择我们刚刚装好的“Independent JPEG Group JFIF”,在下面的“打印到文件(plot to file)”里添上生成的文件名称和路径,这个文件就是一个可以再photoshop中编辑的图形了。在页面设置中选择一个我们需要的尺寸,其他的就和使用真正的打印机方法是一样的。点击打印后,等几秒钟,图形就生成了。 注:系统默认的页面尺寸只有1280*1600,这个尺寸并不能满足我们的需要。我们可以在打印机的属性中自定义我们所需要的尺寸。 补充: 如果cad是2004或更高版本,就不用自己装打印机了,在打印设备中有一个“PublishToWeb JPG.pc3”的打印机,直接用就行了。 再补充: 方法一:用BMPOUT命令输出为BMP图片,用ACDSEE或WINDOWS附件中的画图程序转成JPG格式图片。 方法二:用JPGOUT命令输出为JPG图片,不过该方法在R14、2000和2002中没有该命令,在CAD2004及以上的版本中才能使用。

“jpeg”和“jpg”两种格式的图片真的是一样吗

“jpeg”和“jpg”两种格式的图片真的是 一样吗 贵州省仁怀市共和小学周万权 只要经常对图片进行编辑并运用的人都知道:“jpeg”和“jpg”两种格式的图片是一样的。前者是Joint Photographic Expert Group 的标准缩写,而后者“jpg”又是前者“jpeg”的缩写。生活中两种格式的图片随时可见。不过,在运用图片编辑或播放时,也会出现一些偶然,只支持jpeg格式的图片而不支持jpg格式的,或者只支持jpg格式的图片而不支持jpeg格式的都有可能,下面谈谈我的运用中出现的问题。 今天,我把手机刚接收到的彩信中的小孩子照片(照片是jpeg 格式的)下载下来,然后通过数据线连接电脑,再拷贝到U盘,将U 盘插入我的液晶互联网电视(注:电视机支持图片和各种格式视频的播放),使用电视机的“多媒体”功能播放,准备和家人一起分享,谁知,“奇迹”发生了。“找不到支持的格式。”这真是“大姑娘上轿——还是第一次遇到。”于是,我试图找找原因,非得在电视机上播放不可(因为我是一位喜欢钻研的人,特别是电脑方面的知识)。我尝试了以下几种方法: 一、我将这些“jpeg”格式的图片复制到Word中,另存 为“*.htm,*html)”,然后打开新生成文件夹“Doc1.files” 下的“jpg”格式的图片,在电视机上能正常播放了。 二、我又将这些图片的后缀名(即扩展名)“jpeg”直 接改写为“jpg”,拷入电视机中,同样能正常播放。

三、我用格式工厂软件把这些“jpeg”格式的图片转化为格式为“jpg”的,理所当然在电视机上能正常播放,可是文件却变小了一些。 后来我电话联系了彩信的发送者,了解到她的照片是通过华为手机拍摄的,这说明华为手机的照相机默认照片格式是为“jpeg”格式。而三星手机的照相机设备默认的照片格式是“jpg”格式;苹果手机的照相机默认的相片格式是“jpeg”;而PC机默认的图片格式又是“jpg”。联想笔记本电脑的相机设备默认的也是“jpg”格式的。可见,不同品牌的手机或设备,其照片的默认格式是不同的。 由此可见:“jpeg”与“jpg”两种格式的图片表面上是一样的,它们之间还是存在着质的区别。

JPG图片文件结构分析

JPG文件结构分析 2010-04-06 22:32 【转自网络作者:一江秋水】 一、简述 JPEG是一个压缩标准,又可分为标准 JPEG、渐进式JPEG及JPEG2000三种: ①标准JPEG:以24位颜色存储单个光栅图像,是与平台无关的格式,支持最高级别的压缩,不过,这种压缩是有损耗的。此类型图片在网页下载时只能由上而下依序显示图片,直到图片资料全部下载完毕,才能看到全貌。 ②渐进式 JPEG:渐进式JPG为标准JPG的改良格式,支持交错,可以在网页下载时,先呈现出图片的粗略外观后,再慢慢地呈现出完整的内容,渐进式JPG 的文件比标准JPG的文件要来得小。 ③JPEG2000:新一代的影像压缩法,压缩品质更好,其压缩率比标准JPEG高约30%左右,同时支持有损和无损压缩。一个极其重要的特征在于它能实现渐进传输,即先传输图像的轮廓,然后逐步传输数据,让图像由朦胧到清晰显示。 以一幅24 位彩色图像为例,JPEG的压缩分为四个步骤: ①颜色转换:在将彩色图像进行压缩之前,必须先对颜色模式进行数据转换。转换完成之后还需要进行数据采样。 ②DCT变换:是将图像信号在频率域上进行变换,分离出高频和低频信息的处理过程,然后再对图像的高频部分(即图像细节)进行压缩。首先以象素为单位将图像划分为多个8×8的矩阵,然后对每一个矩阵作DCT 变换。把8×8的象素矩阵变成8×8的频率系数矩阵(所谓频率就是颜色改变的速度),频率系数都是浮点数。 ③量化:由于下面第四步编码过程中使用的码本都是整数,因此要对频率系数进行量化,将之转换为整数。数据量化后,矩阵中的数据都是近似值,和原始图像数据之间有了差异,这一差异是造成图像压缩后失真的主要原因。这一过程中,质量因子的选取至为重要。值选得大,可以大幅度提高压缩比,但是图像质量就比较差,质量因子越小图像重建质量越好,但是压缩比越低。 ④编码:编码是基于统计特性的方法。 四个步骤都完成后的JPEG文件,其基本数据结构为两大类型:“段”和经过压缩编码的图像数据。 二、数据结构 1.段的一般结构如下表所示: 表1:段的一般结构 ----------------------------------------------------------------- 名称字节数数据说明

将JPG格式图片转成PDF文档

将JPG格式图片转成PDF文档 导语:想要既能够识别图像,保持图像以及超链接,还有就是不会导致排版的错乱保持原始版面,以及不会出现乱码确实不好实现。其实JPG 转PDF可以自定义转换页面范围,也可以进行大批量的转换,期间不需要人工的干预,节省了大量的时间与精力。 在公司担任美工一职的日常工作中除了对大量图片进行PS外,还负责进行产品的拍摄,而拍摄的角度和图像的清晰直接影响到产品的展位,若要将一年公司所有所购物品进行分类,以PDF电子文档格式展示,要将这么多的JPG图片进行归类转换,没有识别率较高的JPG转PDF是无论如何也办不到的,图片转PDF转换器正式版后,对存放相应图片文件夹能进行批量转换,即可全自动地对PDF文件集中进行转换处理,并且有效保证了转换后的PDF内容与原图片内容一致性,从而节省了更多的时间和精力,最后得到了老总的认可。

针对普通的JPG转换成PDF转换测试的过程当中,除了最终转换出来的PDF文件内容存在质量问题之外,整个实际转换的过程耗时明显更长。针对这个问题,若转换过程采用单线程技术,效率低,资源占用大,容易造成系统卡死等问题。启用了多线程技术核心体系,内置的加速转换模块可以在多核心CPU的支持下,快速实现内容的解析和同步转换。 JPG转PDF转换的三大特色: 1、拥有完美的JPG文件识别技术:能够深入JPG文件内容进行扫描和分析,快速有效地进行转换,不会出现识别错误以及排版问题。 2、批量JPG转换PDF能够针对大量JPG文件进行一次性转换,快速完成JPG文件转换。 3、多线程处理:JPG转JPG转换在转换效率上完全领先于普通转换,主要得益于软件本身的多线程技术。超线程技术使得软件本身可以在高效率转换程序的基础之上,进一步接触多核心CPU的强大执行效率,辅助提升转换的效率,减少转换过程的耗时。 相对来说,电脑端的JPG转换PDF转换功能更为全面。目前电脑端版本除了支持在线版的各种功能之外,还能够实现批量图片的转换。该功能对于企业用户和经常需要执行大量文件转换的用户来说,非常实用而且能够节省不少的时间。

苹果照片怎么存成jpg的格式

苹果照片怎么存成jpg的格式 现在的年轻人,作为时尚引领的一代,总是走在时代的前沿上,苹果手机自然成为了他们的标配。因为苹果手机的办公软件多,操作方便,所以同时成为了他们的挚爱,可是自从ios11系统的出现,部分人士开始弃机,因为新系统的图片格式变成了heic的,在将图片传阅给他人看时,总会有着各种各样的原因打不开,那么,苹果照片怎么存成jpg的格式呢?那么,heic转jpg如何操作呢? HEIC转JPGhttps://www.wendangku.net/doc/5815348923.html,/heic2jpg HEIC转换器https://www.wendangku.net/doc/5815348923.html,/soft/265983.html

苹果的heic格式,相比较jpg格式来说优势很大,在图片质量变高的情况同时,内存的存储量却在减少,因为是新出现的格式,针对它的软件很少,但是小编今天给大家了想出一个很好的解决办法,借助第三方的HEIC转换器软件从转换的角度打开照片。 1.首先我们需要打开电脑上的任意一个浏览器,搜索该第三方软件的名称,点击进入对应的网站开始下载软件

2.下载完软件后,直接立即体验,此时快捷方式会自动保存到桌面上,我们点击软件界面的添加文件,找到我们要转换的图片文件 3.文件添加好之后,眼睛目光转移到软件的底部,选择好软件的输出格式、图片质量、图片大小等

4.如果要转换手机中的多张图片时,点击屏幕的左上角“添加文件”,目前不支持一键添加多张,只能依次添加,再转换图片 5.如果你只用转换一张图片和话,就直接点击右下角的“开始转换”的标示

6.转换完成后的图片在右上角的文件查看标志,不要当做不知道哟 . 以上就是苹果照片怎么存成jpg的格式的相关知识,希望这篇文章能对你有所帮助,想关注更多这方面的知识,记得关注小编!

相关文档
相关文档 最新文档