当前位置:首页 > 芯闻号 > 充电吧
[导读]1、libpng是什么?libpng是一款C语言编写的比较底层的读写PNG文件的跨平台的库,全称是可携式网络图像(portable network graphics),借助它,你可以轻松读写PNG文件


1、libpng是什么?
libpng是一款C语言编写的比较底层的读写PNG文件的跨平台的库,全称是可携式网络图像(portable network graphics),
借助它,你可以轻松读写PNG文件的每一行像素。因为PNG文件是经过压缩而且格式复杂的图形文件(有的PNG文件甚至像GIF文件一样带动画效果,但是不像jpg那样是有损压缩,png是无损压缩的),而且PNG可以是带透明通道的真彩色图像、不带透明通道的真彩色图像、索引颜色、灰度颜色等各种格式,如果大家都自己写程序分析PNG文件就会显得很麻烦、很累。因此,通过使用libpng你就能直接使用现成的函数、程序来读写PNG文件了。
2、怎样让自己的程序可以使用libpng库?
有很多种方法。https://ftp-osl.osuosl.org/pub/libpng/src/ 这里是libpng和zlib的下载位置,遵循GPL协议。 
方法1:上网下载libpng的DLL、LIB文件以及头文件,然后在自己的程序里,包含png.h,链接libpng.lib,就可以了。但是这样的话你的程序需要libpng.dll才能运行,而libpng使用了zlib所以可能你还需要zlib.dll才能运行。因此你还需要下载zlib的头文件、lib、DLL。
方法2:直接下载libpng的源码和zlib的源码,然后把.c文件和.h文件都加入到自己的工程里面。这招最好使因为这样便于调试。只是你的程序会很大因为你的程序直接集成了libpng和zlib。
方法3:下载libpng的源码和zlib的源码,自己将其编译为DLL或LIB,然后包含png.h,链接LIB文件,就能使用。不过你如果没编译好也可能会出问题。

3.PNG文件结构的分析。     介绍:与BMP格式相比,PNG格式稍微复杂些。PNG图像支持从0~255级次的多层透明色,使用无损压缩的zlib压缩算法压缩图像数据。通常使用 zlib压缩过的图像文件大小比BMP使用的RLE压缩的效果好,BMP的RLE压缩算法只支持压缩8位以下的图像,对于16位以上的真彩色图像不支持图 像压缩,PNG使用的zlib压缩算法支持任何色深的图像数据压缩,压缩后的图像数据可以完整还原,相比之下JPG需要牺牲图像质量使用有损压缩来获得大 的压缩率。特别注意:PNG图像格式使用Big-Endian顺序存储数据。

PNG的文件结构

对于一个PNG文件来说,其文件头总是由位固定的字节来描述的:

十进制数

137 80 78 71 13 10 26 10

十六进制数

89 50 4E 47 0D 0A 1A 0A

其中第一个字节0x89超出了ASCII字符的范围,这是为了避免某些软件将PNG文件当做文本文件来处理。文件中剩余的部分由3个以上的PNG的数据块(Chunk)按照特定的顺序组成,因此,一个标准的PNG文件结构应该如下:

PNG文件标志

PNG数据块

……

PNG数据块

所以一个最小的PNG文件由一个PNG文件标志和三个PNG数据块组成。
PNG的文件表示没什么好说的,就是上面固定的8个字节(是存放在文件开头的前8个字节),就是用来检查该文件是否是png文件,比如libpng源码库中中有下面一段代码来用于检测一个文件是否是png文件。
example.c 244 /* Check to see if a file is a PNG file using png_sig_cmp().  png_sig_cmp()
* returns zero if the image is a PNG and nonzero if it isn't a PNG.
*
* The function check_if_png() shown here, but not used, returns nonzero (true)
* if the file can be opened and is a PNG, 0 (false) otherwise.
*
* If this call is successful, and you are going to keep the file open,
* you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once
* you have created the png_ptr, so that libpng knows your application
* has read that many bytes from the start of the file.  Make sure you
* don't call png_set_sig_bytes() with more than 8 bytes read or give it
* an incorrect number of bytes read, or you will either have read too
* many bytes (your fault), or you are telling libpng to read the wrong
* number of magic bytes (also your fault).
*
* Many applications already read the first 2 or 4 bytes from the start
* of the image to determine the file type, so it would be easiest just
* to pass the bytes to png_sig_cmp() or even skip that if you know
* you have a PNG file, and call png_set_sig_bytes().
*/
#define PNG_BYTES_TO_CHECK 4
int check_if_png(char *file_name, FILE **fp)
{
  char buf[PNG_BYTES_TO_CHECK];

  /* Open the prospective PNG file. */
  if ((*fp = fopen(file_name, "rb")) == NULL)
      return 0;

  /* Read in some of the signature bytes */
  if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK)
      return 0;

  /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.
      Return nonzero (true) if they match */

  return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK));
}
png.c 65 /* Checks whether the supplied bytes match the PNG signature.  We allow
* checking less than the full 8-byte signature so that those apps that
* already read the first few bytes of a file to determine the file type
* can simply check the remaining bytes for extra assurance.  Returns
* an integer less than, equal to, or greater than zero if sig is found,
* respectively, to be less than, to match, or be greater than the correct
* PNG signature (this is the same behavior as strcmp, memcmp, etc).
*/
int PNGAPI
png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check)
{
  png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};

  if (num_to_check > 8)
      num_to_check = 8;

  else if (num_to_check < 1)
      return (-1);

  if (start > 7)
      return (-1);

  if (start + num_to_check > 8)
      num_to_check = 8 - start;

  return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check)));//是比较内存区域buf1和buf2的前count个字节,相等返回0,不等返回非0.
}

下面着重介绍数据块的组成。

紧跟在PNG文件标志后面的数据是数据块(chunks),数据块(chunks)分为两类:关键数据块(critical chunks)和辅助数据块(ancillary chunks)。

关键数据块(critical chunk)在PNG文件中是必须有的,而辅助数据块(ancillary chunks)是可选的。

关键数据块(critical chunks)由4部分组成:文件头数据块(IHDR)、调色板数据块(PLTE)、图像数据块(IDAT)和图像结束数据(IEND),其中调色板数据块(PLTE)根据图像的色深可选。

数据块名称

允许多

个数据块

位 置

文件头数据块(IHDR)

不允许

第一个数据块

调色板数据块(PLTE)

不允许

第二个数据块,可选

图像数据块(IDAT)

允许

如果有调色板数据块(PLTE),则是第三个数据块,如果没有调色板数据块(PLTE),则时第二个数据块。如果有多个图像数据块,则必须按图像数据连续存储

图像结束数据(IEND)

不允许

最后一个数据块


辅助数据块(ancillary chunks)一共有14个,这些辅助数据块包含了很多信息,辅助数据块不是必须包含的。

数据块名称

允许多个

数据块

位 置

基色和白色点数据块(cHRM)

不允许

在PLTE和IDAT之前

图像γ数据块(gAMA)

不允许

在PLTE和IDAT之前

ICCP(iCCP)

允许

在PLTE之后IDAT之前如果有iCCP,则无sRGB

数据块名称

允许多个

数据块

位 置

样本有效位数据块(sBIT)

不允许

在PLTE和IDAT之前

标准RPG颜色(sRGB)

不允许

在PLTE之后IDAT之前如

果有sRGB,则无iCCP

背景颜色数据块(bKGD)

不允许

在PLTE之后IDAT之前

图像直方图数据块(hIST)

不允许

在PLTE之后IDAT之前

图像透明数据块(tRNS)

不允许

在PLTE之后IDAT之前

物理像素尺寸数据块(pHYs)

不允许

在IDAT之前

建议调色板(sPLT)

允许

在IDAT之前

图像最后修改时间数据块(tIME)

不允许

无限制

国际文本数据(iTXt)

允许

无限制

文本信息数据块(tEXt)

允许

无限制

压缩文本数据块(zTXt)

允许

无限制

PNG中每个数据块的格式由4个部分组成:

名称

字节数 

说明

Length (长度)

4字节

指定数据块中数据域的长度,其长度不超过(231-1)字节

Chunk Type Code (数据块类型码)

4字节

数据块类型码由ASCII字母(A-Z和a-z)组成 

Chunk Data (数据块数据) 

可变长度

存储按照Chunk Type Code指定的数据

CRC (循环冗余检测)

4字节

存储用来检测是否有错误的循环冗余码

CRC(cyclic redundancy check)域中的值是对Chunk Type Code域和Chunk Data域中的数据进行计算得到的。CRC具体算法定义在ISO 3309和ITU-T V.42中,其值按下面的CRC码生成多项式进行计算:

x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1

下面,我们依次来了解一下各个关键数据块的结构吧。

IHDR

文件头数据块IHDR(header chunk):它包含有PNG文件中存储的图像数据的基本信息,并要作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块。

文件头数据块由13 + 12(长度信息、数据类型码、循环检测)字节组成,它的格式如下表所示。


域的名称

字节数 

说明

Width

4 bytes

图像宽度,以像素为单位

Height

4 bytes

图像高度,以像素为单位

Bit depth

1 byte 

图像深度: 
索引彩色图像:1,2,4或8 
灰度图像:1,2,4,8或16 
真彩色图像:8或16

ColorType

1 byte 

颜色类型:
0:灰度图像, 1,2,4,8或16 
2:真彩色图像,8或16 
3:索引彩色图像,1,2,4或8 
4:带α通道数据的灰度图像,8或16 
6:带α通道数据的真彩色图像,8或16

Compression method

1 byte 

压缩方法(LZ77派生算法)

Filter method

1 byte 

滤波器方法

Interlace method 

1 byte 

隔行扫描方法:
0:非隔行扫描 
1: Adam7(由Adam M. Costello开发的7遍隔行扫描方法)


PLTE

调色板数据块PLTE(palette chunk)包含有与索引彩色图像(indexed-color image)相关的彩色变换数据,它仅与索引彩色图像有关,而且要放在图像数据块(image data chunk)之前。

PLTE数据块是定义图像的调色板信息,PLTE可以包含1~256个调色板信息,每一个调色板信息由3个字节组成:


字段名

大小(单

位:字节)

描 述

btRed

1

红色颜色值

btGreen

1

绿色颜色值

btBlue

1

蓝色颜色值


因此,调色板的长度应该是3的倍数,否则,这将是一个非法的调色板。

对于索引图像,调色板信息是必须的,调色板的颜色索引从0开始编号,然后是1、2……,调色板的颜色数不能超过色深中规定的颜色数(如图像色深为4的时候,调色板中的颜色数不可以超过2^4=16),否则,这将导致PNG图像不合法。

真彩色图像和带α通道数据的真彩色图像也可以有调色板数据块,目的是便于非真彩色显示程序用它来量化图像数据,从而显示该图像。

IDAT

图像数据块IDAT(image data chunk):它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。

IDAT存放着图像真正的数据信息,因此,如果能够了解IDAT的结构,我们就可以很方便的生成PNG图像。


图像数据块中的图像数据可能是经过变种的LZ77压缩编码DEFLATE压缩的,关于DEFLATE详细介绍可以参考《DEFLATE Compressed Data Format Specification version 1.3》,网址: http://www.ietf.org/rfc/rfc1951.txt 。

IEND

图像结束数据IEND(image trailer chunk):它用来标记PNG文件或者数据流已经结束,并且必须要放在文件的尾部。

如果我们仔细观察PNG文件,我们会发现,文件的结尾12个字符看起来总应该是这样的:

00 00 00 00 49 45 4E 44 AE 42 60 82

不难明白,由于数据块结构的定义,IEND数据块的长度总是0(00 00 00 00,除非人为加入信息),数据标识总是IEND(49 45 4E 44),因此,CRC码也总是AE 42 60 82。


PNG的辅助数据块(ancillary chunks)一共有14个,可以分为5类,上面已有,由于时间关系不能将全部辅助数据块(ancillary chunks)的详细结构进行说明,如果读者有兴趣请参考 http://www.w3.org/TR/REC-png.html。



使用libpng的编程方法:

1.判断文件是否为png文件。

2.初始化libpng数据结

png_info  png_structp png_ptr;

png_infop  info_ptr;

3.设置错误的返回点。

4.设置数据源

5.读取png数据

6.对数据进行处理。

7.释放libpng内存。

下面为一段测试代码:png_to_bmp bmp_to_png

#include

#include

#include

#include

#include


typedef unsigned char  BYTE;

typedef unsigned short WORD;

typedef unsigned long  DWORD;


#pragma pack(1)

typedef struct tagBITMAPFILEHEADER{

    WORD    bfType;                // the flag of bmp, value is "BM"

    DWORD    bfSize;                // size BMP file ,unit is bytes

    DWORD    bfReserved;            // 0

    DWORD    bfOffBits;            // must be 54


}BITMAPFILEHEADER;


typedef struct tagBITMAPINFOHEADER{

    DWORD    biSize;                // must be 0x28

    DWORD    biWidth;          //

    DWORD    biHeight;          //

    WORD            biPlanes;          // must be 1

    WORD            biBitCount;            //

    DWORD    biCompression;        //

    DWORD    biSizeImage;      //

    DWORD    biXPelsPerMeter;  //

    DWORD    biYPelsPerMeter;  //

    DWORD    biClrUsed;            //

    DWORD    biClrImportant;        //

}BITMAPINFOHEADER;

#pragma pack(4)

/******************************图片数据*********************************/

typedef struct _pic_data pic_data;

struct _pic_data

{

int width, height; /* 尺寸 */

int bit_depth;  /* 位深 */

int flag;  /* 一个标志,表示是否有alpha通道 */

unsigned char *rgba; /* 图片数组 */

};

/**********************************************************************/

/*

    写入bmp数据为头

    fp:文件指针

    width:图像的宽度

    height:图像的高度

*/

int write_bmp_header(FILE *fp,int width, int height)

{

    BITMAPFILEHEADER  bf;

  BITMAPINFOHEADER  bi;

  

    //Set BITMAPINFOHEADER

    bi.biSize = 40;

    bi.biWidth = width;

    bi.biHeight = height;

    bi.biPlanes = 1;

    bi.biBitCount = 24;

    bi.biCompression = 0;

    bi.biSizeImage = height*width*3;

    bi.biXPelsPerMeter = 0;

    bi.biYPelsPerMeter = 0;

    bi.biClrUsed = 0;

    bi.biClrImportant = 0;


//Set BITMAPFILEHEADER

  bf.bfType = 0x4d42;

  bf.bfSize = 54 + bi.biSizeImage;    

    bf.bfReserved = 0;

  bf.bfOffBits = 54;

  fwrite(&bf, 14, 1, fp); //先写54字节的头部数据

  fwrite(&bi, 40, 1, fp); 

  

    return 0;

}

/*

    将rgb数组数据写入bmp文件中

    filename:bmp文件名

    out:存在rgb数据的数组 格式为bgr bgr ...

*/

int write_bmp(const char *filename, pic_data *out)

{

    FILE *fp;

    int width, height;

    int i, j, count=0, linesize=0;

    unsigned char  * lineData = NULL;

        

    width = out->width;

    height = out->height;

    linesize = width*3;

    count = height /2;

    

    if((fp = fopen(filename, "wb+")) == NULL){

        perror("fopen bmp error");

        return -1;

    }

    //write_bmp_header(fp, width, height);

    

  lineData = (unsigned char*)malloc(linesize); 

  if(lineData == NULL){

      perror("malloc lineData error");

      return -1;

  }

        

    for(i=0; i<count; i++){    

      memcpy(lineData, out->rgba + (i*linesize), linesize);

      memcpy(out->rgba + (i*linesize), out->rgba+ (height - i -1)*linesize, linesize); 

      memcpy(out->rgba+ (height - i -1)*linesize, lineData, linesize);  

  }  

  fwrite(out->rgba, width*height*3, 1, fp); //图片旋转

    free(lineData);

  fclose(fp);  

    return 0;

}

#define PNG_BYTES_TO_CHECK 4

#define HAVE_ALPHA 1

#define NO_ALPHA 0

int check_if_png(char *file_name, FILE **fp)

{

  unsigned char buf[PNG_BYTES_TO_CHECK];


  /* Open the prospective PNG file. */

  if ((*fp = fopen(file_name, "rb")) == NULL)

      return 0;


  /* Read in some of the signature bytes */

  if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK)

      return 0;


  /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature.

      Return nonzero (true) if they match */

    printf("buf0 =%x buf1=%x buf2=%x buf3=%xn",buf[0], buf[1], buf[2], buf[3]);

  return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK)); //0错误 非0正确

}


/*

    获取png的数据

    filepath:文件名

    out:存放数据的rgb数组,格式bgr bgr ...

*/

int detect_png(char *filepath, pic_data *out)

/* 用于解码png图片 */

{

FILE *pic_fp;

int ret = -1;

/* 初始化各种结构 */

png_structp png_ptr;

png_infop  info_ptr;


  /*检测是否为png文件*/

  

if((ret = check_if_png(filepath,&pic_fp)) ==0)

{

        printf("not png file");

        return -1;

}


png_ptr  = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);

info_ptr = png_create_info_struct(png_ptr);


setjmp(png_jmpbuf(png_ptr)); // 这句很重要


rewind(pic_fp);

/*开始读文件*/

png_init_io(png_ptr, pic_fp); //文件指针赋值 

//png_ptr->io_ptr = (png_voidp)fp;

// png_voidp io_ptr;          /* ptr to application struct for I/O functions */ 

// 读文件了

png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND, 0);

//#define PNG_TRANSFORM_EXPAND        0x0010    /* read only */


int color_type,channels; //typedef unsigned char png_byte;


/*获取宽度,高度,位深,颜色类型*/

channels      = png_get_channels(png_ptr, info_ptr); /*获取通道数*/

out->bit_depth = png_get_bit_depth(png_ptr, info_ptr); /* 获取位深 */

color_type    = png_get_color_type(png_ptr, info_ptr); /*颜色类型*/


int i,j;

int size, pos = 0;

int temp;

/* row_pointers里边就是rgba数据 */

png_bytep* row_pointers; //二级指针

row_pointers = png_get_rows(png_ptr, info_ptr); //获取二维数组的数据

out->width = png_get_image_width(png_ptr, info_ptr);

out->height = png_get_image_height(png_ptr, info_ptr);


printf("channels=%d depth=%d color_type=%d width=%d height=%dn",channels, out->bit_depth,color_type,out->width,out->height);

size = out->width * out->height; /* 计算图片的总像素点数量 */


if(channels == 4 || color_type == PNG_COLOR_TYPE_RGB_ALPHA) //6

{/*如果是RGB+alpha通道,或者RGB+其它字节*/ 

  size *= (3*sizeof(unsigned char)); /* 每个像素点占4个字节内存 */

  out->flag = HAVE_ALPHA;    /* 标记 */

  out->rgba = (unsigned char*) malloc(size);

  if(out->rgba == NULL)

  {/* 如果分配内存失败 */

  fclose(pic_fp);

  puts("错误(png):无法分配足够的内存供存储数据!");

  return 1;

  }


  temp = (4 * out->width);/* 每行有4 * out->width个字节 */

  for(i = 0; i < out->height; i++)

  {

  for(j = 0; j < temp; j += 4)

  {/* 一个字节一个字节的赋值 */

  // out->rgba[0][pos] = row_pointers[i][j]; // red

  // out->rgba[1][pos] = row_pointers[i][j+1]; // green

  // out->rgba[2][pos] = row_pointers[i][j+2];  // blue

  //  out->rgba[3][pos] = row_pointers[i][j+3]; // alpha

  //  ++pos;

      //out->rgba[pos++] = row_pointers[i][j+3]; 忽略

      //pos++;

      char ch = row_pointers[i][j+3];

      out->rgba[pos++] = row_pointers[i][j+2];

      out->rgba[pos++] = row_pointers[i][j+1];

    out->rgba[pos++] = row_pointers[i][j+0]; 

  }

  }

}

else if(channels == 3 || color_type == PNG_COLOR_TYPE_RGB)//2

{/* 如果是RGB通道 */

  size *= (3*sizeof(unsigned char)); /* 每个像素点占3个字节内存 */

  out->flag = NO_ALPHA;    /* 标记 */

  out->rgba = (unsigned char*) malloc(size);

  printf("mallocn");

  if(out->rgba == NULL)

  {/* 如果分配内存失败 */

  fclose(pic_fp);

  puts("错误(png):无法分配足够的内存供存储数据!");

  return 1;

  }


  temp = (3 * out->width);/* 每行有3 * out->width个字节 */

  for(i = 0; i < out->height; i++)

  {

  for(j = 0; j < temp; j += 3)

  {/* 一个字节一个字节的赋值 */

  // out->rgba[0][pos] = row_pointers[i][j]; // red

  //out->rgba[1][pos] = row_pointers[i][j+1]; // green

  // out->rgba[2][pos] = row_pointers[i][j+2];  // blue

  // ++pos;


      out->rgba[pos++] = row_pointers[i][j+2];

      out->rgba[pos++] = row_pointers[i][j+1];

    out->rgba[pos++] = row_pointers[i][j+0];  

  

  }

  }

}

else return 1;


/* 撤销数据占用的内存 */

png_destroy_read_struct(&png_ptr, &info_ptr, 0); 

//free(out->rgba);

return 0;

}


/*

    写入数据到png文件

    file_name:写入数据的文件名

    graph:数据的rgb数组 格式为bgr bgr排放

*/

int write_png_file(char *file_name , pic_data *graph)

/* 功能:将LCUI_Graph结构中的数据写入至png文件 */

{

int j, i, temp, pos;

png_byte color_type;


png_structp png_ptr;

png_infop info_ptr; 


png_bytep * row_pointers;

/* create file */

FILE *fp = fopen(file_name, "wb");

if (!fp)

{

  printf("[write_png_file] File %s could not be opened for writing", file_name);

  return -1;

}



/* initialize stuff */

png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);


if (!png_ptr)

{

  printf("[write_png_file] png_create_write_struct failed");

  return -1;

}

info_ptr = png_create_info_struct(png_ptr);

if (!info_ptr)

{

  printf("[write_png_file] png_create_info_struct failed");

  return -1;

}

if (setjmp(png_jmpbuf(png_ptr)))

{

  printf("[write_png_file] Error during init_io");

  return -1;

}

png_init_io(png_ptr, fp);



/* write header */

if (setjmp(png_jmpbuf(png_ptr)))

{

  printf("[write_png_file] Error during writing header");

  return -1;

}

/* 判断要写入至文件的图片数据是否有透明度,来选择色彩类型 */

if(graph->flag == HAVE_ALPHA) color_type = PNG_COLOR_TYPE_RGB_ALPHA;

else color_type = PNG_COLOR_TYPE_RGB;


png_set_IHDR(png_ptr, info_ptr, graph->width, graph->height,

  graph->bit_depth, color_type, PNG_INTERLACE_NONE,

  PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);


png_write_info(png_ptr, info_ptr);



/* write bytes */

if (setjmp(png_jmpbuf(png_ptr)))

{

  printf("[write_png_file] Error during writing bytes");

  return -1;

}

if(graph->flag == HAVE_ALPHA) temp = (4 * graph->width);

else temp = (3 * graph->width);


pos = 0;

row_pointers = (png_bytep*)malloc(graph->height*sizeof(png_bytep));

for(i = 0; i < graph->height; i++)

{

  row_pointers[i] = (png_bytep)malloc(sizeof(unsigned char)*temp);

  for(j = 0; j < temp; j += 3)

  {

  // row_pointers[i][j]  = graph->rgba[0][pos]; // red

  // row_pointers[i][j+1] = graph->rgba[1][pos]; // green

  // row_pointers[i][j+2] = graph->rgba[2][pos];  // blue

      row_pointers[i][j+2] = graph->rgba[pos++];

      row_pointers[i][j+1] = graph->rgba[pos++];

      row_pointers[i][j+0] = graph->rgba[pos++];

  //if(graph->flag == HAVE_ALPHA) 

  // row_pointers[i][j+3] = graph->rgba[3][pos]; // alpha

  //++pos;

  }

}

png_write_image(png_ptr, row_pointers);


/* end write */

if (setjmp(png_jmpbuf(png_ptr)))

{

  printf("[write_png_file] Error during end of write");

  return -1;

}

png_write_end(png_ptr, NULL);


    /* cleanup heap allocation */

for (j=0; j

  free(row_pointers[j]);

free(row_pointers);


    fclose(fp);

    return 0;

}


int main(int argc, char *argv[]) //规则图片效果较好

{

    if(argc == 3){ //将png图片转化成bmp图片,argv[1]为png文件名 argv[2]为bmp文件名。

        pic_data out;

        detect_png(argv[1], &out);

        write_bmp(argv[2], &out);       

        free(out.rgba);

    }

    return 0;

}




本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭