有時(shí)候,我們需要獲取一個(gè)圖片的格式和大小突那,但是卻不想從內(nèi)存中把它的整個(gè)文件從內(nèi)存中讀取出來
因?yàn)樽x取整個(gè)文件的內(nèi)存耗費(fèi)還是有些的挫酿,所以這么做通常不可取。
實(shí)在需要讀取那也沒辦法愕难。
但是其實(shí)是可以從文件中讀取出來早龟。 原因是圖片文件的格式標(biāo)準(zhǔn)。
這些標(biāo)準(zhǔn)的存在使得可以只讀取部分字段猫缭,
就能獲知圖片的格式葱弟。
先說圖片的格式:
圖片的格式存在 圖片文件的前8個(gè)字節(jié)中。
以PNG 為例
PNG的前八個(gè)字節(jié)依次為:0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A
讀取PNG 圖片前8個(gè)字節(jié)猜丹,判斷一下就可以知道是否是PNG 圖片芝加。
其他圖片的格式類似。
再來說說圖片的大小射窒。
圖片的大小也是存在相關(guān)字段中
還是以PNG 為例藏杖,PNG 的圖片大小,存儲在第9個(gè)字節(jié)開始的8個(gè)字節(jié)中
前四個(gè)字節(jié)表示寬度脉顿,后四個(gè)字節(jié)表示高度蝌麸。
PNG文件存儲的長寬信息存儲較簡單。
但是JPG文件就比較復(fù)雜了弊予。
首先JPG文件存儲的東西是分塊存儲的祥楣。
很多很多的塊。
這些塊的開頭幾個(gè)字節(jié)汉柒,表示該塊包含哪些信息误褪。
其中,如果某個(gè)塊的開頭0xffc0 或者是 0xffc1或者是 0xffc2
那么該塊將會存儲 圖片文件的 尺寸信息碾褂,也就是長寬兽间。
如果不是的話,那么就是別的塊正塌。
除了塊的開頭兩個(gè)字節(jié)是固定的 0xffxx信息嘀略,塊開頭的第三第四個(gè)字節(jié)表示該塊的的長度。
我們可以根據(jù)該塊的大小信息快速跳過此塊乓诽,查找下一個(gè)塊帜羊,這樣能夠過濾不含有
圖片尺寸的信息。
下面為部分代碼鸠天。
//
// HBImageTypeSizeUtill.m
// Pods
//
// Created by wangdan on 16/9/1.
//
//
#import "HBImageTypeSizeUtil.h"
#import <UIKit/UIKit.h>
@implementation HBImageTypeSizeUtil
+ (HBImageType)imageTypeOfFilePath:(NSString *)filePath
{
HBImageType type = HBImageTypeUnKnow;
if (filePath.length == 0) {
return HBImageTypeUnKnow;
}
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
return HBImageTypeUnKnow;
}
NSFileHandle *fileHandler = [NSFileHandle fileHandleForReadingAtPath:filePath];
if (!fileHandler) {
return HBImageTypeUnKnow;
}
NSData *headData = [fileHandler readDataOfLength:8];
if (!headData.length == 8) {
[fileHandler closeFile];
return HBImageTypeUnKnow;
}
Byte *bytesArray = (Byte*)[headData bytes];
if (bytesArray[0] == 0x89 &&
bytesArray[1] == 0x50 && // P
bytesArray[2] == 0x4E && // N
bytesArray[3] == 0x47 && // G
bytesArray[4] == 0x0D &&
bytesArray[5] == 0x0A &&
bytesArray[6] == 0x1A &&
bytesArray[7] == 0x0A)
{
type = HBImageTypePNG;
}
else if (bytesArray[0] == 0xFF && bytesArray[1] == 0xD8)
{
type = HBImageTypeJPG;
}
else if (bytesArray[0] == 0x47 && // G
bytesArray[1] == 0x49 && // I
bytesArray[2] == 0x46 && // F
bytesArray[3] == 0x38 && // 8
(bytesArray[4] == 0x39 || // 9
bytesArray[4] == 0x37) && // 7
bytesArray[5] == 0x61) // a
{
type = HBImageTypeGIF;
}
else if (bytesArray[0] == 0x42 && //B
bytesArray[1] == 0x4D) //M
{
type = HBImageTypeBMP;
}
[fileHandler closeFile];
return type;
}
+ (CGSize)imagSizeOfFilePath:(NSString *)filePath
{
CGSize finalSize = CGSizeZero;
HBImageType type = [self imageTypeOfFilePath:filePath];
switch (type) {
case HBImageTypeJPG:
{
return [self jpgImageSizeWithFilePath:filePath];
}
break;
case HBImageTypePNG:
{
NSData *data = [self fileHeaderData:8 seek:16 filePath:filePath];
finalSize = [self pngImageSizeWithHeaderData:data];
}
break;
case HBImageTypeBMP:
{
NSData *data = [self fileHeaderData:8 seek:18 filePath:filePath];
finalSize = [self bmpImageSizeWithHeaderData:data];
}
break;
case HBImageTypeGIF:
{
NSData *data = [self fileHeaderData:4 seek:6 filePath:filePath];
finalSize = [self gifImageSizeWithHeaderData:data];
}
break;
case HBImageTypeUnKnow:
{
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
if (image) {
finalSize = image.size;
}
else {
finalSize = CGSizeZero;
}
}
break;
default:
finalSize = CGSizeZero;
break;
}
return finalSize;
}
+ (NSData*)fileHeaderData:(NSInteger)length seek:(NSInteger)seek filePath:(NSString *)filePath {
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
return nil;
}
NSDictionary *fileAttribute = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
NSUInteger fileSize = [fileAttribute fileSize];
if (length + seek > fileSize) {
return nil;
}
NSFileHandle *fileHandler = [NSFileHandle fileHandleForReadingAtPath:filePath];
[fileHandler seekToFileOffset:seek];
NSData *data = [fileHandler readDataOfLength:length];
[fileHandler closeFile];
return data;
}
+ (CGSize)gifImageSizeWithHeaderData:(NSData *)data
{
if (data.length != 4) {
return CGSizeZero;
}
unsigned char w1 = 0, w2 = 0;
[data getBytes:&w1 range:NSMakeRange(0, 1)];
[data getBytes:&w2 range:NSMakeRange(1, 1)];
short w = w1 + (w2 << 8);
unsigned char h1 = 0, h2 = 0;
[data getBytes:&h1 range:NSMakeRange(2, 1)];
[data getBytes:&h2 range:NSMakeRange(3, 1)];
short h = h1 + (h2 << 8);
return CGSizeMake(w, h);
}
//JPG文件數(shù)據(jù)讼育,分很多很多的數(shù)據(jù)段, 并且每個(gè)數(shù)據(jù)段都會以 0xFF開頭
//找到一個(gè)數(shù)據(jù)斷后稠集,如果數(shù)據(jù)段的開頭是0xffc0奶段,那么該數(shù)據(jù)段將會存儲 圖片的尺寸信息
//否則0xffc0 后面緊跟的兩個(gè)字段,存儲的是當(dāng)前這個(gè)數(shù)據(jù)段的長度剥纷,可跳過當(dāng)前的數(shù)據(jù)段
//然后尋找下一個(gè)數(shù)據(jù)段痹籍,然后查看是否有圖片尺寸信息
+ (CGSize)jpgImageSizeWithFilePath:(NSString *)filePath
{
if (!filePath.length) {
return CGSizeZero;
}
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
return CGSizeZero;
}
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
NSUInteger offset = 2;
NSUInteger length = 0;
while (1) {
[fileHandle seekToFileOffset:offset];
length = 4;
NSData *data = [fileHandle readDataOfLength:length];
if (data.length != length) {
break;
}
offset += length;
int marker,code;
NSUInteger newLength;
unsigned char value1,value2,value3,value4;
[data getBytes:&value1 range:NSMakeRange(0, 1)];
[data getBytes:&value2 range:NSMakeRange(1, 1)];
[data getBytes:&value3 range:NSMakeRange(2, 1)];
[data getBytes:&value4 range:NSMakeRange(3, 1)];
marker = value1;
code = value2;
newLength = (value3 << 8) + value4;
if (marker != 0xff) {
[fileHandle closeFile];
return CGSizeZero;
}
if (code >= 0xc0 && code <= 0xc3) {
length = 5;
[fileHandle seekToFileOffset:offset];
NSData *data =[fileHandle readDataOfLength:length];
if (data.length != length) {
break;
}
Byte *bytesArray = (Byte*)[data bytes];
NSUInteger height = ((unsigned char)bytesArray[1] << 8) + (unsigned char)bytesArray[2];
NSUInteger width = ((unsigned char)bytesArray[3] << 8) + (unsigned char)bytesArray[4];
[fileHandle closeFile];
return CGSizeMake(width, height);
}
else {
offset += newLength;
offset -=2;
}
}
[fileHandle closeFile];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];
if (image) {
CGSizeMake((NSInteger)image.size.width, (NSInteger)image.size.height);
}
return CGSizeZero;
}
+ (CGSize)pngImageSizeWithHeaderData:(NSData *)data
{
if (data.length != 8) {
return CGSizeZero;
}
unsigned char w1 = 0, w2 = 0, w3 = 0, w4 = 0;
[data getBytes:&w1 range:NSMakeRange(0, 1)];
[data getBytes:&w2 range:NSMakeRange(1, 1)];
[data getBytes:&w3 range:NSMakeRange(2, 1)];
[data getBytes:&w4 range:NSMakeRange(3, 1)];
int w = (w1 << 24) + (w2 << 16) + (w3 << 8) + w4;
unsigned char h1 = 0, h2 = 0, h3 = 0, h4 = 0;
[data getBytes:&h1 range:NSMakeRange(4, 1)];
[data getBytes:&h2 range:NSMakeRange(5, 1)];
[data getBytes:&h3 range:NSMakeRange(6, 1)];
[data getBytes:&h4 range:NSMakeRange(7, 1)];
int h = (h1 << 24) + (h2 << 16) + (h3 << 8) + h4;
return CGSizeMake(w, h);
}
+ (CGSize)bmpImageSizeWithHeaderData:(NSData *)data {
if (data.length != 8) {
return CGSizeZero;
}
unsigned char w1 = 0, w2 = 0, w3 = 0, w4 = 0;
[data getBytes:&w1 range:NSMakeRange(0, 1)];
[data getBytes:&w2 range:NSMakeRange(1, 1)];
[data getBytes:&w3 range:NSMakeRange(2, 1)];
[data getBytes:&w4 range:NSMakeRange(3, 1)];
int w = w1 + (w2 << 8) + (w3 << 16) + (w4 << 24);
unsigned char h1 = 0, h2 = 0, h3 = 0, h4 = 0;
[data getBytes:&h1 range:NSMakeRange(4, 1)];
[data getBytes:&h2 range:NSMakeRange(5, 1)];
[data getBytes:&h3 range:NSMakeRange(6, 1)];
[data getBytes:&h4 range:NSMakeRange(7, 1)];
int h = h1 + (h2 << 8) + (h3 << 16) + (h4 << 24);
return CGSizeMake(w, h);
}
@end