C’è una ragione per cui Image.FromFile lancia una OutOfMemoryException per un formato di immagine non valido?

Sto scrivendo un codice che cattura questa OutOfMemoryException e lancia una nuova eccezione più intuitiva:

 /// ... /// The file does not have a valid image format. public static Image OpenImage( string filename ) { try { return Image.FromFile( filename ); } catch( OutOfMemoryException ex ) { throw new FormatException( "The file does not have a valid image format.", ex ); } } 

Questo codice è accettabile per il suo utente o OutOfMemoryException è intenzionalmente lanciato per un motivo particolare?

No, è storia. GDI + è stato scritto un bel po ‘prima che .NET venisse a galla. Il wrapper SDK per esso è stato scritto in C ++. Le eccezioni sono incerte in C ++, non tutti le acquistano. Ad esempio, Google non lo fa. Quindi per tenerlo compatibile riporta problemi con i codici di errore. Questo non si adatta mai bene, i programmatori di librerie lo fanno un objective per limitare intenzionalmente il numero di possibili codici di errore, diminuendo l’onere per il programmatore del client di doverli segnalare.

GDI + ha questo problema in picche, definisce solo 20 codici di errore. Non è tanto per un pezzo così grande di codice con così tante dipendenze esterne. Che di per sé è un problema, ci sono molti modi per rovinare un file immagine. In nessun modo la segnalazione degli errori di una libreria può essere abbastanza dettagliata da coprire tutti. Il fatto che questi codici di errore siano stati scelti molto prima che i tipi derivati ​​da Eccezione standard definiti da .NET non hanno certamente aiutato.

Il codice di errore Status :: OutOfMemory è stato sovraccaricato per indicare cose diverse. A volte significa veramente memoria insufficiente, non può allocare spazio sufficiente per memorizzare i bit bitmap. Purtroppo, un problema di formato file immagine è riportato dallo stesso codice di errore. L’attrito qui è che non è ansible decidere se la larghezza * height * pixel che legge dal file immagine è un problema perché non c’è abbastanza spazio disponibile per la bitmap. O se i dati nel file immagine sono spazzatura. Si presuppone che il file immagine non sia junk, fair call, questo è un altro problema del programma. Quindi OOM è ciò che riporta.

Per completezza, questi sono i codici di errore:

 enum Status { Ok = 0, GenericError = 1, InvalidParameter = 2, OutOfMemory = 3, ObjectBusy = 4, InsufficientBuffer = 5, NotImplemented = 6, Win32Error = 7, WrongState = 8, Aborted = 9, FileNotFound = 10, ValueOverflow = 11, AccessDenied = 12, UnknownImageFormat = 13, FontFamilyNotFound = 14, FontStyleNotFound = 15, NotTrueTypeFont = 16, UnsupportedGdiplusVersion = 17, GdiplusNotInitialized = 18, PropertyNotFound = 19, PropertyNotSupported = 20, #if (GDIPVER >= 0x0110) ProfileNotFound = 21, #endif //(GDIPVER >= 0x0110) }; 

Bene, è un buon esempio di come un’eccezione non significhi sempre ciò che dice. Questo caso particolare ( OutOfMemoryException per un file non valido) risale a .Net 1.0, che aveva un insieme più limitato di tipi di eccezione da cui i programmatori di questa libreria potevano scegliere. Presumo che da allora non sia stato modificato per mantenere la retrocompatibilità (ovvero “buttare soldi dopo male”).

Per essere onesti, penso che fosse la peggiore scelta ansible per il tipo di eccezione che avrebbero potuto fare qui. Quando apri un file, e succede che è grande, e ottieni una OutOfMemoryException , è logico presumere che tu abbia effettivamente esaurito la memoria e abbaia dall’albero sbagliato per un po ‘(c’è più di una domanda su StackOverflow a riguardo ).

Se è perché il file non è valido, probabilmente sta solo cercando di indovinare quanto è grande un buffer di cui ha bisogno in base a qualche byte in quello che pensa sia l’intestazione. Documenta chiaramente il tuo intento con un test e dovresti stare bene.

È un’eccezione fuorviante. Microsoft dice :

Si visualizza un messaggio di errore “System.OutOfMemoryException” quando si tenta di utilizzare il metodo Bitmap.FromFile in .NET Framework 1.0

Questo problema può verificarsi quando si utilizza il metodo Bitmap.FromFile e una delle seguenti condizioni è vera:

  • Il file immagine è danneggiato.
  • Il file immagine è incompleto.

Nota Potresti riscontrare questo problema se la tua applicazione sta tentando di utilizzare il metodo Bitmap.FromFile su un stream di file che non ha terminato la scrittura su un file. * Il file immagine non ha un formato immagine valido o GDI + non supporta il formato pixel del file. * Il programma non ha permessi per accedere al file immagine. * La proprietà BackgroundImage è impostata direttamente dal metodo Bitmap.FromFile .

(La bitmap scende dall’immagine)

Naturalmente, è anche ansible ottenere questa eccezione quando si tenta di caricare un’immagine troppo grande. Quindi devi considerarlo.