2009-03-13 3 views
22

Ho impostato un DB SQLite che attualmente legge e scrive NSString s perfettamente. Voglio anche memorizzare un'immagine nel database e richiamarla in seguito. Ho letto un po 'sull'uso di NSData e sulla codifica dell'immagine, ma non sono del tutto sicuro di quale sia la sintassi per ciò che voglio fare. Eventuali frammenti di codice o esempi sarebbero molto apprezzati.Lettura e scrittura di immagini su un DB SQLite per iPhone

mio attuale processo va come questa: UIImagePickerController - Sceglie> User Immagine da Foto -> chosenImage è impostato su istanza di UIImageView ->Ora voglio prendere questa immagine e conservarla nel DB

Devo dire che questa chiamata sarà eventualmente sostituita con una chiamata a un server remoto. Non sono sicuro se questo faccia la differenza per quanto riguarda le prestazioni.

risposta

9

Un'opzione (e generalmente preferita quando si lavora in SQL) è quella di scrivere l'immagine in un file sul sistema e memorizzare il percorso (o qualche altro tipo di identificatore) nel database.

+0

Sono davvero in perdita sul motivo per cui qualcuno dovrebbe memorizzare il binario nel DB. Sembra matto per me. Quindi penso che i metadati nel DB siano i migliori. –

+0

Puoi mostrarmi un esempio di codice per qualcosa di simile? Posso vedere come salvare un file potrebbe essere utile. – Jeff

+1

dopo alcuni giorni di ricerca su google. Ho realizzato ed eseguito questa idea. Pubblicherò del codice se qualcuno ne avesse bisogno. – Jeff

31

È necessario convertire UIImage ospitato in UIImageView in un BLOB binario per l'archiviazione in SQLite. Per fare questo, è possibile utilizzare il seguente:

NSData *dataForImage = UIImagePNGRepresentation(cachedImage); 
sqlite3_bind_blob(yourSavingSQLStatement, 2, [dataForImage bytes], [dataForImage length], SQLITE_TRANSIENT); 

Questo genererà una rappresentazione PNG della tua immagine, conservarlo in un caso NSData, e quindi associare i byte dal NSData come BLOB per il secondo argomento in la tua query SQL. Usa UIImageJPEGRepresentation in quanto sopra per memorizzare in quel formato, se ti piace. Dovrai avere una colonna BLOB aggiunta alla tabella appropriata nel tuo database SQLite.

Per recuperare questa immagine, è possibile utilizzare il seguente: Immagine

NSData *dataForCachedImage = [[NSData alloc] initWithBytes:sqlite3_column_blob(yourLoadingSQLStatement, 2) length: sqlite3_column_bytes(yourLoadingSQLStatement, 2)];  
self.cachedImage = [UIImage imageWithData:dataForCachedImage]; 
[dataForCachedImage release]; 
+0

Grazie Brad! Darò questo un tentativo più tardi questo pomeriggio. Sembra che possa fare il trucco però. – Jeff

+0

Ho capito che non volevo farlo. Salvare il file in un URL sul server è un modo migliore per andare. – Jeff

+2

Se funziona meglio per l'applicazione, allora quella è la strada da percorrere. Ho archiviato le immagini nel database quando volevo un singolo file che potrei raggruppare in un'applicazione che contenesse alcuni dati di avviamento. Ha reso il filesystem un po 'più pulito. –

2

Scrivendo a SQLite DB

if(myImage != nil){ 
    NSData *imgData = UIImagePNGRepresentation(myImage); 
    sqlite3_bind_blob(update_stmtement, 6, [imgData bytes], [imgData length], NULL);  
    } 
    else { 
     sqlite3_bind_blob(update_stmtement, 6, nil, -1, NULL); 
    } 

lettura da SQLite DB:

NSData *data = [[NSData alloc] initWithBytes:sqlite3_column_blob(init_statement, 6) length:sqlite3_column_bytes(init_statement, 6)]; 
     if(data == nil) 
      NSLog(@"No image found."); 
     else 
      self.pictureImage = [UIImage imageWithData:data]; 
9

raccomandazione di Apple non è per archiviare i BLOB nei database SQLite che superano i ~ 2 kilobyte.

SQLite organizza i database in pagine. Ogni pagina ha una dimensione di 4 kilobyte. Quando leggi dati dal file di database SQLite carica queste pagine in una cache di pagina interna. Sull'iPhone penso che questa cache abbia una dimensione predefinita di 1 megabyte. Questo rende molto veloce la lettura dei record adiacenti perché probabilmente saranno già nella cache della pagina.

Quando SQLite legge il record del database in memoria, legge l'intero record e tutte le pagine che esso occupa. Quindi se il tuo record contiene un BLOB, potrebbe occupare molte pagine e dovrai espellere le pagine esistenti dalla cache e sostituirle con le pagine del tuo BLOB record.

Questo non è poi così male se si esegue la scansione e si caricano tutti i BLOB per fare qualcosa con loro (visualizzarli ad esempio). Ma se si dice di aver fatto una query in cui si desiderava solo ottenere alcuni dati che si trovano nella stessa riga del BLOB, questa query sarebbe molto più lenta di se il record non contenesse il BLOB di grandi dimensioni.

Quindi, come minimo, è necessario memorizzare i dati BLOB in una tabella separata.Ad esempio:

CREATE TABLE blobs (id INTEGER PRIMARY KEY, data BLOB); 
CREATE TABLE photos (id INTEGER PRIMARY KEY, name TEXT, blob_id INTEGER, 
    FOREIGN KEY(blob_id) REFERENCES blobs(id)); 

O meglio ancora, memorizzare i dati BLOB come file al di fuori del database SQLite.

Si noti che potrebbe essere possibile modificare la dimensione della cache della pagina con SQL PRAGMA statements (se non si utilizza CoreData).

+0

Dove lo consiglia Apple? – Bill

0

La procedura consigliata è comprimere l'immagine e memorizzarla nel database o nel file system. Se non vi interessa circa la risoluzione dell'immagine si può andare avanti e anche ridimensionare l'immagine utilizzando:

UIGraphicsBeginImageContext(newSize); 
    [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)]; 
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();  
    UIGraphicsEndImageContext(); 

Dopo di che è possibile utilizzare UIImageJPEGRepresentation per le immagini JPEG con un valore pari a "0" per la massima compressione . Oppure è possibile utilizzare UIImagePNGRepresentation per immagini png

0

si dovrebbe prima scrivere l'immagine sul file system. e quindi prendere il percorso dell'immagine e memorizzare quel percorso dell'immagine (URL) come TEXT in sqlite.