Jak sprawdzić przesłany plik, czy jest to obraz, czy inny plik?

W mojej aplikacji internetowej mam moduł przesyłania obrazów. Chcę sprawdzić przesłany plik, czy jest to plik obrazu,czy jakikolwiek inny. Używam Javy po stronie serwera.

Obraz jest odczytywany jako BufferedImage w Javie, a następnie zapisuję go na dysk za pomocą ImageIO.write()

Jak sprawdzić BufferedImage, czy to naprawdę obrazek, czy coś innego?

Wszelkie sugestie lub linki będą mile widziane.

Author: BalusC, 2010-11-13

3 answers

Zakładam, że uruchamiasz to w kontekście serwletów. Jeśli jest to przystępne, aby sprawdzić typ zawartości na podstawie tylko rozszerzenia pliku, a następnie użyć ServletContext#getMimeType() aby uzyskać typ MIME (typ zawartości). Sprawdź, czy zaczyna się od image/.

String fileName = uploadedFile.getFileName();
String mimeType = getServletContext().getMimeType(fileName);
if (mimeType.startsWith("image/")) {
    // It's an image.
}

Domyślne typy mime są definiowane w web.xml danego programu servletcontainer. Na przykład Tomcat, znajduje się w /conf/web.xml. Możesz rozszerzyć / nadpisać go w /WEB-INF/web.xml swojej aplikacji internetowej w następujący sposób:

<mime-mapping>
    <extension>svg</extension>
    <mime-type>image/svg+xml</mime-type>
</mime-mapping>

Ale to nie uniemożliwia użytkownikom, którzy oszukują Cię, zmieniając rozszerzenie pliku. Jeśli chcesz również to zakryć, możesz również określić typ mime na podstawie zawartości pliku . Jeśli jest to przystępne, aby sprawdzić tylko typy BMP, GIF, JPG lub PNG (ale nie TIF, PSD, SVG, itp), można po prostu karmić go bezpośrednio do ImageIO#read() i sprawdź, czy nie rzuca wyjątku.

try (InputStream input = uploadedFile.getInputStream()) {
    try {
        ImageIO.read(input).toString();
        // It's an image (only BMP, GIF, JPG and PNG are recognized).
    } catch (Exception e) {
        // It's not an image.
    }
}

Ale jeśli chcesz pokryć więcej typów obrazów, rozważ użycie 3rd party library, która wykonuje całą pracę przez wąchanie nagłówków plików . Na przykład JMimeMagic lub Apache Tika, które obsługują zarówno BMP, GIF, JPG, PNG, TIF i PSD (ale nie SVG). Apache Batik obsługuje SVG. Poniższy przykład używa JMimeMagic:

try (InputStream input = uploadedFile.getInputStream()) {
    String mimeType = Magic.getMagicMatch(input, false).getMimeType();
    if (mimeType.startsWith("image/")) {
        // It's an image.
    } else {
        // It's not an image.
    }
}

W razie potrzeby można użyć kombinacji i przeważyć jeden i drugi.

To powiedziawszy, niekoniecznie musisz ImageIO#write() zapisać przesłany obraz na dysk. Tylko pisanie uzyskanego InputStream bezpośrednio do Path lub dowolnego OutputStream Jak FileOutputStream zwykły sposób Java IO jest więcej niż wystarczający (Zobacz także zalecany sposób zapisywania przesłanych plików w aplikacji servlet):

try (InputStream input = uploadedFile.getInputStream()) {
    Files.copy(input, new File(uploadFolder, fileName).toPath());
}

Chyba, że chcesz zebrać informacje o obrazie, takie jak jego wymiary i / lub chcesz nimi manipulować (przycinanie/zmiana rozmiaru/obracanie/konwersja/itp.) oczywiście.

 87
Author: BalusC,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:21

Użyłem org.Apacz.commons.obrazowanie.Obrazowanie w moim przypadku. Poniżej znajduje się przykładowy fragment kodu, aby sprawdzić, czy obraz jest obrazem jpeg, czy nie. Rzuca ImageReadException, jeśli przesłany plik nie jest obrazem.

    try {
        //image is InputStream
        byte[] byteArray = IOUtils.toByteArray(image);
        ImageFormat mimeType = Imaging.guessFormat(byteArray);
        if (mimeType == ImageFormats.JPEG) {
            return;
        } else {
            // handle image of different format. Ex: PNG
        }
    } catch (ImageReadException e) {
        //not an image
    }
 3
Author: gagan bopanna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-17 15:23:29

To jest wbudowane w JDK i po prostu wymaga strumienia z obsługą

byte[] data = ;
InputStream is = new BufferedInputStream(new ByteArrayInputStream(data));
String mimeType = URLConnection.guessContentTypeFromStream(is);
//...close stream
 2
Author: gcstang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-29 20:19:01