最近在做身份证读头读取数据,但疼的第三方只给了个so库,说可以读出RGB数据。
RGB转BMP格式:
身份证头像照片宽和高分别为102、126,所以RGB数据的大小为102 x 126 x 3个字节
要转为BMP格式,必须加上54字节的BMP头格式,然后每一行RGB数据最后加上2个0表示一行结束,所以转换出来的BMP图片大小是:102 x 126 x 3 + 54 + 126 x 3字节
函数如下:
int rgb2bmp(char *rgb_buffer,int nWidth,int nHeight,FILE*fp1)
{
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef struct
{ long imageSize;
long blank;
long startPosition;
}BmpHead;
typedef struct
{
long Length;
long width;
long height;
WORD colorPlane;
WORD bitColor;
long zipFormat;
long realSize;
long xPels;
long yPels;
long colorUse;
long colorImportant;
}InfoHead;
BmpHead m_BMPHeader;
char bfType[2]={'B','M'};
m_BMPHeader.imageSize=3*nWidth*nHeight+54;
m_BMPHeader.blank=0;
m_BMPHeader.startPosition=54;
fwrite(bfType,1,sizeof(bfType),fp1);
fwrite(&m_BMPHeader.imageSize,1,sizeof(m_BMPHeader.imageSize),fp1);
fwrite(&m_BMPHeader.blank,1,sizeof(m_BMPHeader.blank),fp1);
fwrite(&m_BMPHeader.startPosition,1,sizeof(m_BMPHeader.startPosition),fp1);
InfoHead m_BMPInfoHeader;
m_BMPInfoHeader.Length=40;
m_BMPInfoHeader.width=nWidth;
m_BMPInfoHeader.height=nHeight;
m_BMPInfoHeader.colorPlane=1;
m_BMPInfoHeader.bitColor=24;
m_BMPInfoHeader.zipFormat=0;
m_BMPInfoHeader.realSize=3*nWidth*nHeight;
//m_BMPInfoHeader.realSize=0;
m_BMPInfoHeader.xPels=0;
m_BMPInfoHeader.yPels=0;
m_BMPInfoHeader.colorUse=0;
m_BMPInfoHeader.colorImportant=0;
fwrite(&m_BMPInfoHeader.Length,1,sizeof(m_BMPInfoHeader.Length),fp1);
fwrite(&m_BMPInfoHeader.width,1,sizeof(m_BMPInfoHeader.width),fp1);
fwrite(&m_BMPInfoHeader.height,1,sizeof(m_BMPInfoHeader.height),fp1);
fwrite(&m_BMPInfoHeader.colorPlane,1,sizeof(m_BMPInfoHeader.colorPlane),fp1);
fwrite(&m_BMPInfoHeader.bitColor,1,sizeof(m_BMPInfoHeader.bitColor),fp1);
fwrite(&m_BMPInfoHeader.zipFormat,1,sizeof(m_BMPInfoHeader.zipFormat),fp1);
fwrite(&m_BMPInfoHeader.realSize,1,sizeof(m_BMPInfoHeader.realSize),fp1);
fwrite(&m_BMPInfoHeader.xPels,1,sizeof(m_BMPInfoHeader.xPels),fp1);
fwrite(&m_BMPInfoHeader.yPels,1,sizeof(m_BMPInfoHeader.yPels),fp1);
fwrite(&m_BMPInfoHeader.colorUse,1,sizeof(m_BMPInfoHeader.colorUse),fp1);
fwrite(&m_BMPInfoHeader.colorImportant,1,sizeof(m_BMPInfoHeader.colorImportant),fp1);
fwrite(rgb_buffer,BMP_BODY,1,fp1);
return 0;
}
刚开始的时候转换出来的数据老是不对,后来经过对比,发现原始数据的排列并不是RGB,而是BGR,对调过来后即可,
RGB转jpeg:
我是在android系统下调试,android代码external/jpeg目录下自带jpeg编解码库,在Android.mk的LOCAL_SHARED_LIBRARIES加入libjpeg链接;
由于用到jpeg的头文件,还要在Android.mk中加入:
LOCAL_C_INCLUDES := \
external/jpeg
以下代码是两个编码函数,我用的是第一个。第二个是从jpeg代码库中的demo代码复制过来的,结果得到的图片是倒过来的;后来修改了第一个,从最后一行RGB开始压缩,得到了我想要的数据:
#include
#include
#include
#include
extern "C" {
#include "jpeglib.h"
#include "jerror.h"
}
#define IMGWIDTH 102
#define IMGHEIGHT 126
void rgb_to_jpeg (char *filename, unsigned char *img, int quality, int gray)
{
struct jpeg_compress_struct jcoms;
struct jpeg_error_mgr jerr; /* More stuff */
FILE *fp; /* target file */
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
int line_length, m; /* physical row width in image buffer */
unsigned char *line;
jcoms.err = jpeg_std_error(&jerr);
jpeg_create_compress(&jcoms);
if ((fp = fopen(filename, "w")) == NULL)
{
}
jpeg_stdio_dest(&jcoms, fp);
jcoms.image_width = IMGWIDTH;
jcoms.image_height = IMGHEIGHT;
jcoms.input_components = gray ? 1 : 3;
//3 colour
jcoms.in_color_space = gray ? \
JCS_GRAYSCALE : JCS_RGB;
/*colorspace*/
jpeg_set_defaults(&jcoms);
jpeg_set_quality(&jcoms, quality, TRUE);
/* limit to baseline-JPEG values */
jpeg_start_compress(&jcoms, TRUE);
line_length = gray ? IMGWIDTH : IMGWIDTH * 3;
/* JSAMPLEs per row in image_buffer */
#if 0
for (m = 0, line = img; m < IMGHEIGHT; \
m++, line +=line_length)
#endif
for (m = IMGHEIGHT, line = &img[line_length * (IMGHEIGHT - 1) - 1]; m > 0; \
m--, line -=line_length)
jpeg_write_scanlines(&jcoms, &line, 1);
/* Step 6: Finish compression */
jpeg_finish_compress(&jcoms);
/* to read the jpg data to the image buffer*/
/* After finish_compress, we can close the output file. */
fclose(fp);
jpeg_destroy_compress(&jcoms);
ALOGE("destroy compress OK!\n");
//return statbuf.st_size;
/* And we're done! */
}
void
write_JPEG_file (char * filename, unsigned char *image_buffer, int image_width, int image_height, int quality)
{
/* This struct contains the JPEG compression parameters and pointers to
* working space (which is allocated as needed by the JPEG library).
* It is possible to have several such structures, representing multiple
* compression/decompression processes, in existence at once. We refer
* to any one struct (and its associated working data) as a "JPEG object".
*/
struct jpeg_compress_struct cinfo;
/* This struct represents a JPEG error handler. It is declared separately
* because applications often want to supply a specialized error handler
* (see the second half of this file for an example). But here we just
* take the easy way out and use the standard error handler, which will
* print a message on stderr and call exit() if compression fails.
* Note that this struct must live as long as the main JPEG parameter
* struct, to avoid dangling-pointer problems.
*/
struct jpeg_error_mgr jerr;
/* More stuff */
FILE * outfile; /* target file */
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
int row_stride; /* physical row width in image buffer */
/* Step 1: allocate and initialize JPEG compression object */
/* We have to set up the error handler first, in case the initialization
* step fails. (Unlikely, but it could happen if you are out of memory.)
* This routine fills in the contents of struct jerr, and returns jerr's
* address which we place into the link field in cinfo.
*/
cinfo.err = jpeg_std_error(&jerr);
/* Now we can initialize the JPEG compression object. */
jpeg_create_compress(&cinfo);
/* Step 2: specify data destination (eg, a file) */
/* Note: steps 2 and 3 can be done in either order. */
/* Here we use the library-supplied code to send compressed data to a
* stdio stream. You can also write your own code to do something else.
* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
* requires it in order to write binary files.
*/
if ((outfile = fopen(filename, "wb")) == NULL) {
fprintf(stderr, "can't open %s\n", filename);
exit(1);
}
jpeg_stdio_dest(&cinfo, outfile);
/* Step 3: set parameters for compression */
/* First we supply a description of the input image.
* Four fields of the cinfo struct must be filled in:
*/
cinfo.image_width = image_width; /* image width and height, in pixels */
cinfo.image_height = image_height;
cinfo.input_components = 3; /* # of color components per pixel */
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
/* Now use the library's routine to set default compression parameters.
* (You must set at least cinfo.in_color_space before calling this,
* since the defaults depend on the source color space.)
*/
jpeg_set_defaults(&cinfo);
/* Now you can set any non-default parameters you wish to.
* Here we just illustrate the use of quality (quantization table) scaling:
*/
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
/* Step 4: Start compressor */
/* TRUE ensures that we will write a complete interchange-JPEG file.
* Pass TRUE unless you are very sure of what you're doing.
*/
jpeg_start_compress(&cinfo, TRUE);
/* Step 5: while (scan lines remain to be written) */
/* jpeg_write_scanlines(...); */
/* Here we use the library's state variable cinfo.next_scanline as the
* loop counter, so that we don't have to keep track ourselves.
* To keep things simple, we pass one scanline per call; you can pass
* more if you wish, though.
*/
row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */
while (cinfo.next_scanline < cinfo.image_height) {
/* jpeg_write_scanlines expects an array of pointers to scanlines.
* Here the array is only one element long, but you could pass
* more than one scanline at a time if that's more convenient.
*/
row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
/* Step 6: Finish compression */
jpeg_finish_compress(&cinfo);
/* After finish_compress, we can close the output file. */
fclose(outfile);
/* Step 7: release JPEG compression object */
/* This is an important step since it will release a good deal of memory. */
jpeg_destroy_compress(&cinfo);
/* And we're done! */
}