cc++javac#读取png图片

cc++javac#读取png图片,第1张

给你一个java的,自己改改

import javaawt;

import javaawtimage;

import javautilRandom;

import javaio;

import javaxswing;

public class LoadImage {

/

@param args

/

public static void main(String[] args) {

String myreadline = "";

//定义一个String类型的变量,用来每次读取一行

try {

FileReader fr = new FileReader("data/imagelisttxt");//创建FileReader对象,用来读取字符流

BufferedReader br = new BufferedReader(fr); //缓冲指定文件的输入

FileWriter fw = new FileWriter("data/17d_resulttxt");//创建FileWriter对象,用来写入字符流

BufferedWriter bw = new BufferedWriter(fw); //将缓冲对文件的输出

while (brready()) {

myreadline = brreadLine();//读取一行

BufferedImage image = toBufferedImage(new ImageIcon("data/Image/"+myreadline)getImage());

int height = imagegetHeight();

int width = imagegetWidth();

int r1=0, r2=0, r3=0, r4=0, r5=0, r6=0, r7=0, r8=0, r9=0, r10=0, r11=0, r12=0, r13=0, r14=0, r15=0, r16=0, r17=0;

int g1=0, g2=0, g3=0, g4=0, g5=0, g6=0, g7=0, g8=0, g9=0, g10=0, g11=0, g12=0, g13=0, g14=0, g15=0, g16=0, g17=0;

int b1=0, b2=0, b3=0, b4=0, b5=0, b6=0, b7=0, b8=0, b9=0, b10=0, b11=0, b12=0, b13=0, b14=0, b15=0, b16=0, b17=0;

int rgb1=0, rgb2=0, rgb3=0, rgb4=0, rgb5=0, rgb6=0, rgb7=0, rgb8=0, rgb9=0, rgb10=0, rgb11=0, rgb12=0, rgb13=0, rgb14=0, rgb15=0, rgb16=0, rgb17=0;

//Systemoutprintln("Height=" + height + ", Width=" + width);

//Random ran = new Random();

//int x = rannextInt(width), y = rannextInt(height);

for (int y=0;y<height;y++) {

for (int x=0;x<width;x++) {

Color color = new Color(imagegetRGB(x, y));

if(colorgetRed()<=15)

r1++;

if(colorgetRed()>15 && colorgetRed()<=30)

r2++;

if(colorgetRed()>30 && colorgetRed()<=45)

r3++;

if(colorgetRed()>45 && colorgetRed()<=60)

r4++;

if(colorgetRed()>60 && colorgetRed()<=75)

r5++;

if(colorgetRed()>75 && colorgetRed()<=90)

r6++;

if(colorgetRed()>90 && colorgetRed()<=105)

r7++;

if(colorgetRed()>105 && colorgetRed()<=120)

r8++;

if(colorgetRed()>120 && colorgetRed()<=135)

r9++;

if(colorgetRed()>135 && colorgetRed()<=150)

r10++;

if(colorgetRed()>150 && colorgetRed()<=165)

r11++;

if(colorgetRed()>165 && colorgetRed()<=180)

r12++;

if(colorgetRed()>180 && colorgetRed()<=195)

r13++;

if(colorgetRed()>195 && colorgetRed()<=210)

r14++;

if(colorgetRed()>210 && colorgetRed()<=225)

r15++;

if(colorgetRed()>225 && colorgetRed()<=240)

r16++;

if(colorgetRed()>240 && colorgetRed()<=255)

r17++;

if(colorgetGreen()<=15)

g1++;

if(colorgetGreen()>15 && colorgetGreen()<=30)

g2++;

if(colorgetGreen()>30 && colorgetGreen()<=45)

g3++;

if(colorgetGreen()>45 && colorgetGreen()<=60)

g4++;

if(colorgetGreen()>60 && colorgetGreen()<=75)

g5++;

if(colorgetGreen()>75 && colorgetGreen()<=90)

g6++;

if(colorgetGreen()>90 && colorgetGreen()<=105)

g7++;

if(colorgetGreen()>105 && colorgetGreen()<=120)

g8++;

if(colorgetGreen()>120 && colorgetGreen()<=135)

g9++;

if(colorgetGreen()>135 && colorgetGreen()<=150)

g10++;

if(colorgetGreen()>150 && colorgetGreen()<=165)

g11++;

if(colorgetGreen()>165 && colorgetGreen()<=180)

g12++;

if(colorgetGreen()>180 && colorgetGreen()<=195)

g13++;

if(colorgetGreen()>195 && colorgetGreen()<=210)

g14++;

if(colorgetGreen()>210 && colorgetGreen()<=225)

g15++;

if(colorgetGreen()>225 && colorgetGreen()<=240)

g16++;

if(colorgetGreen()>240 && colorgetGreen()<=255)

g17++;

if(colorgetBlue()<=15)

b1++;

if(colorgetBlue()>15 && colorgetBlue()<=30)

b2++;

if(colorgetBlue()>30 && colorgetBlue()<=45)

b3++;

if(colorgetBlue()>45 && colorgetBlue()<=60)

b4++;

if(colorgetBlue()>60 && colorgetBlue()<=75)

b5++;

if(colorgetBlue()>75 && colorgetBlue()<=90)

b6++;

if(colorgetBlue()>90 && colorgetBlue()<=105)

b7++;

if(colorgetBlue()>105 && colorgetBlue()<=120)

b8++;

if(colorgetBlue()>120 && colorgetBlue()<=135)

b9++;

if(colorgetBlue()>135 && colorgetBlue()<=150)

b10++;

if(colorgetBlue()>150 && colorgetBlue()<=165)

b11++;

if(colorgetBlue()>165 && colorgetBlue()<=180)

b12++;

if(colorgetBlue()>180 && colorgetBlue()<=195)

b13++;

if(colorgetBlue()>195 && colorgetBlue()<=210)

b14++;

if(colorgetBlue()>210 && colorgetBlue()<=225)

b15++;

if(colorgetBlue()>225 && colorgetBlue()<=240)

b16++;

if(colorgetBlue()>240 && colorgetBlue()<=255)

b17++;

}

}

rgb1 = r1 + g1 + b1;

rgb2 = r2 + g2 + b2;

rgb3 = r3 + g3 + b3;

rgb4 = r4 + g4 + b4;

rgb5 = r5 + g5 + b5;

rgb6 = r6 + g6 + b6;

rgb7 = r7 + g7 + b7;

rgb8 = r8 + g8 + b8;

rgb9 = r9 + g9 + b9;

rgb10 = r10 + g10 + b10;

rgb11 = r11 + g11 + b11;

rgb12 = r12 + g12 + b12;

rgb13 = r13 + g13 + b13;

rgb14 = r14 + g14 + b14;

rgb15 = r15 + g15 + b15;

rgb16 = r16 + g16 + b16;

rgb17 = r17 + g17 + b17;

//Systemoutprintln("rect " + rgb1 + " " + rgb2 + " " + rgb3);

bwwrite("rect " + rgb1 + " " + rgb2 + " " + rgb3 + " " + rgb4 + " " + rgb5 + " " + rgb6 + " " + rgb7 + " " + rgb8 + " " + rgb9 + " " + rgb10 + " " + rgb11 + " " + rgb12 + " " + rgb13 + " " + rgb14 + " " + rgb15 + " " + rgb16 + " " + rgb17); //写入文件

bwnewLine();

//Systemoutprintln(myreadline);//在屏幕上输出

}

bwflush(); //刷新该流的缓冲

bwclose();

brclose();

fwclose();

brclose();

frclose();

} catch (IOException e) {

eprintStackTrace();

}

}

// This method returns a buffered image with the contents of an image

public static BufferedImage toBufferedImage(Image image) {

if (image instanceof BufferedImage) {

return (BufferedImage) image;

}

// Determine if the image has transparent pixels; for this method's

// implementation, see e661 Determining If an Image Has Transparent

// Pixels

boolean hasAlpha = hasAlpha(image);

// Create a buffered image with a format that's compatible with the

// screen

BufferedImage bimage = null;

GraphicsEnvironment ge = GraphicsEnvironment

getLocalGraphicsEnvironment();

try {

// Determine the type of transparency of the new buffered image

int transparency = TransparencyOPAQUE;

if (hasAlpha) {

transparency = TransparencyBITMASK;

}

// Create the buffered image

GraphicsDevice gs = gegetDefaultScreenDevice();

GraphicsConfiguration gc = gsgetDefaultConfiguration();

bimage = gccreateCompatibleImage(imagegetWidth(null), image

getHeight(null), transparency);

} catch (HeadlessException e) {

// The system does not have a screen

}

if (bimage == null) {

// Create a buffered image using the default color model

int type = BufferedImageTYPE_INT_RGB;

if (hasAlpha) {

type = BufferedImageTYPE_INT_ARGB;

}

bimage = new BufferedImage(imagegetWidth(null), image

getHeight(null), type);

}

// Copy image to buffered image

Graphics g = bimagecreateGraphics();

// Paint the image onto the buffered image

gdrawImage(image, 0, 0, null);

gdispose();

return bimage;

}

// This method returns true if the specified image has transparent pixels

public static boolean hasAlpha(Image image) {

// If buffered image, the color model is readily available

if (image instanceof BufferedImage) {

BufferedImage bimage = (BufferedImage) image;

return bimagegetColorModel()hasAlpha();

}

// Use a pixel grabber to retrieve the image's color model;

// grabbing a single pixel is usually sufficient

PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);

try {

pggrabPixels();

} catch (InterruptedException e) {

}

// Get the image's color model

ColorModel cm = pggetColorModel();

return cmhasAlpha();

}

}

没必要那么麻烦只要使用GDI+库里面的Bitmap对象和Graphics对象就可以了。WindowsXP以上的OS都提供GDI+图形接口了,他的功能比GDI接口更强大,使用更方便。建议你可以查查GDI+的用法。这里给你个最简单的C#的例子:

SystemDrawingBitmap bmp = new Bitmap("1png");//创建Bitmap对象

SystemDrawingColor c = bmpGetPixel(0, 0);//获得图像上(0,0)点的像素

int a = cA;//该像素的Alpha通道值

int r = cR;//该像素的红色通道值

int g = cG;//该像素的绿色通道值

int b = cB;//该像素的蓝色通道

那建议你上网查一查PNG格式的标准,就知道PNG文件里的数据排列了。但PNG是压缩过的,所以你还得有解压算法才行。

png的存储格式:

关键数据块中有4个标准数据块:

文件头数据块IHDR(header chunk):包含有图像基本信息,作为第一个数据块出现并只出现一次。

调色板数据块PLTE(palette chunk):必须放在图像数据块之前。

图像数据块IDAT(image data chunk):存储实际图像数据。PNG数据允许包含多个连续的图像数据块。

图像结束数据IEND(image trailer chunk):放在文件尾部,表示PNG数据流结束。

在第二个数据块中包含了调色板数据块。可是,当我们去解析png24时,却未找到调色板、并且我们发现png24的存储模式是点阵颜色值加一位的阿尔法通道值构成的,这种存储模式根本不需要调色板的存在。基于这种存储模式,png24的位深最低是32位真彩,在我们看到的图像过渡中会很圆润,因为每个点都可以是不同的色彩以及不同的透明值。而这种模式也是我们最常使用、大家所理解中的png模式。至于"png"后面的“24”可见也和位深并无关系,至于为什么叫24,我也没有找到具体的答案。

png24源数据中无调色盘的存在,而在标准数据块的第二块中,却显示了调色板数据块。即然存在,肯定是有意义的,可见png有另外一种存储模式--带色盘的png8模式。png8有点类似于GIF,包含了一个调色板,并在调色板上有一个透明颜色值,这种模式在计算机的存储中,每个点阵存储的是色盘索引、并且无阿尔法半透明位。所以,png8在颜色位深上,可以低于32位;也可以使用更换色盘的技术来处理一些独特的效果;但是由于每个点阵没有阿尔法定义,边缘会像GIF一样存在锯齿现像。

好像讲的有点乱,总结一下区别吧:

png8和png24的根本区别,不是颜色位的区别,而是存储方式不同;

png8 色盘索引、调色板中一位透明值、不支持阿尔法通道的半透明,存储格式中每个像素无透明度的数据块定义;

png24 无调色板、支持阿尔法通道的半透明、每个点阵都有透明度的定义,最低32位真彩色;

特性

支持256色调色板技术以产生小体积文件

最高支持48位真彩色图像以及16位灰度图像。

支持阿尔法通道的半透明特性。

支持图像亮度的gamma校正信息。

支持存储附加文本信息,以保留图像名称、作者、版权、创作时间、注释等信息。

使用无损压缩

渐近显示和流式读写,适合在网络传输中快速显示预览效果后再展示全貌。

使用CRC循环冗余编码防止文件出错。

最新的PNG标准允许在一个文件内存储多幅图像。

看。有使用无损压缩和多幅图像。挺复杂的哦!

>

在 VC++ 中,可以使用 MFC 库提供的 CImage 类来判断是否为空白以及读取当前大小。

判断是否为空白

要判断一张是否为空白,可以使用 CImage 类的 GetSize() 方法获取的大小,然后遍历的每个像素点,判断像素点的 RGB 值是否为 255(即白色)。如果所有像素点的 RGB 值都为 255,则说明该为空白。

示例代码如下:

CImage image;

imageLoad(_T("testjpg")); // 加载

// 获取大小

int width = imageGetWidth();

int height = imageGetHeight();

bool isBlank = true; // 是否为空白

// 遍历每个像素点

for (int i = 0; i < width; i++) {

for (int j = 0; j < height; j++) {

// 获取像素点的 RGB 值

COLORREF color = imageGetPixel(i, j);

int r = GetRValue(color);

int g = GetGValue(color);

int b = GetBValue(color);

// 判断像素点的 RGB 值是否为白色

if (r != 255 || g != 255 || b != 255) {

isBlank = false;

break;

}

}

if (!isBlank) {

break;

}

}

if (isBlank) {

// 空白

}

else {

// 非空白

}

上述代码中,我们首先使用 CImage 类的 Load() 方法加载了一张,然后使用 GetSize() 方法获取了的大小。接着,我们使用双重循环遍历了的每个像素点,并判断像素点的 RGB 值是否为白色。如果所有像素点的 RGB 值都为白色,则将 isBlank 标记为 true,否则将其标记为 false。最后,根据 isBlank 的值来判断是否为空白。

需要注意的是,这种判断方式并不是非常准确,因为有可能存在非常浅的颜色(比如灰色)或者透明度不为 0 的像素点。因此,判断是否为空白需要根据具体的应用场景进行具体分析和处理。

读取当前大小

要读取一张的大小(即占用硬盘容量大小),可以使用 CImage 类的 GetFileSize() 方法获取。该方法返回的是占用硬盘容量大小(单位为字节),需要将其转换为 KB 才能表示为人类可读的格式。

示例代码如下:

CImage image;

imageLoad(_T("testjpg")); // 加载

// 获取大小(单位为字节)

int fileSize = imageGetFileSize();

// 转换为 KB

double fileSizeKB = fileSize / 10240;

// 输出大小(保留两位小数)

printf("The size of the image is %2f KB\n", fileSizeKB);

详细情况参阅下文,不过换算很麻烦,自己看看吧(这里只有一半,文章太大,发不上来,如要后半部,写信给我)。另外我有一个能得到指定的大小的Dll文件,如果需要也可告诉我。mm1990@qqcom

JPEG 压缩简介

-------------

1 色彩模型

JPEG 的使用的是 YCrCb 颜色模型, 而不是计算机上最常用的 RGB 关于色

彩模型, 这里不多阐述 只是说明, YCrCb 模型更适合图形压缩 因为人眼对上

的亮度 Y 的变化远比色度 C 的变化敏感 我们完全可以每个点保存一个 8bit 的亮

度值, 每 2x2 个点保存一个 Cr Cb 值, 而图象在肉眼中的感觉不会起太大的变化

所以, 原来用 RGB 模型, 4 个点需要 4x3=12 字节 而现在仅需要 4+2=6 字节; 平

均每个点占 12bit 当然 JPEG 格式里允许每个点的 C 值都记录下来; 不过 MPEG 里

都是按 12bit 一个点来存放的, 我们简写为 YUV12

[R G B] -> [Y Cb Cr] 转换

-------------------------

(R,G,B 都是 8bit unsigned)

| Y | | 0299 0587 0114 | | R | | 0 |

| Cb | = |- 01687 - 03313 05 | | G | + |128|

| Cr | | 05 - 04187 - 00813| | B | |128|

Y = 0299R + 0587G + 0114B (亮度)

Cb = - 01687R - 03313G + 05 B + 128

Cr = 05 R - 04187G - 00813B + 128

[Y,Cb,Cr] -> [R,G,B] 转换

-------------------------

R = Y + 1402 (Cr-128)

G = Y - 034414(Cb-128) - 071414(Cr-128)

B = Y + 1772 (Cb-128)

一般, C 值 (包括 Cb Cr) 应该是一个有符号的数字, 但这里被处理过了, 方法

是加上了 128 JPEG 里的数据都是无符号 8bit 的

2 DCT (离散余弦变换)

JPEG 里, 要对数据压缩, 先要做一次 DCT 变换 DCT 变换的原理, 涉及到数学

知识, 这里我们不必深究 反正和傅立叶变换(学过高数的都知道) 是差不多了 经过

这个变换, 就把里点和点间的规律呈现出来了, 更方便压缩JPEG 里是对每 8x8

个点为一个单位处理的 所以如果原始的长宽不是 8 的倍数, 都需要先补成 8

的倍数, 好一块块的处理 另外, 记得刚才我说的 Cr Cb 都是 2x2 记录一次吗 所

以大多数情况, 是要补成 16x16 的整数块按从左到右, 从上到下的次序排列 (和我

们写字的次序一样) JPEG 里是对 Y Cr Cb 分别做 DCT 变换的 这里进行 DCT 变换

的 Y, Cr, Cb 值的范围都是 -128~127 (Y 被减去 128)

JPEG 编码时使用的是 Forward DCT (FDCT) 解码时使用的 Inverse DCT (IDCT)

下面给出公式:

FDCT:

7 7 2x+1 2y+1

F(u,v) = alpha(u)alpha(v) sum sum f(x,y) cos (------- uPI) cos (------ vPI)

x=0 y=0 16 16

u,v = 0,1,,7

{ 1/sqrt(8) (u==0)

alpha(u) = {

{ 1/2 (u!=0)

IDCT:

7 7 2x+1 2y+1

f(x,y) = sum sum alpha(u)alpha(v)F(u,v)cos (------- uPI) cos (------ vPI)

u=0 v=0 16 16

x,y=0,17

这个步骤很花时间, 另外有种 AA&N 优化算法, 大家可以去 inet 自己找一下

在 Intel 主页上可以找到 AA&N IDCT 的 MMX 优化代码 ( Intel 主页上的代码,

输入数据为 124 的定点数, 输入矩阵需要转置 90 度)

3 重排列 DCT 结果

DCT 将一个 8x8 的数组变换成另一个 8x8 的数组 但是内存里所有数据都是线

形存放的, 如果我们一行行的存放这 64 个数字, 每行的结尾的点和下行开始的点就

没有什么关系, 所以 JPEG 规定按如下次序整理 64 个数字

0, 1, 5, 6,14,15,27,28,

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

这样数列里的相邻点在上也是相邻的了

4 量化

对于前面得到的 64 个空间频率振幅值, 我们将对它们作幅度分层量化 *** 作方

法就是分别除以量化表里对应值并四舍五入

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

vector[i] = (int) (vector[i] / quantization_table[i] + 05)

下面有张 JPEG 标准量化表 (按上面同样的弯曲次序排列)

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

这张表依据心理视觉阀制作, 对 8bit 的亮度和色度的图象的处理效果不错

当然我们可以使用任意的量化表 量化表是定义在 jpeg 的 DQT 标记后 一般

为 Y 值定义一个, 为 C 值定义一个

量化表是控制 JPEG 压缩比的关键 这个步骤除掉了一些高频量, 损失了很高

细节 但事实上人眼对高空间频率远没有低频敏感所以处理后的视觉损失很小

另一个重要原因是所有的的点与点之间会有一个色彩过渡的过程 大量的图象

信息被包含在低空间频率中 经过量化处理后, 在高空间频率段, 将出现大量连续

的零

注意, 量化后的数据有可能超过 2 byte 有符号整数的处理范围

5 0 RLC 编码

现在我们矢量中有许多连续的 0 我们可以使用 RLC 来压缩掉这些 0 这里我们

将跳过第一个矢量 (后面将解释为什么) 因为它的编码比较特别 假设有一组矢量

(64 个的后 63 个) 是

57,45,0,0,0,0,23,0,-30,-16,0,0,1,0,0,0, 0 , 0 ,0 , 0,,0

经过 RLC 压缩后就是

(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-16) ; (2,1) ; EOB

EOB 是一个结束标记, 表示后面都是 0 了 实际上, 我们用 (0,0) 表示 EOB

但是, 如果这组数字不以 0 结束, 那么就不需要 EOB

由于后面 huffman 编码的要求, 每组数字前一个表示 0 的数量的必须是 4 bit,

就是说, 只能是 0~15, 所以我们实际这样编码:

(0,57) ; (15,0) (2,3) ; (4,2) ; (15,0) (15,0) (1,895) , (0,0)

注意 (15,0) 表示了 16 个连续的 0

6 huffman 编码

为了提高储存效率, JPEG 里并不直接保存数值, 而是将数值按位数分成 16 组:

数值 组 实际保存值

0 0 -

-1,1 1 0,1

-3,-2,2,3 2 00,01,10,11

-7,-6,-5,-4,4,5,6,7 3 000,001,010,011,100,101,110,111

-15,,-8,8,,15 4 0000,,0111,1000,,1111

-31,,-16,16,,31 5 00000,,01111,10000,,11111

-63,,-32,32,,63 6

-127,,-64,64,,127 7

-255,,-128,128,,255 8

-511,,-256,256,,511 9

-1023,,-512,512,,1023 10

-2047,,-1024,1024,,2047 11

-4095,,-2048,2048,,4095 12

-8191,,-4096,4096,,8191 13

-16383,,-8192,8192,,16383 14

-32767,,-16384,16384,,32767 15

还是来看前面的例子:

(0,57) ; (0,45) ; (4,23) ; (1,-30) ; (0,-8) ; (2,1) ; (0,0)

只处理每对数右边的那个:

57 是第 6 组的, 实际保存值为 111001 , 所以被编码为 (6,111001)

45 , 同样的 *** 作, 编码为 (6,101101)

23 -> (5,10111)

-30 -> (5,00001)

-8 -> (4,0111)

1 -> (1,1)

前面的那串数字就变成了:

(0,6), 111001 ; (0,6), 101101 ; (4,5), 10111; (1,5), 00001; (0,4) , 0111 ;

(2,1), 1 ; (0,0)

括号里的数值正好合成一个字节 后面被编码的数字表示范围是 -3276732767

合成的字节里, 高 4 位是前续 0 的个数, 低 4 位描述了后面数字的位数

继续刚才的例子, 如果 06 的 huffman 编码为 111000

69 = (4,5) --- 1111111110011001

21 = (1,5) --- 11111110110

4 = (0,4) --- 1011

33 = (2,1) --- 11011

0 = EOB = (0,0) --- 1010

那么最后对于前面的例子表示的 63 个系数 (记得我们将第一个跳过了吗) 按位流

写入 JPG 文件中就是这样的:

111000 111001 111000 101101 1111111110011001 10111 11111110110 00001

1011 0111 11011 1 1010

DC 的编码

---------

记得刚才我们跳过了每组 64 个数据的第一个吧, DC 就是指的这个数字 (后面 63

个简称 AC) 代入前面的 FDCT 公式可以得到

c(0,0) 7 7

DC = F(0,0) = --------- sum sum f(x,y) cos 0 cos 0 其中 c(0,0) = 1/2

4 x=0 y=0

1 7 7

= --- sum sum f(x,y)

8 x=0 y=0

即一块图象样本的平均值 就是说, 它包含了原始 8x8 图象块里的很多能量 (通常

会得到一个很大的数值)

JPEG 的作者指出连续块的 DC 率之间有很紧密的联系, 因此他们决定对 8x8 块的

DC 值的差别进行编码 (Y, Cb, Cr 分别有自己的 DC)

Diff = DC(i) - DC(i-1)

所以这一块的 DC(i) 就是: DC(i) = DC(i-1) + Diff

JPG 从 0 开始对 DC 编码, 所以 DC(0)=0 然后再将当前 Diff 值加在上一个值上得

到当前值

下面再来看看上面那个例子: (记住我们保存的 DC 是和上一块 DC 的差值 Diff)

例如上面例子中, Diff 是 -511, 就编码成

(9, 000000000)

如果 9 的 Huffman 编码是 1111110 (在 JPG 文件中, 一般有两个 Huffman 表, 一

个是 DC 用, 一个是 AC 用) 那么在 JPG 文件中, DC 的 2 进制表示为

1111110 000000000

它将放在 63 个 AC 的前面, 上面上个例子的最终 BIT 流如下:

1111110 000000000 111000 111001 111000 101101 1111111110011001 10111

11111110110 00001 1011 0111 11011 1 1010

下面简单叙述一下针对一个数据单元的 Y 的解码

-----------------------------------------------

在整个解码的开始, 你需要先初始化 DC 值为 0

1) 先解码 DC:

a) 取得一个 Huffman 码 (使用 Huffman DC 表)

b) Huffman解码, 看看后面的数据位数 N

c) 取得 N 位, 计算 Diff 值

d) DC + = Diff

e) 写入 DC 值: " vector[0]=DC "

2) 解码 63 个 AC:

------- 循环处理每个 AC 直到 EOB 或者处理到 64 个 AC

a) 取得一个 Huffman 码 (使用 Huffman AC 表)

b) Huffman 解码, 得到 (前面 0 数量, 组号)

[记住: 如果是(0,0) 就是 EOB 了]

c) 取得 N 位(组号) 计算 AC

d) 写入相应数量的 0

e) 接下来写入 AC

-----------------

下一步的解码

------------

上一步我们得到了 64 个矢量 下面我们还需要做一些解码工作:

1) 反量化 64 个矢量 : "for (i=0;i<=63;i++) vector[i]=quant[i]" (注意防止溢出)

2) 重排列 64 个矢量到 8x8 的块中

3) 对 8x8 的块作 IDCT

对 8x8 块的 (Y,Cb,Cr) 重复上面的 *** 作 [Huffman 解码, 步骤 1), 2), 3)]

4) 将所有的 8bit 数加上 128

5) 转换 YCbCr 到 RGB

JPG 文件(Byte 级)里怎样组织信息

-----------------------------------

注意 JPEG/JFIF 文件格式使用 Motorola 格式, 而不是 Intel 格式, 就是说, 如果

是一个字的话, 高字节在前, 低字节在后

JPG 文件是由一个个段 (segments) 构成的 每个段长度 <=65535 每个段从一个标

记字开始 标记字都是 0xff 打头的, 以非 0 字节和 0xFF 结束 例如 'FFDA' ,

'FFC4', 'FFC0' 每个标记有它特定意义, 这是由第2字节指明的 例如, SOS (Start

Of Scan = 'FFDA') 指明了你应该开始解码 另一个标记 DQT (Define Quantization

Table = 0xFFDB) 就是说它后面有 64 字节的 quantization 表

在处理 JPG 文件时, 如果你碰到一个 0xFF, 而它后面的字节不是 0, 并且这个字节

没有意义 那么你遇到的 0xFF 字节必须被忽略 (一些 JPG 里, 常用用 0xFF 做某

些填充用途) 如果你在做 huffman 编码时碰巧产生了一个 0xFF, 那么就用 0xFF

0x00 代替 就是说在 jpeg 图形解码时碰到 FF00 就把它当作 FF 处理

另外在 huffman 编码区域结束时, 碰到几个 bit 没有用的时候, 应该用 1 去填充

然后后面跟 FF

下面是几个重要的标记

--------------------

SOI = Start Of Image = 'FFD8'

这个标记只在文件开始出现一次

EOI = End Of Image = 'FFD9'

JPG 文件都以 FFD9 结束

RSTi = FFDi ( i = 07) [ RST0 = FFD0, RST7=FFD7]

= 复位标记

通常穿插在数据流里, 我想是担心 JPG 解码出问题吧(应该配合 DRI 使用) 不过很

多 JPG 都不使用它

(SOS --- RST0 --- RST1 -- RST2 --

-- RST6 --- RST7 -- RST0 --)

----

标记

----

下面是必须处理的标记

SOF0 = Start Of Frame 0 = FFC0

SOS = Start Of Scan = FFDA

APP0 = it's the marker used to identify a JPG file which uses the JFIF

specification = FFE0

COM = Comment = FFFE

DNL = Define Number of Lines = FFDC

DRI = Define Restart Interval = FFDD

DQT = Define Quantization Table = FFDB

DHT = Define Huffman Table = FFC4

以上就是关于c/c++/java/c#读取png图片全部的内容,包括:c/c++/java/c#读取png图片、200分c/c++/java/c#读取png图片、VC++如何判断图片是否为空白图片以及读取当前图片大小等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/9534810.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-29
下一篇2023-04-29

发表评论

登录后才能评论

评论列表(0条)

    保存