【问题标题】:Determine the Height and the Width of a BLOB确定 BLOB 的高度和宽度
【发布时间】:2020-01-31 16:13:53
【问题描述】:

我意识到在我们的数据库中,有些人的图像文件是定向横向的,而所有这些都应该是纵向的。 所以,我需要确定哪个文件的宽度大于高度。

我想知道是否有任何方法可以获取BLOB 类型列的heightwidth,例如dbms_lob.getlength 函数,它返回CLOB/BLOB 中的字符数(字节)列。

【问题讨论】:

  • 我会假设每种图像格式(JPGPNG)都有一些存储图像类型和分辨率的标题信息。您需要提取标头字节,然后自己解释该信息。或者尝试从header中提取exif信息(但不是每张图片都有EXIF信息)

标签: sql oracle plsql blob oracle12c


【解决方案1】:

BLOB 是二进制数据 - 它本质上没有格式(例如 JPEG/PNG/BMP),因此不是隐含的图像,询问其宽度/高度是没有意义的。

您需要做的是将二进制数据(BLOB)从其(未知)二进制格式(即 JPG/PNG/BMP/等)中取出,并使用图像阅读器从文件的元数据中读取尺寸。数据(因此您不必加载整个文件)。

您可以编写一个 Java 类,该类具有一个函数,该函数采用 BLOB/二进制流和图像格式,然后使用 ImageIOImageReaderImageInputStream(例如,作为我在阅读时发现的第一个命中二进制数据中的图像;将有其他解决方案/库)从标题 [1, 2] 中提取尺寸并返回。

然后,要将该类加载到 Oracle 数据库中,请使用 loadjava utilityCREATE OR REPLACE AND COMPILE JAVA SOURCEexample 用于解压缩存储在 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 数据库中未经测试,因为我目前手头没有实例。)

【讨论】:

  • 非常感谢 MT0,非常感谢您非常全面的回答。
  • @BarbarosÖzhan 更新了一些示例代码 - 它尚未在数据库中进行测试,但希望它能够工作(或者至少让您知道前进的方向)。
【解决方案2】:

@MT0 的答案是假设这是一个需要继续推进的过程。

假设您尚未使用 19.1,如果这只是临时/短期要求,您可以create an ORDImage from the BLOB。假设图像是ORDImage 可以理解的文件类型之一(实际上,基本上包括普通用户上传的任何内容),构造函数可以解析图像并提取高度和宽度等属性然后您可以查询。它还提供了多种操作图像的方法(缩放/旋转/等)

不幸的是,ORDImage 在 Oracle 18 中已被弃用,我相信它已在 Oracle 19 中被删除,因此您不想再使用它来编写您将永久依赖的代码.但是,如果您只是想获得一份临时报告或进行短期数据修复,这可能比查找、加载和使用 Java 图像处理库更容易。

【讨论】:

  • 是的,正如你提到的贾斯汀,我不在 19.1(而是 12.1.0.2)。非常感谢您的全面回答,我将首先尝试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-21
  • 2017-05-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多