2009-10-11 10 views
7

Ho diverse immagini .png (ETA: ma il formato potrebbe anche essere JPEG o qualcos'altro) che sto per visualizzare in UITableViewCell s. In questo momento, per ottenere le altezze di riga, carico le immagini, ottengo le loro proprietà size e le uso per capire quanto è alto fare le righe (calcolando eventuali modifiche necessarie lungo la strada, poiché la maggior parte delle immagini viene ridimensionata prima di essere visualizzato). Al fine di accelerare le cose e ridurre l'utilizzo della memoria, mi piacerebbe essere in grado di ottenere size senza caricare le immagini. C'è un modo per fare questo?Ottieni dimensioni dell'immagine senza caricare nella memoria

Nota: So che ci sono un certo numero di scorciatoie ho potuto implementare per eliminare questo problema, ma per vari motivi non riesco a ridimensionare le immagini in anticipo o raccogliere le dimensioni delle immagini in anticipo, costringendomi a ottenere questo informazioni in fase di esecuzione.

+1

CGImageSource è l'API perfetta per questo, ma fastidiosamente non è disponibile su iPhone. Probabilmente dovrai implementarlo da solo. Detto questo, tieni presente che UIImage eliminerà i suoi dati se usi + imageWithContentsOfFile: che dovrebbe rimuovere i tuoi dubbi sull'uso della memoria. –

risposta

4

Come di iOS SDK 4.0, questo compito può essere realizzato con il framework ImageIO (CGImageSource...). Ho risposto allo a similar question here.

6

Dovrebbe essere piuttosto semplice. PNG spec ha una spiegazione di PNG datastream (che è effettivamente un file). La sezione IHDR contiene informazioni sulle dimensioni dell'immagine.

Quindi quello che devi fare è leggere in PNG "valore magico" e quindi leggere due interi a quattro byte, che saranno rispettivamente larghezza e altezza. Potrebbe anche essere necessario riordinare i bit in questi valori (non sono sicuro di come sono memorizzati), ma una volta capito, sarà molto semplice.

+0

Buona idea, tranne che ho dimenticato di dire che potrebbe non essere un PNG, è proprio quello che mi capita di avere adesso (post modificato per riflettere questo). Devo anche supportare JPEG, almeno, anche se suppongo di poterlo fare in un modo simile a quello che descrivi. –

1

Questo è ben implementato in Perl Image::Size module per circa una dozzina di formati, inclusi PNG e JPEG. Al fine di ri-attuarlo in Objective C basta prendere il codice Perl e leggere come pseudocodice ;-)

Ad esempio, pngsize() è definito come

# 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 [email protected] 
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 è solo poche linee più lunghe .

0

soluzioni low tech:

se si sa cosa le immagini sono in anticipo, memorizzare l'immagine dimensioni con i loro nomi di file in un file XML o plist (o in qualunque modo si preferisce) e appena letto queste proprietà in

.

se non si conoscono le immagini (cioè verranno definite in fase di esecuzione), è necessario che le immagini siano state caricate in un momento o nell'altro. la prima volta che li fai caricare, salva la loro altezza e larghezza in un file in modo che tu possa accedervi in ​​seguito.

1

Nota: Questa funzione non funziona con iPhone PNG compressi, questa compressione viene eseguita automaticamente dal XCode e modificare l'intestazione dell'immagine, vedere maggiori dettagli qui e come disattivare questa funzione: http://discussions.apple.com/thread.jspa?threadID=1751896

versioni future di PSFramework interpreterà anche queste intestazioni, restate sintonizzati.


Vedere questa funzione, fa proprio questo. Legge solo 30 byte del file PNG e restituisce la dimensione (CGSize). Questa funzione fa parte di un framework per l'elaborazione di immagini chiamate PSFramework (http://sourceforge.net/projects/photoshopframew/). Non ancora implementato per altri formati di immagine, gli sviluppatori sono i benvenuti.Il progetto è Open Source sotto la licenza 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

// Ecco un rapido & sporco porta a 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

imageUrl è un NSURL, inoltre importa ImageIO/ImageIO.h con <> attorno ad esso.

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]; 
} 
Problemi correlati