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