PL/SQL 获取 JPEG 图像的尺寸

问题描述

Oracle 19c 中取消了对 Oracle Multimedia 的支持,因此我从 JPEG 图像中提取尺寸的代码引发了错误。这个问题有解决方法吗?

对于 Oracle 12,我的代码如下所示:

    BEGIN
        img := ORDSYS.ORDImage.init('FILE',my_dir,my_img_name);
        img.setProperties();
        w := img.getWidth();
        h := img.getHeight();
    EXCEPTION
        WHEN OTHERS THEN
            w := NULL;
            h := NULL;
    END;

解决方法

基于在 response to "Getting Image size of JPEG from its binary" 中找到的代码(我不确定是哪种语言),我想出了这个程序:

PROCEDURE p_jpegstats(directory_in IN  VARCHAR2,filename_in  IN  VARCHAR2,height_out   OUT INTEGER,width_out    OUT INTEGER,bpc_out      OUT INTEGER,-- bits per channel
                      cps_out      OUT INTEGER   -- colors per component
                     ) IS
    file    bfile;
    pos     INTEGER:=1;
    h       VARCHAR2(4);
    w       VARCHAR2(4);
    mrkr    VARCHAR2(2);
    len     VARCHAR2(4);
    bpc     VARCHAR2(2);
    cps     VARCHAR2(2);

    --  Declare a quick helper procedure for readability
    PROCEDURE next_byte(buf out varchar2,amt INTEGER:=1) IS
        cnt     INTEGER;
    BEGIN
        cnt := amt;
        dbms_lob.read(file,cnt,pos,buf);
        pos := pos + cnt;
    END next_byte;
BEGIN
-- This code is based off of code found here: https://stackoverflow.com/a/48488655/3303651

-- Open the file
    file := bfilename(directory_in,filename_in);
    dbms_lob.fileopen(file);

-- Init the output variables in case something goes awry.
    height_out := NULL;
    width_out  := NULL;
    bpc_out    := NULL;
    cps_out    := NULL;

    LOOP
    BEGIN
        LOOP
            next_byte(mrkr);
            EXIT WHEN mrkr <> 'FF';
        END LOOP;
        CONTINUE WHEN mrkr = 'D8';  -- Start of image (SOI)
        EXIT WHEN mrkr = 'D9';      -- End of image (EOI)
        CONTINUE WHEN mrkr BETWEEN 'D0' AND 'D7';
        CONTINUE WHEN mrkr = '01';  -- TEM
        next_byte(len,2);
        IF mrkr = 'C0' THEN
            next_byte(bpc);    -- bits per channel
            next_byte(h,2);   -- height
            next_byte(w,2);   -- width
            next_byte(cps);    -- colors per component
            EXIT;
        END IF;
        pos := pos + to_number(len,'XXXX') - 2;
    EXCEPTION WHEN OTHERS THEN EXIT; END;
    END LOOP;

-- Write back the values we found
    height_out := to_number(h,'XXXX');
    width_out  := to_number(w,'XXXX');
    bpc_out    := to_number(bpc,'XX');
    cps_out    := to_number(cps,'XX');

-- close out the file
    dbms_lob.fileclose(file);
END p_jpegstats;

如果目录无效或无法打开文件,这将引发错误。如果输出为 NULL,则说明存在其他问题。

它可能不是最有效或最优雅的代码(我不是 PL/SQL 的专家 [还!]),但它有效。这是一个示例用法:

DECLARE
    h       INTEGER;
    w       INTEGER;
    bpc     INTEGER;
    cps     INTEGER;
BEGIN
    p_jpegstats('MY_DIR','my_image.jpg',h,w,bpc,cps);
    DBMS_OUTPUT.PUT_LINE(w || ' x ' || h || '  ' || bpc || '  ' || cps);
END;
/

这应该返回类似

800 x 200  8  3

编辑:删除了未使用的变量。