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_RECEIVE
SetCTSMode(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" {
#endif
typedef 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,000
uart_parameter_parity_EnumDef parity; //校验位:见uart_parameter_parity_EnumDef
uart_parameter_DataBits_EnumDef dataBits;//数据长度:见uart_parameter_DataBits_EnumDef
uart_parameter_StopBits_EnumDef stopBits;//停止位:见uart_parameter_StopBits_EnumDef
void (*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