pineapple-music/FlacPic.h

263 lines
7.1 KiB
C
Raw Normal View History

/*
FLAC标签图片提取库 Ver 1.0
FLAC文件中稳定便
BMPJPEGPNGGIF图片格式
使ID3v2版本相同
ShadowPower 2014/8/1
*/
#ifndef _ShadowPower_FLACPIC___
#define _ShadowPower_FLACPIC___
#define _CRT_SECURE_NO_WARNINGS
#ifndef NULL
#define NULL 0
#endif
#include <cstdio>
#include <cstdlib>
#include <memory.h>
#include <cstring>
typedef unsigned char byte;
namespace spFLAC {
//Flac元数据块头部结构体定义
struct FlacMetadataBlockHeader
{
byte flag; //标志位高1位是否为最后一个数据块低7位数据块类型
byte length[3]; //数据块长度,不含数据块头部
};
byte *pPicData = 0; //指向图片数据的指针
int picLength = 0; //存放图片数据长度
char picFormat[4] = {}; //存放图片数据的格式(扩展名)
//检测图片格式参数1数据返回值是否成功不是图片则失败
bool verificationPictureFormat(char *data)
{
//支持格式JPEG/PNG/BMP/GIF
byte jpeg[2] = { 0xff, 0xd8 };
byte png[8] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
byte gif[6] = { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 };
byte gif2[6] = { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 };
byte bmp[2] = { 0x42, 0x4d };
memset(&picFormat, 0, 4);
if (memcmp(data, &jpeg, 2) == 0)
{
strcpy(picFormat, "jpg");
}
else if (memcmp(data, &png, 8) == 0)
{
strcpy(picFormat, "png");
}
else if (memcmp(data, &gif, 6) == 0 || memcmp(data, &gif2, 6) == 0)
{
strcpy(picFormat, "gif");
}
else if (memcmp(data, &bmp, 2) == 0)
{
strcpy(picFormat, "bmp");
}
else
{
return false;
}
return true;
}
//安全释放内存
void freePictureData()
{
if (pPicData)
{
delete pPicData;
}
pPicData = 0;
picLength = 0;
memset(&picFormat, 0, 4);
}
//将图片提取到内存参数1文件路径成功返回true
bool loadPictureData(const char *inFilePath)
{
freePictureData();
FILE *fp = NULL;
fp = fopen(inFilePath, "rb");
if (!fp) //如果打开失败
{
fp = NULL;
return false;
}
fseek(fp, 0, SEEK_SET); //设文件流指针到文件头部
byte magic[4] = {}; //存放校验数据
memset(&magic, 0, 4);
fread(&magic, 4, 1, fp); //读入校验数据
byte fLaC[4] = { 0x66, 0x4c, 0x61, 0x43 };
if (memcmp(&magic, &fLaC, 4) == 0)
{
//数据校验正确文件类型为Flac
FlacMetadataBlockHeader fmbh; //创建Flac元数据块头部结构体
memset(&fmbh, 0, 4); //清空内存
fread(&fmbh, 4, 1, fp); //读入头部数据
//计算数据块长度,不含头部
int blockLength = fmbh.length[0] * 0x10000 + fmbh.length[1] * 0x100 + fmbh.length[2];
int loopCount = 0; //循环计数,防死
while ((fmbh.flag & 0x7f) != 6)
{
//如果数据类型不是图片,此处循环执行
loopCount++;
if (loopCount > 40)
{
//循环40次没有遇到末尾就直接停止
fclose(fp);
fp = NULL;
return false; //可能文件不正常
}
fseek(fp, blockLength, SEEK_CUR); //跳过数据块
if ((fmbh.flag & 0x80) == 0x80)
{
//已经是最后一个数据块了,仍然不是图片
fclose(fp);
fp = NULL;
return false; //没有找到图片数据
}
//取得下一数据块头部
memset(&fmbh, 0, 4); //清空内存
fread(&fmbh, 4, 1, fp); //读入头部数据
blockLength = fmbh.length[0] * 0x10000 + fmbh.length[1] * 0x100 + fmbh.length[2];//计算数据块长度
}
//此时已到图片数据块
int nonPicDataLength = 0; //非图片数据长度
fseek(fp, 4, SEEK_CUR); //信仰之跃
nonPicDataLength += 4;
char nextJumpLength[4]; //下次要跳的长度
fread(&nextJumpLength, 4, 1, fp); //读取安全跳跃距离
nonPicDataLength += 4;
int jumpLength = nextJumpLength[0] * 0x1000000 + nextJumpLength[1] * 0x10000 + nextJumpLength[2] * 0x100 + nextJumpLength[3];//计算数据块长度
fseek(fp, jumpLength, SEEK_CUR); //Let's Jump!!
nonPicDataLength += jumpLength;
fread(&nextJumpLength, 4, 1, fp);
nonPicDataLength += 4;
jumpLength = nextJumpLength[0] * 0x1000000 + nextJumpLength[1] * 0x10000 + nextJumpLength[2] * 0x100 + nextJumpLength[3];
fseek(fp, jumpLength, SEEK_CUR); //Let's Jump too!!
nonPicDataLength += jumpLength;
fseek(fp, 20, SEEK_CUR); //信仰之跃
nonPicDataLength += 20;
//非主流情况检测+获得文件格式
char tempData[20] = {};
memset(tempData, 0, 20);
fread(&tempData, 8, 1, fp);
fseek(fp, -8, SEEK_CUR); //回到原位
//判断40次一位一位跳到文件头
bool ok = false; //是否正确识别出文件头
for (int i = 0; i < 40; i++)
{
//校验文件头
if (verificationPictureFormat(tempData))
{
ok = true;
break;
}
else
{
//如果校验失败尝试继续向后校验
fseek(fp, 1, SEEK_CUR);
nonPicDataLength++;
fread(&tempData, 8, 1, fp);
fseek(fp, -8, SEEK_CUR);
}
}
if (!ok)
{
fclose(fp);
fp = NULL;
freePictureData();
return false; //无法识别的数据
}
//-----抵达图片数据区-----
picLength = blockLength - nonPicDataLength; //计算图片数据长度
pPicData = new byte[picLength]; //动态分配图片数据内存空间
memset(pPicData, 0, picLength); //清空图片数据内存
fread(pPicData, picLength, 1, fp); //得到图片数据
//------------------------
fclose(fp); //操作已完成,关闭文件。
}
else
{
//校验失败不是Flac
fclose(fp);
fp = NULL;
freePictureData();
return false;
}
return true;
}
//取得图片数据的长度
int getPictureLength()
{
return picLength;
}
//取得指向图片数据的指针
byte *getPictureDataPtr()
{
return pPicData;
}
//取得图片数据的扩展名(指针)
char *getPictureFormat()
{
return picFormat;
}
bool writePictureDataToFile(const char *outFilePath)
{
FILE *fp = NULL;
if (picLength > 0)
{
fp = fopen(outFilePath, "wb"); //打开目标文件
if (fp) //打开成功
{
fwrite(pPicData, picLength, 1, fp); //写入文件
fclose(fp); //关闭
return true;
}
else
{
return false; //文件打开失败
}
}
else
{
return false; //没有图像数据
}
}
//提取图片文件参数1输入文件参数2输出文件返回值是否成功
bool extractPicture(const char *inFilePath, const char *outFilePath)
{
if (loadPictureData(inFilePath)) //如果取得图片数据成功
{
if (writePictureDataToFile(outFilePath))
{
return true; //文件写出成功
}
else
{
return false; //文件写出失败
}
}
else
{
return false; //无图片数据
}
freePictureData();
}
}
#endif