一种用于png图片处理的C/C++库lodepng的使用说明及踩坑记录

Posted 爱小羊

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一种用于png图片处理的C/C++库lodepng的使用说明及踩坑记录相关的知识,希望对你有一定的参考价值。

引言

前文说到,基于Alios系统的门禁只能处理JPG图片,由于历史遗留问题,服务器下发的人脸中有png格式的图片,开发人员需要将png图片进行解码处理成RGBA格式的图片,用于人脸识别,网上用的最多图片处理库为libjpg和libpng这些图片处理库过于复杂且移植后会扩大程序的大小,因此一款轻量级的png图片处理库的需求日益强烈。

lodepng介绍

LodePNG是一个集合了PNG图像解码器和编码器的代码文件,不依赖于诸如zlib和libpng的外部链接/库,提供方便友好的PNG编解码器调用方法。LodePNG主要是采用C(ISO C90)编写的,并提供了C++的接口。LodePNG的使用非常简单,只要在项目文件中包含lodepng.cpp和lodepng.h或者lodepng.c和lodepng.h就可以。

下载方式

1、登录官网http://lodev.org/lodepng/进行下载,并且官方给出的有例子便于学习。

2、登录github搜索lodepng,找到star最多的那一个就是,可以用git软件进行下载。

使用方法

在此给出自己写的一个例子供参考。应用时很简单,lodepng库提供的有直接读入文件的接口,lodepng_decode32_file() 这个接口可以直接将图片读入,并生成RGBA的格式图像,将其保存为RAW格式,可以使用imageJ软件进行查看。

#include <stdio.h>
#include "lodepng.h"

//#define filename "E:\\\\sun.png"

int main()
{
	FILE *fp;
	unsigned char *pBuffer;
	unsigned error;
	unsigned char * image;
    unsigned width, height;
	const char* filename =  "E:\\\\face\\\\2.png";
	const char* filename_new =  "E:\\\\png3.png";
	error =lodepng_decode32_file(&image, &width, &height, filename);
	//error =lodepng_decode24_file(&image, &width, &height, filename);//image内存的大小是多少
    if(error) printf("error %u: %s\\n", error, lodepng_error_text(error));

	printf("error is %d,,width is %d ,height is %d\\r\\n",error,width,height);
	//lodepng_encode24_file(filename_new, image, width, height);
	//fp = fopen("E:\\\\face\\\\19_32.raw","w");//生成raw图片是这样生成的吗
	fp = fopen("E:\\\\face\\\\2_1211.raw","wb");//生成raw图片是这样生成的吗  //一定要用wb打开二进制
	//fwrite(image, width*height*3 , 1, fp);
	fwrite(image, width*height*4 , 1, fp);
	//fwrite(image, width*height*4 , 1, fp);
	fclose(fp);

   free(image);

	
	return 0;
}

解码前图片

解码后图片

本人是在Alios系统下进行开发,在此系统下没有fopen等函数,需要根据alios的文档说明将fopen函数改为aos_open函数,对win下的lodepng库进行改写,经过验证可以在alios系统下使用。

static long lodepng_filesize(const char* filename) {
#ifdef WIN32  //Added by sun
  FILE* file;
  long size;
  file = fopen(filename, "rb");
  if(!file) return -1;

  if(fseek(file, 0, SEEK_END) != 0) {
    fclose(file);
    return -1;
  }

  size = ftell(file);
  /* It may give LONG_MAX as directory size, this is invalid for us. */
  if(size == LONG_MAX) size = -1;

  fclose(file);
#else
    int file = -1;
    int ret = -1;
    struct aos_stat file_st;
    long size;

    file = aos_open(filename, O_RDWR);
    if (file < 0) {
      return -1;
    }
  /*
    if(aos_lseek(file, 0, SEEK_END) != 0) {
    aos_close(file);
    return -1;
  }
  */
    ret = aos_stat(filename, &file_st);
    if (!ret) {
    size = file_st.st_size;
}
#endif
  return size;
}

踩坑记录

说到这里又让我感觉到了嵌入式的特点,太需要经验了,总体来看其实就是移植一个库,移植过来调用调用就行了,但还是出现了很多问题。比如解码一张这样的图片

结果却是这样,只能大概判断出是错位了,想了好久准备使用16进制文件读取软件,如Hex Editor Neo来读取。

经过读取终于发现了问题,正确的RGBA是这样的
但是转换出来的却是这样的,可以发现有明显的错位,当时我还没意识到错误在哪,技术领导看后说怎么多了换行符0d,0a,我这才发现问题。在网上进行搜索发现,fwrite实际写入文件的数据大小比参数指定的数值大一些字节,原因是:win下用文本方式读写文件,会在0A(换行)前加0D(回车)。发现自己用的fp = fopen(“E:\\face\\19_32.raw”,“w”);用的W参数进行打开的,w参数是以文本的方式打开,将w参数改为wb就可以了,一切都正常了,开始没有想到这个问题,我说为啥有的图片转换正常,有的不正常,原来是图片中出现0a的话会被添上0d,导致错误,如果图片中没有oa则正常。错误解决。

总结

通过这个任务学会了嵌入式系统中图片的处理,RGBA格式图片的buffer大小长4,png图片的大小不是,是因为png对图片进行了压缩,RGBA格式没有压缩。此外还学到了图片的位深,C语言IO函数,如fopen,fclose等知识以及如何申请内存等相关知识。此外任何一个任务都不能小看,比如这次任务看着简单,但是不做一遍根本不知道会产生什么问题。

以上是关于一种用于png图片处理的C/C++库lodepng的使用说明及踩坑记录的主要内容,如果未能解决你的问题,请参考以下文章

用于 C/C++ 的压缩库能够处理数组中超过 32 位的元素

如何在 C++ 中将图像从 .bmp 转换为 .png

PHP图片处理之图片背景画布操作

读取图片

C/C++ HTTP 库,只处理逻辑?

Android设计中的.9.png图片