确定 BLOB 的高度和宽度
Determine the Height and the Width of a BLOB
我发现有些人的图片文件是横向的,而在我们的数据库中他们应该都是纵向的。 因此,我需要确定哪个文件的宽度大于其高度。
我想知道是否有任何方法可以获取 BLOB
类型列的 height
和 width
,例如 dbms_lob.getlength
函数,其中 returns 数字CLOB
/BLOB
列中的字符(字节)数。
A BLOB
是二进制数据 - 它本质上没有格式(例如 JPEG/PNG/BMP),因此不是隐含的图像并询问它的 width/height 是做什么的没有意义。
您需要做的是将二进制数据(BLOB)从其(未知)二进制格式(即 JPG/PNG/BMP/etc。)中提取出来,并使用图像 reader 从中读取尺寸文件的元数据(因此您不必加载整个文件)。
您可以编写一个 Java class 的函数,该函数接受 BLOB/binary 流和图像格式,然后使用 ImageIO or ImageReader & ImageInputStream (for example, as the first hits I found on reading images from binary data; there will be other solutions/libraries) extract the dimensions from the header [1, 2] 和 return 它。
然后,要将 class 加载到 Oracle 数据库中,请使用 loadjava
utility or CREATE OR REPLACE AND COMPILE JAVA SOURCE
( 解压缩存储在 Oracle BLOB 中的压缩字符串)。
然后编写一个 SQL 函数来包装 Java 实现,以便它将 BLOB 传递给 Java 函数并且 returns 宽度或高度 (或包含两个值的结构)。
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 的答案是假设这是一个需要继续前进的过程。
假设您还没有使用 19.1,并且如果这只是临时/短期要求,您可以 create an ORDImage
from the BLOB
。假设图像是 ORDImage
理解的文件类型之一(实际上,这基本上将包括普通用户上传的任何内容),构造函数可以解析图像并提取高度等属性然后你可以查询的宽度。它还提供了多种操作图像的方法(缩放/旋转/等)
不幸的是,ORDImage
已在 Oracle 18 中弃用,我相信它已在 Oracle 19 中删除,因此您不想再使用它来编写您将要编写的代码永久依赖。不过,如果您只是想获取临时报告或进行短期数据修复,这可能比查找、加载和使用 Java 图像处理库更容易。
我发现有些人的图片文件是横向的,而在我们的数据库中他们应该都是纵向的。 因此,我需要确定哪个文件的宽度大于其高度。
我想知道是否有任何方法可以获取 BLOB
类型列的 height
和 width
,例如 dbms_lob.getlength
函数,其中 returns 数字CLOB
/BLOB
列中的字符(字节)数。
A BLOB
是二进制数据 - 它本质上没有格式(例如 JPEG/PNG/BMP),因此不是隐含的图像并询问它的 width/height 是做什么的没有意义。
您需要做的是将二进制数据(BLOB)从其(未知)二进制格式(即 JPG/PNG/BMP/etc。)中提取出来,并使用图像 reader 从中读取尺寸文件的元数据(因此您不必加载整个文件)。
您可以编写一个 Java class 的函数,该函数接受 BLOB/binary 流和图像格式,然后使用 ImageIO or ImageReader & ImageInputStream (for example, as the first hits I found on reading images from binary data; there will be other solutions/libraries) extract the dimensions from the header [1, 2] 和 return 它。
然后,要将 class 加载到 Oracle 数据库中,请使用 loadjava
utility or CREATE OR REPLACE AND COMPILE JAVA SOURCE
(
然后编写一个 SQL 函数来包装 Java 实现,以便它将 BLOB 传递给 Java 函数并且 returns 宽度或高度 (或包含两个值的结构)。
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 的答案是假设这是一个需要继续前进的过程。
假设您还没有使用 19.1,并且如果这只是临时/短期要求,您可以 create an ORDImage
from the BLOB
。假设图像是 ORDImage
理解的文件类型之一(实际上,这基本上将包括普通用户上传的任何内容),构造函数可以解析图像并提取高度等属性然后你可以查询的宽度。它还提供了多种操作图像的方法(缩放/旋转/等)
不幸的是,ORDImage
已在 Oracle 18 中弃用,我相信它已在 Oracle 19 中删除,因此您不想再使用它来编写您将要编写的代码永久依赖。不过,如果您只是想获取临时报告或进行短期数据修复,这可能比查找、加载和使用 Java 图像处理库更容易。