Определите высоту и ширину BLOB - PullRequest
4 голосов
/ 02 октября 2019

Я понял, что файлы изображений некоторых людей ориентированы в альбомной ориентации, тогда как все они должны быть портретными, в нашей базе данных. Итак, мне нужно определить, какой файл имеет ширину больше его высоты.

Интересно, есть ли какой-нибудь метод для получения столбцов типа height и width из BLOBнапример, функция dbms_lob.getlength, которая возвращает количество символов (байтов) в столбце CLOB / BLOB.

Ответы [ 2 ]

8 голосов
/ 02 октября 2019

A BLOB - это двоичные данные - они по сути не имеют формата (такого как JPEG / PNG / BMP) и, как таковые, не являются неявно изображением, и спрашивать, какова его ширина / высота, не имеет смысла.

Что вам нужно сделать, это взять двоичные данные (BLOB) из их (неизвестного) двоичного формата (например, JPG / PNG / BMP / и т. Д.) И использовать программу чтения изображений для считывания измерений из мета-файла-data (поэтому вам не нужно загружать весь файл).

Вы можете написать класс Java, который имеет функцию, которая принимает BLOB / двоичный поток и формат изображения, а затем использует ImageIO или ImageReader & ImageInputStream (например, в качестве первых совпадений, которые я обнаружил при чтении изображений из двоичных данных; будут другие решения / библиотеки), извлеките измерения из заголовка[ 1 , 2 ] и верните его.

Затем, чтобы загрузить этот класс в базу данных Oracle, используйте утилиту loadjava или CREATE OR REPLACE AND COMPILE JAVA SOURCE ( пример для распаковки сжатой строкихранится в Oracle BLOB).

Затем напишите функцию SQL, чтобы обернуть реализацию Java, чтобы она передавала BLOB в функцию Java и возвращала ширину или высоту (или структуру, содержащую оба значения).


Java-код :

import java.io.IOException;
import java.sql.Blob;
import java.sql.SQLException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.MemoryCacheImageInputStream;

public class ImageMetaDataReader {
    public static Integer getHeight(
            final Blob   blob,
            final String fileType
    ) throws SQLException
    {
        Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix( fileType );
        while(iter.hasNext())
        {
            ImageReader reader = iter.next();
            try
            {
                ImageInputStream stream = new MemoryCacheImageInputStream( blob.getBinaryStream() );
                reader.setInput(stream);
                return reader.getHeight(reader.getMinIndex());
            } catch ( IOException e ) {
            } finally {
                reader.dispose();
            }
        }
        return null;
    }

    public static Integer getWidth(
            final Blob   blob,
            final String fileType
    ) throws SQLException
    {
        Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix( fileType );
        while(iter.hasNext())
        {
            ImageReader reader = iter.next();
            try
            {
                ImageInputStream stream = new MemoryCacheImageInputStream( blob.getBinaryStream() );
                reader.setInput(stream);
                return reader.getWidth(reader.getMinIndex());
            } catch ( IOException e ) {
            } finally {
                reader.dispose();
            }
        }
        return null;
    }
}

Тестирование :

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.Blob;
import java.sql.SQLException;

public class MockBlob implements Blob {
    private final File file;

    public MockBlob(
            final File file
    )
    {
        this.file = file;
    }

    @Override
    public long length() throws SQLException {
        return file.length();
    }

    @Override
    public InputStream getBinaryStream() throws SQLException {
        try
        {
            return new FileInputStream( this.file );
        }
        catch( FileNotFoundException e )
        {
            throw new SQLException( e.getMessage() );
        }
    }

    @Override public byte[] getBytes(long pos, int length) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); }
    @Override public long position(byte[] pattern, long start) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); }
    @Override public long position(Blob pattern, long start) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); }
    @Override public int setBytes(long pos, byte[] bytes) throws SQLException { throw new UnsupportedOperationException("Not supported yet.");  }
    @Override public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException { throw new UnsupportedOperationException("Not supported yet.");  }
    @Override public OutputStream setBinaryStream(long pos) throws SQLException { throw new UnsupportedOperationException("Not supported yet.");  }
    @Override public void truncate(long len) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); }
    @Override public void free() throws SQLException { throw new UnsupportedOperationException("Not supported yet."); }
    @Override public InputStream getBinaryStream(long pos, long length) throws SQLException { throw new UnsupportedOperationException("Not supported yet."); }
}
import java.io.File;
import java.sql.Blob;
import java.sql.SQLException;

public class ImageTest {
    public static void main(
            final String[] args
    ) throws SQLException
    {
        File file = new File( "/path/to/test.png" );
        Blob blob = new MockBlob( file );
        System.out.println(
                "height: "
                + ImageMetaDataReader.getHeight( blob, "png" )
        );
        System.out.println(
                "width: "
                + ImageMetaDataReader.getWidth( blob, "png" )
        );
    }
}

SQL :

CREATE AND COMPILE JAVA SOURCE NAMED "ImageMetaDataReader" AS
<the java code from above>
/

CREATE FUNCTION getImageHeight(
  file     IN BLOB,
  fileType IN VARCHAR2
) RETURN NUMBER
AS LANGUAGE JAVA
name 'ImageMetaDataReader.getHeight( java.sql.Blob, String) return Integer';
/

CREATE FUNCTION getImageWidth(
  file     IN BLOB,
  fileType IN VARCHAR2
) RETURN NUMBER
AS LANGUAGE JAVA
name 'ImageMetaDataReader.getWidth( java.sql.Blob, String) return Integer';
/

(Код не проверен в базе данных Oracle, так как в данный момент у меня нет экземпляра для передачи.)

2 голосов
/ 02 октября 2019

@ Ответ MT0 - это путь, позволяющий предположить, что это процесс, который должен работать в будущем.

Предполагая, что вы еще не используете 19.1, и если это просто специальное / краткосрочное требование,Вы можете создать ORDImage из BLOB. Предполагая, что изображение относится к одному из типов файлов, которые ORDImage понимает (что реально включает в себя практически все, что будет загружать обычный пользователь), конструктор может анализировать изображение и извлекать свойства, такие как высота и шириначто вы можете запросить. Он также предоставляет различные методы для управления изображением (масштабирование / вращение / и т. Д.)

К сожалению, ORDImage устарел в Oracle 18, и я считаю, что он был удален в Oracle 19, так что это не что-точто вы хотели бы больше использовать для написания кода, на который вы будете полагаться постоянно. Если вы просто пытаетесь получить специальный отчет или сделать кратковременное исправление данных, возможно, это проще, чем найти, загрузить и использовать библиотеку обработки изображений Java.

...