Взгляните на встроенный ассемблер для C/C++, вот статья DDJ. Если Вы не будете на 100% уверены, что Ваша программа будет работать на совместимой платформе, необходимо следовать рекомендациям, которые многие дали здесь.
Это должно быть довольно просто. В спецификации PNG есть объяснение потока данных PNG (который фактически является файлом). Раздел IHDR содержит информацию о размерах изображения.
Итак, что вам нужно сделать, это прочитать в PNG
«магическое значение», а затем прочитать два четырехбайтовых целых числа, которые будут ширина и высота соответственно. Вам также может потребоваться изменить порядок битов в этих значениях (не знаю, как они хранятся), но как только вы это поймете, это будет очень просто.
Это прекрасно реализовано в Perl модуле Image :: Size примерно для дюжины форматов, включая PNG и JPEG. Чтобы повторно реализовать его в Objective C, просто возьмите код Perl и прочтите его как псевдокод; -)
Например, pngsize () определяется как
# pngsize : gets the width & height (in pixels) of a png file
# cor this program is on the cutting edge of technology! (pity it's blunt!)
#
# Re-written and tested by tmetro@vl.com
sub pngsize
{
my $stream = shift;
my ($x, $y, $id) = (undef, undef, "could not determine PNG size");
my ($offset, $length);
# Offset to first Chunk Type code = 8-byte ident + 4-byte chunk length + 1
$offset = 12; $length = 4;
if (&$read_in($stream, $length, $offset) eq 'IHDR')
{
# IHDR = Image Header
$length = 8;
($x, $y) = unpack("NN", &$read_in($stream, $length));
$id = 'PNG';
}
($x, $y, $id);
}
jpegsize всего на несколько строк длиннее.
низкотехнологичные решения:
если вы заранее знаете, что это за изображения, сохраните размеры изображений вместе с их именами в XML-файле или plist (или как вам удобнее) и просто прочтите эти свойства в.
, если вы не знаете, что это за изображения (т. е. они будут определены во время выполнения), тогда вы должны были загружать изображения в тот или иной момент. при первой загрузке сохраните их высоту и ширину в файле, чтобы вы могли получить к нему доступ позже.
Попробуйте использовать функции CGImageCreateWithPNGDataProvider и CGImageCreateWithJPEGDataProvider . Не знаю, достаточно ли они ленивы или нет, и возможно ли это даже для JPEG, но попробовать стоит.
Примечание: Эта функция не работает с iPhone сжатых PNG, это сжатие автоматически выполняется XCode и изменить заголовок изображения, смотрите больше деталей здесь и как отключить эту функцию: http://discussions.apple.com/thread.jspa?threadID=1751896
Будущие версии PSFramework тоже будут интерпретировать эти заголовки, оставайтесь с нами.
Смотрите эту функцию, она делает именно это. Читает только 30 байт PNG файла и возвращает размер (CGSize). Эта функция является частью фреймворка обработки изображений под названием PSFramework (http://sourceforge.net/projects/photoshopframew/). Для других форматов изображений пока не реализована, разработчики приветствуются. Проект является Open Source под лицензией GNU.
CGSize PSPNGSizeFromMetaData( NSString* anFileName ) {
// File Name from Bundle Path.
NSString *fullFileName = [NSString stringWithFormat:@"%@/%@", [[NSBundle mainBundle] bundlePath], anFileName ];
// File Name to C String.
const char* fileName = [fullFileName UTF8String];
/* source file */
FILE * infile;
// Check if can open the file.
if ((infile = fopen(fileName, "rb")) == NULL)
{
NSLog(@"PSFramework Warning >> (PSPNGSizeFromMetaData) can't open the file: %@", anFileName );
return CGSizeZero;
}
////// ////// ////// ////// ////// ////// ////// ////// ////// ////// //////
// Lenght of Buffer.
#define bytesLenght 30
// Bytes Buffer.
unsigned char buffer[bytesLenght];
// Grab Only First Bytes.
fread(buffer, 1, bytesLenght, infile);
// Close File.
fclose(infile);
////// ////// ////// ////// //////
// PNG Signature.
unsigned char png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
// Compare File signature.
if ((int)(memcmp(&buffer[0], &png_signature[0], 8))) {
NSLog(@"PSFramework Warning >> (PSPNGSizeFromMetaData) : The file (%@) don't is one PNG file.", anFileName);
return CGSizeZero;
}
////// ////// ////// ////// ////// ////// ////// ////// ////// //////
// Calc Sizes. Isolate only four bytes of each size (width, height).
int width[4];
int height[4];
for ( int d = 16; d < ( 16 + 4 ); d++ ) {
width[ d-16] = buffer[ d ];
height[d-16] = buffer[ d + 4];
}
// Convert bytes to Long (Integer)
long resultWidth = (width[0] << (int)24) | (width[1] << (int)16) | (width[2] << (int)8) | width[3];
long resultHeight = (height[0] << (int)24) | (height[1] << (int)16) | (height[2] << (int)8) | height[3];
// Return Size.
return CGSizeMake( resultWidth, resultHeight );
}
// Вот быстрый и грязный перенос на C#.
public static Size PNGSize(string fileName)
{
// PNG Signature.
byte[] png_signature = {137, 80, 78, 71, 13, 10, 26, 10};
try
{
using (FileStream stream = File.OpenRead(fileName))
{
byte[] buf = new byte[30];
if (stream.Read(buf, 0, 30) == 30)
{
int i = 0;
int imax = png_signature.Length;
for (i = 0; i < imax; i++)
{
if (buf[i] != png_signature[i])
break;
}
// passes sig test
if (i == imax)
{
// Calc Sizes. Isolate only four bytes of each size (width, height).
// Convert bytes to integer
int resultWidth = buf[16] << 24 | buf[17] << 16 | buf[18] << 8 | buf[19];
int resultHeight = buf[20] << 24 | buf[21] << 16 | buf[22] << 8 | buf[23];
// Return Size.
return new Size( resultWidth, resultHeight );
}
}
}
}
catch
{
}
return new Size(0, 0);
}