Получите размер изображения, не загружаясь в к памяти

Взгляните на встроенный ассемблер для C/C++, вот статья DDJ. Если Вы не будете на 100% уверены, что Ваша программа будет работать на совместимой платформе, необходимо следовать рекомендациям, которые многие дали здесь.

8
задан Peter Hosey 12 October 2009 в 03:50
поделиться

6 ответов

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

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

6
ответ дан 5 December 2019 в 10:42
поделиться

Это прекрасно реализовано в 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 всего на несколько строк длиннее.

1
ответ дан 5 December 2019 в 10:42
поделиться

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

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

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

0
ответ дан 5 December 2019 в 10:42
поделиться

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

0
ответ дан 5 December 2019 в 10:42
поделиться

Примечание: Эта функция не работает с 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 );

}

1
ответ дан 5 December 2019 в 10:42
поделиться

// Вот быстрый и грязный перенос на 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);

}

1
ответ дан 5 December 2019 в 10:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: