#include <algorithm>
#include "QHExifInfo.h"
using std::string;
namespace {
// IF Entry
struct IFEntry {
// Raw fields
unsigned short tag;
unsigned short format;
unsigned data;
unsigned length;
// Parsed fields
string val_string;
unsigned short val_16;
unsigned val_32;
double val_rational;
unsigned char val_byte;
};
// Helper functions
unsigned int parse32(const unsigned char *buf, bool intel) {
if (intel)
return ((unsigned)buf[3]<<24) |
((unsigned)buf[2]<<16) |
((unsigned)buf[1]<<8) |
buf[0];
return ((unsigned)buf[0]<<24) |
((unsigned)buf[1]<<16) |
((unsigned)buf[2]<<8) |
buf[3];
}
unsigned short parse16(const unsigned char *buf, bool intel) {
if (intel)
return ((unsigned) buf[1]<<8) | buf[0];
return ((unsigned) buf[0]<<8) | buf[1];
}
string parseEXIFString(const unsigned char *buf,
unsigned num_components,
unsigned data,
unsigned base,
unsigned len) {
string value;
if (num_components <= 4)
value.assign( (const char*)&data, num_components );
else {
if (base+data+num_components <= len)
value.assign( (const char*)(buf+base+data), num_components );
}
return value;
}
double parseEXIFRational(const unsigned char *buf, bool intel) {
double numerator = 0;
double denominator = 1;
numerator = (double) parse32(buf, intel);
denominator= (double) parse32(buf+4, intel);
if(denominator < 1e-20)
return 0;
return numerator/denominator;
}
IFEntry parseIFEntry(const unsigned char *buf,
unsigned offs,
bool alignIntel,
unsigned base,
unsigned len) {
IFEntry result;
// Each directory entry is composed of:
// 2 bytes: tag number (data field)
// 2 bytes: data format
// 4 bytes: number of components
// 4 bytes: data value or offset to data value
result.tag = parse16(buf + offs, alignIntel);
result.format = parse16(buf + offs + 2, alignIntel);
result.length = parse32(buf + offs + 4, alignIntel);
result.data = parse32(buf + offs + 8, alignIntel);
// Parse value in specified format
switch (result.format) {
case 1:
result.val_byte = (unsigned char) *(buf + offs + 8);
break;
case 2:
result.val_string = parseEXIFString(buf, result.length, result.data, base, len);
break;
case 3:
result.val_16 = parse16((const unsigned char *) buf + offs + 8, alignIntel);
break;
case 4:
result.val_32 = result.data;
break;
case 5:
if (base + result.data + 8 <= len)
result.val_rational = parseEXIFRational(buf + base + result.data, alignIntel);
break;
case 7:
case 9:
case 10:
break;
default:
result.tag = 0xFF;
}
return result;
}
}
//
// Main parsing function
//
int QHExifInfo::parseFrom(const unsigned char *buf, unsigned len) {
bool alignIntel = true; // byte alignment (defined in EXIF header)
unsigned offs = 0; // current offset into buffer
if (!buf || len == 0)
return PARSE_EXIF_ERROR_NO_EXIF;
clear();
// Scan for EXIF header (bytes 0xFF 0xE1) and do a sanity check by
// looking for bytes "Exif\0\0". The marker length data is in Motorola
// byte order, which results in the 'false' parameter to parse16().
// The marker has to contain at least the TIFF header, otherwise the
// EXIF data is corrupt. So the minimum length specified here has to be:
// 2 bytes: section size
// 6 bytes: "Exif\0\0" string
// 2 bytes: TIFF header (either "II" or "MM" string)
// 2 bytes: TIFF magic (short 0x2a00 in Motorola byte order)
// 4 bytes: Offset to first IFD
// =========
// 16 bytes
// for (offs = 0; offs < len-1; offs++)
// if (buf[offs] == 0xFF && buf[offs+1] == 0xE1)
// break;
// if (offs + 4 > len)
// return PARSE_EXIF_ERROR_NO_EXIF;
// offs += 2;
unsigned short section_length = parse16(buf + offs, false);
if (offs + section_length > len || section_length < 16)
return PARSE_EXIF_ERROR_CORRUPT;
offs += 2;
if (!std::equal(buf+offs, buf+offs+6, "Exif\0\0"))
return PARSE_EXIF_ERROR_NO_EXIF;
offs += 6;
// Now parsing the TIFF header. The first two bytes are either "II" or
// "MM" for Intel or Motorola byte alignment. Sanity check by parsing
// the unsigned short that follows, making sure it equals 0x2a. The
// last 4 bytes are an offset into the first IFD, which are added to
// the global offset counter. No need for bounds checking here because
// we checked in the previous section.
unsigned tiff_header_start = offs;
if (buf[offs] == 'I' && buf[offs+1] == 'I')
alignIntel = true;
else {
if(buf[offs] == 'M' && buf[offs+1] == 'M')
alignIntel = false;
else
return PARSE_EXIF_ERROR_UNKNOWN_BYTEALIGN;
}
this->ByteAlign = alignIntel;
offs += 2;
if (0x2a != parse16(buf+offs, alignIntel))
return PARSE_EXIF_ERROR_CORRUPT;
offs += 2;
unsigned first_ifd_offset = parse32(buf + offs, alignIntel);
offs += first_ifd_offset - 4;
if (offs >= len)
return PARSE_EXIF_ERROR_CORRUPT;
// Now parsing the first Image File Directory (IFD0, for the main image).
// An IFD consists of a variable number of 12-byte directory entries. The
// first two bytes of the IFD section contain the number of directory
// entries in the section. The last 4 bytes of the IFD contain an offset
// to the next IFD, which means this IFD must contain exactly 6 + 12 * num
// bytes of data.
if (offs + 2 > len)
return PARSE_EXIF_ERROR_CORRUPT;
int num_entries = parse16(buf + offs, alignIntel);
if (offs + 6 + 12 * num_entries > len)
return PARSE_EXIF_ERROR_CORRUPT;
offs += 2;
unsigned exif_sub_ifd_offset = 0;
unsigned gps_sub_ifd_offset = 0;
while (--num_entries >= 0) {
IFEntry result = parseIFEntry(buf, offs, alignIntel, tiff_header_start, len);
switch(result.tag) {
case 0x102:
// Bits per sample
if (result.format == 3)
this->BitsPerSample = result.val_16;
break;
case 0x10E:
// Image description
if (result.format == 2)
this->ImageDescription = result.val_string;
break;
case 0x10F:
// Digicam make
if (result.format == 2)
this->Make = result.val_string;
break;
case 0x110:
// Digicam model
if (result.format == 2)
this->Model = result.val_string;
break;
case 0x112:
// Orientation of image
if (result.format == 3)
this->Orientation = result.val_16;
break;
case 0x131:
// Software used for image
if (result.format == 2)
this->Software = result.val_string;
break;
case 0x132:
// EXIF/TIFF date/time of image modification
if (result.format == 2)
this->DateTime = result.val_string;
break;
case 0x8298:
// Copyright information
if (result.format == 2)
this->Copyright = result.val_string;
break;
case 0x8825:
// GPS IFS offset
gps_sub_ifd_offset = tiff_header_start + result.data;
break;
case 0x8769:
// EXIF SubIFD offset
exif_sub_ifd_offset = tiff_header_start + result.data;
break;
}
没有合适的资源?快使用搜索试试~ 我知道了~
Qt照片查看系统的实现
共39个文件
cpp:10个
h:10个
png:10个
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 37 浏览量
2024-04-04
12:21:13
上传
评论
收藏 65KB RAR 举报
温馨提示
Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统Qt实现照片查看系统
资源推荐
资源详情
资源评论
收起资源包目录
QHImageViewer.rar (39个子文件)
QHImageViewer
QHMainWindow.h 2KB
QHExifInfo.cpp 17KB
QHImageManager.cpp 9KB
QHImageViewer.cpp 8KB
QHTextBrowser.ui 1KB
QHMainWindow.cpp 9KB
QHImageHeader.h 5KB
QHConfig.h 512B
QHToolBar.h 619B
QHConfig.cpp 479B
QHExifInfo.h 4KB
Translations.ts 19KB
QHVelocitytracker.h 1KB
main.cpp 354B
QHToolBar.cpp 796B
QHImageManager.h 1KB
QHImageViewer.ui 442B
icons
Information.png 4KB
RotateRight.png 3KB
Previous.png 3KB
ZoomOut.png 3KB
Restore.png 2KB
AppIcon.ico 66KB
ZoomIn.png 3KB
Save.png 2KB
RotateLeft.png 3KB
Next.png 3KB
Open.png 3KB
Translations.qm 7KB
QHVelocityTracker.cpp 4KB
QHToolBar.ui 7KB
QHTextBrowser.h 356B
QHTextBrowser.cpp 661B
QHImageViewer.qrc 525B
QHImageViewer.pro 957B
QHImageViewer.h 1KB
QHJpgQualityGuess.h 5KB
QHImageHeader.cpp 14KB
QHMainWindow.ui 666B
共 39 条
- 1
资源评论
尘海折柳
- 粉丝: 1w+
- 资源: 107
下载权益
C知道特权
VIP文章
课程特权
开通VIP
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功