General

6.13 Come implementare correttamente un archivio di immagini.
  Stefano Bettini
Una delle domande maggiormente ricorrenti sul newsgroup riguarda certamente il modo corretto di implementare un "archivio di immagini".
Di fronte a tale problematica generalmente lo sviluppatore poco esperto sceglie di memorizzare l'immagine in un campo di tabella di tipo OLE, finendo però ben presto per rendersi conto che il suo database raggiunge rapidamente dimensioni spropositate rispetto alla quantità di immagini archiviate; dov'è lo sbaglio?
Il problema nasce da una "sbadataggine" dei programmatori Microsoft; utilizzando l'automazione OLE infatti le immagini vengono salvate in formato NON compresso, col risultato che pochi megabytes di immagini .jpg (tipico formato compresso) finiscono x occupare parecchie decine di megabytes una volta memorizzate nel database, con tutti gli ovvi svantaggi che tale situazione comporta (difficile trasportabilità, lentezza ecc. ecc).

Esistono almeno due diverse tecniche per ovviare a tale inconveniente:

1) Utilizzare il database solo come "indice", lasciando le immagini esterne allo stesso.
E' certamente la soluzione più semplice e quella ottimale nel 99% dei casi; è sufficiente memorizzare all' interno del database il solo path del file immagine, path che poi potrà essere utilizzato unitamente al controllo "Immagine" (standard in Access97) per la visualizzazione sia sulle forms che sui reports.
Supponendo di aver memorizzato il path del file immagine nel campo Path_Immagine sarà sufficiente inserire un controllo Immagine nella form o nel report basati sulla tabella ed un controllo nascosto collegato al campo in questione.
A questo punto, sull' evento Corrente (per le forms) o SuFormattazione (per i reports) sarà sufficiente aggiungere la semplice riga di codice seguente per visualizzare l' immagine:
Me.MioControlloImmagine.Picture = Me.Path_Immagine
Nel caso non si potessero/volessero utilizzare controlli nascosti occorrerà naturalmente implementare il codice opportuno che vada a recuperare il valore del campo Path_Immagine dal record corretto tramite recordset od una istruzione DLookup().

2) Memorizzare le immagini in formato binario.
Soluzione valida e pratica solo per casi molto particolari, in quanto costringe a ricrearsi il file immagine al volo per poterlo visualizzare tramite il controllo Immagine o tramite un controllo/programma di terze parti.
Il "trucco" sta tutto nell'utilizzare un campo OLE in modalità BLOB (Binary Large OBject), caricandolo perciò direttamente tramite una procedura che legga il file immagine in modalità binaria.
Per chi fosse interessato a questa tecnica, valida comunque per memorizzare sulle tabelle qualsiasi tipo di dato binario, accludo due esempi di funzioni adatti a salvare/estrarre dati di tipo BLOB tratti dall'(imperdibile) Access97 Knowledge Base.

Const BlockSize = 32768

'**************************************************************
' FUNCTION: ReadBLOB()
' PURPOSE:
'   Legge un BLOB-file e lo memorizza in un campo
' PREREQUISITES:
'   The specified table with the OLE object field to contain the
'   binary data must be opened in Visual Basic code (Access Basic
'   code in Microsoft Access 2.0 and earlier) and the correct record
'   navigated to prior to calling the ReadBLOB() function.
' ARGUMENTS:
'   Source - The path and filename of the binary information
'            to be read and stored.
'   T      - The table object to store the data in.
'   Field  - The OLE object field in table T to store the data in.
' RETURN:
'   The number of bytes read from the Source file.
'**************************************************************
Function ReadBLOB(Source As String, T As Recordset, sField As String)
    Dim NumBlocks As Integer, SourceFile As Integer, i As Integer
    Dim FileLength As Long, LeftOver As Long
    Dim FileData As String
    Dim RetVal As Variant
    On Error GoTo Err_ReadBLOB
    ' Open the source file.
    SourceFile = FreeFile
    Open Source For Binary Access Read As SourceFile
    ' Get the length of the file.
    FileLength = LOF(SourceFile)
    If FileLength = 0 Then
        ReadBLOB = 0
        Exit Function
    End If
    ' Calculate the number of blocks to read and leftover bytes.
    NumBlocks = FileLength \ BlockSize
    LeftOver = FileLength Mod BlockSize
    ' SysCmd is used to manipulate status bar meter.
    RetVal = SysCmd(acSysCmdInitMeter, "Reading BLOB", FileLength \ 1000)
    ' Put first record in edit mode.
    T.MoveFirst
    T.Edit
    ' Read the leftover data, writing it to the table.
    FileData = String$(LeftOver, 32)
    Get SourceFile, , FileData
    T(sField).AppendChunk (FileData)
    RetVal = SysCmd(acSysCmdUpdateMeter, LeftOver / 1000)
    ' Read the remaining blocks of data, writing them to the table.
    FileData = String$(BlockSize, 32)
    For i = 1 To NumBlocks
        Get SourceFile, , FileData
        T(sField).AppendChunk (FileData)
        RetVal = SysCmd(acSysCmdUpdateMeter, BlockSize * i / 1000)
    Next i
    ' Update the record and terminates function.
    T.Update
    RetVal = SysCmd(acSysCmdRemoveMeter)
    Close SourceFile
    ReadBLOB = FileLength
    Exit Function
Err_ReadBLOB:
    ReadBLOB = -Err
    Exit Function
End Function

'**************************************************************
' FUNCTION: WriteBLOB()
'
' PURPOSE:
'   Legge un campo BLOB ricreando il file originale
' PREREQUISITES:
'   The specified table with the OLE object field containing the
'   binary data must be opened in Visual Basic code (Access Basic
'   code in Microsoft Access 2.0 or earlier) and the correct
'   record navigated to prior to calling the WriteBLOB() function.
' ARGUMENTS:
'   T           - The table object containing the binary information.
'   sField      - The OLE object field in table T containing the
'                 binary information to write.
'   Destination - The path and filename to write the binary
'                 information to.
' RETURN:
'   The number of bytes written to the destination file.
'**************************************************************
Function WriteBLOB(T As Recordset, sField As String, Destination As String)
    Dim NumBlocks As Integer, DestFile As Integer, i As Integer
    Dim FileLength As Long, LeftOver As Long
    Dim FileData As String
    Dim RetVal As Variant
    On Error GoTo Err_WriteBLOB
    ' Get the size of the field.
    FileLength = T(sField).FieldSize()
    If FileLength = 0 Then
        WriteBLOB = 0
        Exit Function
    End If
    ' Calculate number of blocks to write and leftover bytes.
    NumBlocks = FileLength \ BlockSize
    LeftOver = FileLength Mod BlockSize
    ' Remove any existing destination file.
    DestFile = FreeFile
    Open Destination For Output As DestFile
    Close DestFile
    ' Open the destination file.
    Open Destination For Binary As DestFile
    ' SysCmd is used to manipulate the status bar meter.
    RetVal = SysCmd(acSysCmdInitMeter, "Writing BLOB", FileLength / 1000)
    ' Write the leftover data to the output file.
    FileData = T(sField).GetChunk(0, LeftOver)
    Put DestFile, , FileData
    ' Update the status bar meter.
    RetVal = SysCmd(acSysCmdUpdateMeter, LeftOver / 1000)
    ' Write the remaining blocks of data to the output file.
    For i = 1 To NumBlocks
        ' Reads a chunk and writes it to output file.
        FileData = T(sField).GetChunk((i - 1) * BlockSize + LeftOver, BlockSize)
        Put DestFile, , FileData
        RetVal = SysCmd(acSysCmdUpdateMeter, _
              ((i - 1) * BlockSize + LeftOver) / 1000)
    Next i
    ' Terminates function
    RetVal = SysCmd(acSysCmdRemoveMeter)
    Close DestFile
    WriteBLOB = FileLength
    Exit Function
Err_WriteBLOB:
    WriteBLOB = -Err
    Exit Function
End Function


Se pensate di avere del materiale freeware interessante e volete pubblicarlo, allora leggete qui.