1

Support for Oracle Multimedia was dropped in Oracle 19c, so my code to extract dimensions from a JPEG image is throwing an error. Is there a workaround to this issue?

For Oracle 12, my code looked like this:

    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;
Zeda
  • 382
  • 4
  • 13

1 Answers1

2

Based on code found in a response to "Getting Image size of JPEG from its binary" (I'm not sure which language), I came up with this procedure:

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;

This will throw an error if the directory is invalid or the file can't be opened. If the outputs are NULL, then there was some other issue.

It's probably not the most efficient or elegant code (I'm not a pro with PL/SQL [yet!]), but it works. Here is an example usage:

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;
/

This ought to return something like

800 x 200  8  3

Edit: Removed unused variable.

Zeda
  • 382
  • 4
  • 13