JPEG格式传输以(段标记SOI)0xFF 0xD8开始,(段标记EOI)0xFF 0xD9结束
解析JPEG格式数据驱动文件:
jpeg_driver.h
#ifndef _jpeg_driver_H_
#define _jpeg_driver_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"typedef enum
{eJPEG_Segment_Error = -1,//错误值,标记用,不是类型码eJPEG_Segment_SOI = 0xD8,//文件头eJPEG_Segment_EOI = 0xD9,//文件尾eJPEG_Segment_SOF0 = 0xC0,//帧开始(标准JPEG)eJPEG_Segment_SOF1 = 0xC1,//同上eJPEG_Segment_DHT = 0xC4,//定义Huffman表eJPEG_Segment_SOS = 0xDA,//扫描行开始eJPEG_Segment_DQT = 0xDB,//定义量化表eJPEG_Segment_DRI = 0xDD,//定义重新开始间隔eJPEG_Segment_APP0 = 0xE0,//定义开始交换格式和图像识别信息eJPEG_Segment_COM = 0xFE,//注释eJPEG_Segment_DNL = 0xDC//定义扫描行数
}JPEG_SegmentCode_EnumDef;//JPEG数据段类型码值extern JPEG_SegmentCode_EnumDef jpeg_SegmentDetection_driver(uint8_t format,uint8_t code);
extern int jpeg_SegmentAnalysis_driver(uint8_t *data,long int len);
extern int jpeg_FileSave(char *name,uint8_t *data,long int len);
extern uint8_t *jpeg_FileRead(char *name,long int *len);
extern int jpeg_ImageExtraction(uint8_t *data,long int len);#ifdef __cplusplus
}
#endif
#endif
jpeg_driver.c
/**********************************************************************
*file:JPEG格式数据解析
*author:残梦
*versions:V1.0
*date:2024.05.23
*note:参考文档 jpeg图片格式详解:https://blog.csdn.net/yun_hen/article/details/78135122
**********************************************************************/
#include "jpeg_driver.h"
#include "stdio.h"
#include "stdlib.h"#define dMerge_u16(MSB,LSB) ((((uint16_t)MSB)<<8) | ((uint16_t)LSB))//合并两个字节为uint16_t类型/****************************************************
@function:jpeg格式检查
@param:format--JPEG段格式码;code--JPEG段类型码
@return:参看JPEG_SegmentCode_EnumDef
@note:
****************************************************/
JPEG_SegmentCode_EnumDef jpeg_SegmentDetection_driver(uint8_t format,uint8_t code)
{if(format != 0xFF)return eJPEG_Segment_Error;switch(code){case eJPEG_Segment_SOI:case eJPEG_Segment_EOI:case eJPEG_Segment_SOF0:case eJPEG_Segment_SOF1:case eJPEG_Segment_DHT:case eJPEG_Segment_SOS:case eJPEG_Segment_DQT:case eJPEG_Segment_DRI:case eJPEG_Segment_APP0:case eJPEG_Segment_COM:case eJPEG_Segment_DNL:return (JPEG_SegmentCode_EnumDef)code;default:return eJPEG_Segment_Error;}
}/****************************************************
@function:jpeg段格式信息解析
@param:data--数据区域,len--数据长度
@return:0--识别成功-1--段格式错误-2--段类型未识别-3--数据长度不足-4--数据解析出错误值
@note:
****************************************************/
int jpeg_SegmentAnalysis_driver(uint8_t *data,long int len)
{long int pos = 0,segment_len = 0,i = 0;uint8_t temp = 0;if(len < 2)return -3;if(data[pos++] != 0xFF)return -1;switch(data[pos++]){case eJPEG_Segment_SOI:{printf("\n\n/******************SOI*****************图片起始点/\n");}break;case eJPEG_Segment_EOI:{printf("\n\n/******************EOI*****************图片起始点/\n");}break;case eJPEG_Segment_SOF0:{len -= 2;if(len < 2)return -3;segment_len = dMerge_u16(data[pos],data[pos+1]);len -= 2;pos += 2;printf("eSOF0[%d]\n",segment_len);if(len < segment_len)return -3;printf("样本精度:%d\n",data[pos++]);printf("图片尺寸[宽度*高度]:[%d*%d]\n",dMerge_u16(data[pos],data[pos+1]),dMerge_u16(data[pos+2],data[pos+3]));pos += 4;temp = data[pos++];printf("组件数量:%d (1=灰度图,3=YCbCr/YIQ 彩色图,4=CMYK 彩色图)\n",temp);for(i = 0;i < temp;i++){printf("组件ID:%d (1=Y, 2=Cb, 3=Cr, 4=I, 5=Q)\n",data[pos++]);printf("采样系数[垂直,水平]:[%d,%d]\n",(data[pos]&0x0F),(data[pos]>>4));pos++;printf("量化表号:%d\n",data[pos++]);}}break;case eJPEG_Segment_SOF1:{printf("SOF1\n");}break;case eJPEG_Segment_DHT:{len -= 2;if(len < 2)return -3;segment_len = dMerge_u16(data[pos],data[pos+1]);len -= 2;pos += 2;printf("DHT[%d]\n",segment_len);if(len < segment_len)return -3;printf("HT[%d号]信息:%d (HT类型, 0=DC表,1=AC表)\n",data[pos]&0x0F,data[pos]>>4);pos++;}break;case eJPEG_Segment_SOS:{len -= 2;if(len < 2)return -3;segment_len = dMerge_u16(data[pos],data[pos+1]);len -= 2;pos += 2;printf("SOS[%d]\n",segment_len);if(len < segment_len)return -3;temp = data[pos++];if((temp < 1) || (temp > 4))return -4;printf("扫描行内组件数量:%d\n",temp);for(i = 0;i < temp;i++){printf("组件ID:%d\n",data[pos++]);printf("Huffman表号:AC=%d,DC=%d\n",data[pos]&0x0F,data[pos]>>4);pos++;}}break;case eJPEG_Segment_DQT:{len -= 2;if(len < 2)return -3;segment_len = dMerge_u16(data[pos],data[pos+1]);len -= 2;pos += 2;printf("DQT[%d]\n",segment_len);if(len < segment_len)return -3;printf("QT号:%d,精度:%d\n",(data[pos]&0x0F),((((data[pos]&0xF0)>>4) == 0)?8:0));pos++;//0-3位是QT号,4-7位QT精度,此处是0,所以精度是8bit,即1个字节printf("QT量化表:");for(;pos < (segment_len-3);pos++)printf("%02X ",data[pos]);printf("\n");}break;case eJPEG_Segment_DRI:{printf("DRI\n");}break;case eJPEG_Segment_APP0:{len -= 2;if(len < 2)return -3;segment_len = dMerge_u16(data[pos],data[pos+1]);len -= 2;pos += 2;printf("APP0[%d]\n",segment_len);if(len < segment_len)return -3;if((data[pos+0] == 0x4A) \&& (data[pos+1] == 0x46)\&& (data[pos+2] == 0x49)\&& (data[pos+3] == 0x46)\&& (data[pos+4] == 0x00)){printf("交换格式:JFIF\n");}else{printf("交换格式:未识别\n");return -1;}pos += 5;printf("版本:%d.%d\n",data[pos],data[pos+1]);pos += 2;printf("密度单位:%d\n",data[pos++]);printf("像素密度:[X,Y]:[%d,%d]\n",dMerge_u16(data[pos],data[pos+1]),dMerge_u16(data[pos+2],data[pos+3]));pos += 4;printf("缩略图密度:[X,Y]:[%d,%d]\n",data[pos],data[pos+1]);pos += 2;}break;case eJPEG_Segment_COM:{printf("COM\n");}break;case eJPEG_Segment_DNL:{printf("DNL\n");}break;default:return -2;}return 0;
}/****************************************************
@function:将数据保存至文件
@param:name:文件名,需含文件后缀data--数据区域len--数据长度
@return:0--成功-1-参数异常-2--文件创建失败
@note:
****************************************************/
int jpeg_FileSave(char *name,uint8_t *data,long int len)
{FILE *file = NULL;if((name == NULL) || (data == NULL) || (len == 0))return -1;if((file = fopen(name, "wb")) == NULL)return -2;fwrite(data,1,len,file);fclose(file);return 0;
}/****************************************************
@function:读取文件所有数据
@param:name:文件名,需含文件后缀len--数据长度
@return:数据地址,使用完毕后需要使用free释放该内存NULL--失败
@note:
****************************************************/
uint8_t *jpeg_FileRead(char *name,long int *len)
{FILE *file = NULL;uint8_t *data = NULL;if((name == NULL) || (len == NULL))return NULL;if((file = fopen(name, "rb")) == NULL)return NULL;fseek(file, 0, SEEK_END);*len = ftell(file);fseek(file, 0, 0);data = (unsigned char*)malloc(*len);fread(data, 1, *len, file);fclose(file);return data;
}/****************************************************
@function:提取数据流中JPEG格式数据,并按顺序生成对应图像1.jpg,2.jpg,.....
@param:data--数据区域
@return:图像数量
@note:
****************************************************/
int jpeg_ImageExtraction(uint8_t *data,long int len)
{long int i = 0,pos = 0,num = 0;uint8_t flag = 0;char buf[20] = {0};//查找JPEG标识符for(i = 0;i < (len-1);i++){if(jpeg_SegmentDetection_driver(data[i],data[i+1]) == eJPEG_Segment_Error)continue;if(data[i+1] == eJPEG_Segment_SOI){pos = i;flag = 1;}else if(data[i+1] == eJPEG_Segment_EOI){if(flag == 1){sprintf(buf,"%d.jpg",num++);jpeg_FileSave(buf,&data[pos],(i+1 - pos + 1));}flag = 0;}}return num;
}
串口透传JPEG格式图像数据实例工程:
串口驱动文件:
uart_driver.c
/*********************************************
*file:labwindows CVI 串口UART驱动代码
*date:2023.06.25
*revision:V1.0
*author:残梦
*note:
eg:参见PanelUart0_UI.c文件,此文件做的是一个串口助手工具
*********************************************/
#include <windows.h>
#include <winreg.h>
#include <userint.h>
#include <utility.h>
#include "rs232.h"
#include "string.h"
#include "stdio.h"
#include "uart_driver.h"#define MAX_BUF_NUM (1024)//串口收发缓冲大小static int uart_GetComNum_driver(char strSerialList[256][25], int *comNum);/****************************************
@function:打开串口
@param:uart--串口结构体
@return:负值--失败,0--正常
@note:
1、首次使用需清零uart的值
****************************************/
int uart_open_driver(uart_driver_StructDef *uart)
{char ComLab[10] = {0};//1、获取串口状态if(uart_StatusGet_driver(uart) == 0)return -1;//2、参数检查if(uart->configuration.port < 0){return -2;}if(uart->configuration.BaudRate < 0){return -2;}if(uart->configuration.parity < 0){return -2;}if(uart->configuration.dataBits < 0){return -2;}if(uart->configuration.stopBits < 0){return -2;}//3、建立串口memset(ComLab, 0, sizeof(ComLab));sprintf(ComLab,"COM%d",uart->configuration.port);if (OpenComConfig(uart->configuration.port, ComLab, (long)(uart->configuration.BaudRate),\(int)(uart->configuration.parity), (int)(uart->configuration.dataBits), (int)(uart->configuration.stopBits),\MAX_BUF_NUM,MAX_BUF_NUM) < 0)goto ERROR_PROCESS;InstallComCallback (uart->configuration.port, LWRS_RXCHAR,0, 0, uart->configuration.Callback, NULL);//LWRS_RXCHAR;//LWRS_TXEMPTY LWRS_RXFLAG | LWRS_RECEIVESetCTSMode(uart->configuration.port,LWRS_HWHANDSHAKE_OFF); /* 禁止硬件握手,即不用RTS/CTS和DTR/DSR */FlushInQ(uart->configuration.port); //清空输入队列的缓存数据FlushOutQ(uart->configuration.port); //清空输出队列的缓存数据uart->private.status = 1;return 0;
ERROR_PROCESS:{uart->private.status = 0;return -3;}
}/****************************************
@function:关闭串口
@param:uart--串口结构体
@return:void
@note:
****************************************/
void uart_close_driver(uart_driver_StructDef *uart)
{if(uart->private.status){CloseCom(uart->configuration.port);}uart->private.status = 0;
}/****************************************
@function:获取串口状态
@param: Bits:见uart_StatusBit_EnumDef
@return:-1=串口无效,0=串口正在使用
@note:
****************************************/
int uart_StatusGet_driver(uart_driver_StructDef *uart)
{int state = 0;if(uart->private.status){state = GetComStat(uart->configuration.port);if((state < 0) || (state & 0x1080)){uart_close_driver(uart);uart->configuration.Abnormal_Callback();return -1;}return 0;}return -1;
}/****************************************
@function:扫描可用串口,并添加到对应的面板Ring控件中
@param:panelHandle--面板句柄portID--Ring控件类型的ID值
@return:void
@note:显示样式:COM0、COM1....
****************************************/
void uart_ScanPort_driver(int panelHandle,int portID)
{char strSerialList[256][25]; int comNum,i = 0,com = 0; ClearListCtrl(panelHandle,portID);if(uart_GetComNum_driver(strSerialList,&comNum) < 0){return;}for(i = 0;i < comNum;i++){sscanf(strSerialList[i],"COM%d",&com);InsertListItem(panelHandle,portID, 0, strSerialList[i], com);}
}/****************************************
@function:通过访问注册表获得串口号
@param:strSerialList--二维数组用来存放返回数组;
@return:-1--失败;0--成功
@note:
****************************************/
static int uart_GetComNum_driver(char strSerialList[256][25], int *comNum)
{char Name[25];int i = 0;unsigned char szPortName[25];long Status = 0.0;int dwIndex = 0;int dwName;int dwSizeofPortName;int Type;HKEY hKey; //返回注册表项的句柄if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\SERIALCOMM\\", 0, KEY_READ, &hKey) != ERROR_SUCCESS) //打开注册表return -1;dwName = sizeof(Name);dwSizeofPortName = sizeof(szPortName);while((Status == ERROR_SUCCESS)||(Status == ERROR_MORE_DATA)){Status = RegEnumValue(hKey, dwIndex++, Name, &dwName, NULL, &Type, szPortName, &dwSizeofPortName); //列举注册表的值if((Status == ERROR_SUCCESS)||(Status == ERROR_MORE_DATA)){strcpy(strSerialList[i], (const char*)szPortName); // 串口字符串保存//printf("%s %d\n",strSerialList[i],i);i++;}dwName = sizeof(Name); dwSizeofPortName = sizeof(szPortName); }*comNum = i;RegCloseKey(hKey); //关闭注册表return 0;
}/****************************************
@function:接收串口数据
@param: portNumber--端口号data--数据接收区BytesNumber--接收数据最大字节数,最大1025字节,退出函数时此值表示实际接收字节数
@return:-1--失败,0--成功
@note:data建议1025字节
****************************************/
int uart_DataReceive_driver(int portNumber,char *data,size_t *BytesNumber)
{size_t number = 0;if(data == NULL)return -1;number = GetInQLen(portNumber);*BytesNumber = (number > *BytesNumber)?*BytesNumber:number;*BytesNumber = (*BytesNumber > MAX_BUF_NUM)?MAX_BUF_NUM:*BytesNumber;if(ComRd(portNumber,data,*BytesNumber) < 0)return -1;//接收,GetInQLen用于得到Com口的输入队列数据缓存的大小data[*BytesNumber] = '\0';return 0;
}/****************************************
@function:中断函数中接收串口数据
@param: portNumber--端口号eventMask--中断事件码data--数据接收区,需大于BytesNumber一个字节BytesNumber--接收数据最大字节数,最大1025字节,退出函数时此值表示实际接收字节数
@return:-1--失败,0--成功
@note:data建议1025字节
****************************************/
int uart_DataReceive_IT_driver(int portNumber,int eventMask,char *data,size_t *BytesNumber)
{if (eventMask & LWRS_RXCHAR){return uart_DataReceive_driver(portNumber,data,BytesNumber);}return -1;
}/****************************************
@function:串口发送数据,按ASCII值发送
@param: uart--串口结构体data--数据区BytesNumber--字节数
@return:-1--失败,0--成功
@note:
****************************************/
int uart_DataTransmit_driver(uart_driver_StructDef *uart,char data[],size_t BytesNumber)
{if(uart_StatusGet_driver(uart) < 0)return -1;if(BytesNumber != ComWrt (uart->configuration.port, data, BytesNumber))return -1;return 0;
}/****************************************
@function:ASCII数据转化为hex格式
@param: DataASCII--ASCII数据区DataHex--转化为十六进制的数据区
@return:-1--失败,0--成功
@note:DataHex建议空间是DataASCII的三倍,函数中未检查空间大小
****************************************/
int uart_ASCII_ConvertHex_driver(char *DataASCII,char *DataHex)
{size_t LengthASCII = 0,i = 0,j = 0;if((DataASCII == NULL) || (DataHex == NULL))return -1;memset(DataHex,'\0',sizeof(DataHex));LengthASCII = strlen(DataASCII);for(i=0,j=0;(i < LengthASCII);i++){DataHex[j] = uart_Number_ConvertHexCharacter(DataASCII[i]>>4);j++;DataHex[j] = uart_Number_ConvertHexCharacter(DataASCII[i]&0x0F);j++;DataHex[j] = ' ';j++;}return 0;
}/****************************************
@function:hex数据转化为ASCII转格式
@param: DataHex--十六进制的数据区DataASCII--转化为ASCII数据区
@return:-1--失败,0--成功
@note:DataASCII空间等于DataHex空间即可,函数中未检查空间大小
格式:"02 03 ff 33"
****************************************/
int uart_Hex_ConvertASCII_driver(char* DataHex,char* DataASCII)
{size_t LengthHex = 0,i = 0,j = 0,k = 0;if((DataHex == NULL) || (DataHex == NULL))return -1;memset(DataASCII,'\0',sizeof(DataASCII));LengthHex = strlen(DataHex);for(i=0,j=0,k=0;i < LengthHex;i++){if(DataHex[i] == 0x20)continue; if(k == 0){DataASCII[j] = uart_HexCharacter_ConvertNumber(DataHex[i]);k++;}else{DataASCII[j] = DataASCII[j]*16 + uart_HexCharacter_ConvertNumber(DataHex[i]);j++;k=0;}}return 0;
}/****************************************
@function:十六进制字符对应的数字值
@param:hex:十六进制字符['0'-'f']
@return:对应数字0-15
@note:'1'=1,'a'=10
****************************************/
char uart_HexCharacter_ConvertNumber(char hex)
{if(hex >= '0' && hex <= '9')return (hex - '0');else if(hex >= 'a' && hex <= 'f')return (hex - 'a' + 10);return 0;
}/****************************************
@function:计算该值对应的十六进制字符
@param:数字0-15
@return:十六进制字符['0'-'f']
@note:'1'=1,'a'=10
****************************************/
char uart_Number_ConvertHexCharacter(char number)
{if(number >= 0 && number <= 9)return (number + '0');else if(number >= 10 && number < 16)return (number - 10 + 'a');return '0';
}/****************************************
@function:字符串按十六进制格式检查
@param: data--数据区
@return:-2--不通过,首位置不通过,-1--中间位置不通过,0--通过
@note:若检查不通过,会自动截取至不满足位置添加字符串结束标志
****************************************/
int uart_StringCheckHex_driver(char *data)
{size_t LengthData = 0,i = 0;if(data == NULL)return -1;LengthData = strlen(data);for(i=0;i < LengthData;i++){if(data[i] == 0x20){continue;}if(data[i] < '0' || data[i] > 'f'){data[i] = '\0';if(i == 0){return -2;}return -1;}}return 0;
}
uart_driver.h
#ifndef _uart_driver_H_
#define _uart_driver_H_
#ifdef __cplusplus
extern "C" {
#endiftypedef enum
{eParity_no = 0,eParity_odd,eParity_even,eParity_mark,eParity_space
}uart_parameter_parity_EnumDef;//校验位配置枚举typedef enum
{eDataBits_5 = 5,eDataBits_6,eDataBits_7,eDataBits_8,
}uart_parameter_DataBits_EnumDef;//数据位配置枚举typedef enum
{eStopBits_1 = 1,eStopBits_2
}uart_parameter_StopBits_EnumDef;//停止位配置枚举typedef struct
{int port;//串口端口号;范围(0,+∞)unsigned __int64 BaudRate;//波特率:Valid Values: 110, 150, 300, 600, 1,200, 2,400, 4,800, 9,600, 14,400, 19,200, 28,800, 38,400, 56,000, 57,600, 115,200, 128,000, and 256,000uart_parameter_parity_EnumDef parity; //校验位:见uart_parameter_parity_EnumDefuart_parameter_DataBits_EnumDef dataBits;//数据长度:见uart_parameter_DataBits_EnumDefuart_parameter_StopBits_EnumDef stopBits;//停止位:见uart_parameter_StopBits_EnumDefvoid (*Callback)(int,int,void*);//事件回调函数void (*Abnormal_Callback)(void);//异常回调函数,发生此事件时,串口会自动关闭
}uart_configuration_StructDef;//串口配置参数typedef struct
{char status;//初值=0;串口状态:0--空闲,1--使用中
}uart_private_StructDef;//内部使用变量;注:定义时必须赋初值typedef struct
{uart_configuration_StructDef configuration;uart_private_StructDef private;
}uart_driver_StructDef;//串口驱动结构体int uart_open_driver(uart_driver_StructDef *uart);
void uart_close_driver(uart_driver_StructDef *uart);
int uart_StatusGet_driver(uart_driver_StructDef *uart);
void uart_ScanPort_driver(int panelHandle,int portID);
int uart_DataReceive_driver(int portNumber,char *data,size_t *BytesNumber);
int uart_DataReceive_IT_driver(int portNumber,int eventMask,char *data,size_t *BytesNumber);
int uart_DataTransmit_driver(uart_driver_StructDef *uart,char data[],size_t BytesNumber);
int uart_ASCII_ConvertHex_driver(char *DataASCII,char *DataHex);
int uart_Hex_ConvertASCII_driver(char* DataHex,char* DataASCII);
char uart_HexCharacter_ConvertNumber(char hex);
char uart_Number_ConvertHexCharacter(char number);
int uart_StringCheckHex_driver(char *data);#ifdef __cplusplus
}
#endif
#endif
应用代码:
jpeg.h
#ifndef _jpeg_H_
#define _jpeg_H_
void jpeg_uart_init(void);
int jpeg();
#endif
jpeg.c
#include <ansi_c.h>
#include "jpeg_driver.h"
#include "uart_driver.h"extern void disply(char *name);
void uart_COM_Callback(int portNumber, int eventMask, void *callbackdata);
void uart_Abnormal_Callback(void);uart_driver_StructDef uart = \
{.private.status = 0,\.configuration.port = 3,\.configuration.BaudRate = 256000,\.configuration.parity = eParity_no,\.configuration.dataBits = eDataBits_8,\.configuration.stopBits = eStopBits_1,\.configuration.Callback = &uart_COM_Callback,\.configuration.Abnormal_Callback = &uart_Abnormal_Callback
};#define duart_size (1024*40)
uint8_t uart_buffer[duart_size] = {0};
long int uart_pos = 0,jpeg_start = 0;;
uint8_t uart_flag = 0;/****************************************************
@function:从设备0回调函数
@param:
@return:void
@note:
****************************************************/
void uart_COM_Callback(int portNumber, int eventMask, void *callbackdata)
{uint8_t data[1025] = {0};size_t BytesNumber = 1024,j = 0,z = 0;if(uart_DataReceive_IT_driver(uart.configuration.port, eventMask,data,&BytesNumber) < 0)return;if(BytesNumber == 0)return;for(j = 0;j < BytesNumber;j++){if(uart_pos >= duart_size)uart_pos = 0;uart_buffer[uart_pos++] = data[j];if(uart_pos < 2)continue;if(jpeg_SegmentDetection_driver(uart_buffer[uart_pos-2],uart_buffer[uart_pos-1]) == eJPEG_Segment_Error)continue;if(uart_buffer[uart_pos-1] == eJPEG_Segment_SOI){jpeg_start = uart_pos-2;uart_flag = 1;}else if(uart_buffer[uart_pos-1] == eJPEG_Segment_EOI){if(uart_flag == 1){//for(z = 0;z < (uart_pos-1 - jpeg_start + 1);z++)//{// printf("%02x ",uart_buffer[jpeg_start + z]);//}jpeg_FileSave("out.jpg",&uart_buffer[jpeg_start],(uart_pos-1 - jpeg_start + 1));disply("out.jpg");}uart_flag = 0;uart_pos = 0;}}
}/****************************************************
@function:从设备0异常回调函数
@param:
@return:void
@note:
****************************************************/
void uart_Abnormal_Callback(void)
{printf("%s\n",__func__);
}//串口解析jpeg格式数据
void jpeg_uart_init(void)
{if(uart_open_driver(&uart) < 0)return;
}//读取test.dat内的图像数据保存为照片+开启串口解析JPEG格式图像
int jpeg()
{jpeg_uart_init();return 0;long int len = 0;uint8_t *data = jpeg_FileRead("test.dat",&len);jpeg_ImageExtraction(data,len);free(data);return 0;
}
完整工程下载:
链接:https://pan.baidu.com/s/1OxSdYbS1G-PV4OPYAmjpjg
提取码:srvh
参考文档 jpeg图片格式详解:https://blog.csdn.net/yun_hen/article/details/78135122