Получить размер изображения без загрузки в память - PullRequest
7 голосов
/ 11 октября 2009

У меня есть несколько .png изображений ( ETA: , но формат также может быть JPEG или что-то еще), которые я собираюсь отобразить в UITableViewCell с. Прямо сейчас, чтобы получить высоту строк, я загружаю изображения, получаю их свойства size и использую их, чтобы выяснить, насколько высоки строки (вычисляя любые необходимые изменения по пути, так как большинство изображений изменить размер перед отображением). Чтобы ускорить процесс и сократить использование памяти, я бы хотел получить size без загрузки изображений. Есть ли способ сделать это?

Примечание: Я знаю, что есть несколько ярлыков, которые я мог бы реализовать, чтобы устранить эту проблему, но по нескольким причинам я не могу заранее изменить размер изображения или заранее собрать размеры изображения, заставляя меня чтобы получить эту информацию во время выполнения.

Ответы [ 8 ]

6 голосов
/ 11 октября 2009

Это должно быть довольно просто. Спецификация PNG содержит объяснение потока PNG (который фактически является файлом). IHDR раздел содержит информацию о размерах изображения.

Итак, вам нужно прочитать PNG «магическое значение», а затем прочитать два четырехбайтовых целых числа, которые будут соответственно шириной и высотой. Вам также может понадобиться переупорядочить биты в этих значениях (не знаете, как они хранятся), но как только вы это выясните, это будет очень просто.

4 голосов
/ 13 ноября 2010

Начиная с iOS SDK 4.0, эту задачу можно выполнить с помощью инфраструктуры ImageIO (CGImageSource...). Я ответил на аналогичный вопрос здесь .

1 голос
/ 08 декабря 2016

imageUrl является NSURL, также импортируйте ImageIO / ImageIO.h с <> вокруг него.

CGImageSourceRef imageSourceRef = CGImageSourceCreateWithURL((CFURLRef)imageUrl, NULL);

if (!imageSourceRef)
    return;

CFDictionaryRef props = CGImageSourceCopyPropertiesAtIndex(imageSourceRef, 0, NULL);

NSDictionary *properties = (NSDictionary*)CFBridgingRelease(props);

if (!properties) {
    return;
}

NSNumber *height = [properties objectForKey:@"PixelHeight"];
NSNumber *width = [properties objectForKey:@"PixelWidth"];
int height = 0;
int width = 0;

if (height) {
    height = [height intValue];
}
if (width) {
    width = [width intValue];
}
1 голос
/ 26 июня 2010

// Вот быстрый и грязный порт для C #


public static Size PNGSize(string fileName)
{
    // PNG Signature. 
    byte[] png_signature = {137, 80, 78, 71, 13, 10, 26, 10}; </p>

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);

}

1 голос
/ 05 января 2010

Примечание: Эта функция не работает со сжатыми PNG-файлами iPhone, это сжатие автоматически выполняется XCode и изменяет заголовок изображения, подробнее см. Здесь и как отключить эту функцию: http://discussions.apple.com/thread.jspa?threadID=1751896

Будущие версии PSFramework также будут интерпретировать эти заголовки, следите за обновлениями.


Посмотри на эту функцию, она так и делает. Читает только 30 байтов PNG-файла и возвращает размер (CGSize). Эта функция является частью структуры для обработки изображений, называемой PSFramework (http://sourceforge.net/projects/photoshopframew/). Еще не реализована для других форматов изображений, разработчики приветствуются. Проект с открытым исходным кодом по лицензии 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 );

}

1 голос
/ 12 октября 2009

Это прекрасно реализовано в модуле Image :: Size Perl для примерно десятка форматов, включая 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 всего на несколько строк длиннее.

0 голосов
/ 12 октября 2009

низкотехнологичные решения:

Если вы заранее знаете, что это за изображения, сохраните размеры изображений вместе с их именами файлов в файле XML или в формате plist (или как вам удобнее) и просто прочитайте эти свойства в.

если вы не знаете, что это за изображения (то есть они будут определены во время выполнения), значит, вы должны были загрузить изображения в тот или иной момент. при первой загрузке сохраните их высоту и ширину в файле, чтобы вы могли получить к ним доступ позже.

0 голосов
/ 12 октября 2009

Попробуйте использовать функции CGImageCreateWithPNGDataProvider и CGImageCreateWithJPEGDataProvider . Я не знаю, достаточно ли они ленивы или нет, или это вообще возможно для JPEG, но стоит попробовать.

...