Benutzer-Werkzeuge

Webseiten-Werkzeuge


prog:oracle_multimedia_12c

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
prog:oracle_multimedia_12c [2019/01/13 10:05]
gpipperr
prog:oracle_multimedia_12c [2019/01/13 10:06] (aktuell)
gpipperr [Multimedia in der Oracle Datenbank 12c / 18c - Bildbearbeitung in PL/SQL]
Zeile 1: Zeile 1:
 +=====Multimedia in der Oracle Datenbank 12c / 18c - Bildbearbeitung in PL/SQL====
  
 +**Start: 05.2017**
 +
 +**12c, Basis Funktion aber schon ab Oracle 8i seit 1998 verfügbar**
 +
 +
 +
 +**18c** 
 +<note important>Oracle Multimedia is deprecated in Oracle Database Release 18c, and may be desupported in a future release. Oracle recommends that you stop using deprecated features as soon as possible.
 +</note>
 +=> https://docs.oracle.com/en/database/oracle/oracle-database/18/imurg/index.html
 +
 +
 +
 +**Ziel:** Mit der Oracle Multimedia Option Bilder in der Datenbank bearbeiten und in APEX darstellen
 +
 +
 +Mit Oracle Multimedia 12c (seit 8i / 11g noch unter dem Namen Oracle interMedia vertrieben) steht dem Apex Entwickler ein reichhaltiges Werkzeug für das Metadaten Handling von Bild und Ton Daten in der Oracle Datenbank zur Verfügung.
 +
 +Mit der Oracle Multimedia 12c lassen sich die Metadaten und Attribute von Multimedia Daten lesen und setzen und viele Eigenschaften von Bild Dateien, wie Größe, Rotation, Schärfe, Kontrast etc., direkt in der Datenbank bearbeiten. 
 +
 +Bestimmte Eigenschaften wie die Farbe eines Bildes lassen sich aus den binären Daten des Bildes ermitteln und werden damit auch suchbar.
 +
 +Mit diesem umfangreichen Set an Hilfsmitteln lassen sich mit PL/SQL auch komplexere Aufgabenstellung in Oracle Apex relativ einfach integrieren.
 +
 +Übersicht über die Elemente in der Datenbank:
 +
 +{{ :prog:apex:oracle_multimedia_overview_v01.png | Oracle Multimedia in der Datenbank}}
 +
 +
 +
 +Die Verarbeitung der Daten wird über Datenbank Objekt Typen durchgeführt:
 +
 +  * Bild Daten => ORDImage
 +  * Audio Daten => ORDAudio
 +  * Heterogene Daten => ORDDoc
 +  * Video Daten => ORDVideo
 +
 +
 +Die Speicherung in einer Datenbank Tabelle  kann ebenfalls mit diesem Typen durchgeführt werden.
 +
 +<fc #008000>Vorteil der Speicherung als Objekt Type:</fc>
 +  * Daten und Eigenschaften über ein Objekt ansprechbar
 +  * Schlankes Datenmodel
 +<fc #800000>
 +Nachteil der Speicherung als Objekt Type:</fc>
 +  * Laderoutienen etwas komplexer
 +  * Gefahr von Bugs
 +  * Daten müssen für andere Tools immer extrahiert werden
 +
 +
 +Übersicht über möglichen Feature (11g) => http://www.oracle.com/technetwork/database/database-technologies/multimedia/overview/multimedia11gr2-featover-128418.pdf
 +----
 +
 +====Installation ====
 +
 +Siehe https://docs.oracle.com/database/121/IMURG/ap_instl_upgrd.htm
 +
 +
 +Benötigt die JAVAVM, XDB, XML Option
 +
 +Legt folgende User an:
 +  * ORDSYS
 +  * ORDPLUGINS  ( hier können eigene Erweiterungen abgelegt werden)
 +  * SI_INFORMTN_SCHEMA
 +  * ORDDATA
 +  * MDSYS -  Oracle Multimedia Locatorset 
 +
 +Prüfen ob die Option auch korrekt installiert wurde:
 +<code sql>
 +SYS>execute sys.validate_ordim;
 +
 +PL/SQL procedure successfully completed.
 +
 +
 +SYS>select version, status from dba_registry where comp_id='ORDIM';
 +
 +VERSION                                            STATUS
 +------------------------------------------------- --------
 +12.1.0.2.0                                         VALID
 +</code>
 +
 +
 +----
 +
 +==== Eine Beispiel Anwendung ====
 +
 +Für ein Bautagebuch sollen auch die anfallenden Bilddaten gespeichert werden.
 +
 +=== Einen User anlegen ===
 +
 +Als SYS:
 +<code sql>
 +-- create the user
 +create user conbook identified by conbook default tablespace USERS temporary tablespace TEMP;
 +alter user conbook quota unlimited on USERS;
 +
 +grant connect, resource to conbook;
 +
 +
 +-- create the info Archive DIRECTORY
 +create or replace directory IMG_ARCHIVE as 'C:\entwicklung\work\OracleMultiMedia\99-Images';
 +grant read,write on directory IMG_ARCHIVE to conbook;
 +</code>
 +
 +Darauf achten das der Oracle User unter dem die 12c DB läuft, in meinen Fall der User ORARUN, auch die entsprechenden Rechte auf das Verzeichnis besitzt!
 +
 +
 +Im Dateisystem unter "C:\entwicklung\work\OracleMultiMedia\99-Images" liegen in meinen Testfall nun 13 Bilder, 1.jpg bis 13.jpg. Diese werden später über das Directory Objekt in die Datenbank geladen.
 +
 +
 +=== Tabelle für die Bilddaten ===
 +
 +Für das Speichern der Bilddaten wird der Datentyp ORDSYS.ORDIMAGE eingesetzt.
 +
 +
 +ORDSYS.ORDIMAGE hat die folgenden "Felder":
 +<code>
 +  -------------------
 +  -- TYPE ATTRIBUTES
 +  -------------------
 +  source              ORDSource,
 +  height              INTEGER,
 +  width               INTEGER,
 +  contentLength       INTEGER,
 +  fileFormat          VARCHAR2(4000),
 +  contentFormat       VARCHAR2(4000),
 +  compressionFormat   VARCHAR2(4000),
 +  mimeType            VARCHAR2(4000),
 +
 +</code>
 +
 +Als User conbook
 +<code sql>
 +CREATE TABLE CONBOOK.CON_IMAGES
 +(
 +  ID       NUMBER(13),
 +  name     VARCHAR2(256)                        NOT NULL,
 +  remarks  VARCHAR2(4000),
 +  img      ORDSYS.ORDIMAGE,
 +  preview  ORDSYS.ORDIMAGE
 +)
 +LOB(img.source.localData)     STORE AS SECUREFILE
 +LOB(preview.source.localData) STORE AS SECUREFILE
 +;
 +
 +
 +ALTER TABLE CONBOOK.CON_IMAGES ADD (
 +  CONSTRAINT CON_IMAGES_PK
 +  PRIMARY KEY
 +  (ID)
 +  ENABLE VALIDATE);
 +</code>
 +
 +=== Daten in die Tabelle laden ===
 +
 +Einfache Laderoutine:
 +
 +<code sql>
 +  CREATE OR REPLACE procedure loadConImg (p_id number , p_name varchar2 , p_remark varchar2)
 + as
 +   v_img_orig ORDSYS.ORDImage;
 +   v_img_preview ORDSYS.ORDImage;
 +   v_ctx RAW(64) := NULL;
 +  BEGIN
 +    -- save metadata and return a referenz on the img object
 +    insert into CON_IMAGES (ID, NAME, REMARKS,img,preview) 
 +      values (p_id,p_name,p_remark,ORDImage(),ORDSYS.ORDImage.init())
 +      RETURNING img INTO v_img_orig;
 +
 +    
 +    -- read the image data to the temporary object
 +  v_img_orig.importFrom(v_ctx,'file','IMG_ARCHIVE',p_name);
 +         
 +    -- insert the temporary object into the image tabee    
 +    UPDATE CON_IMAGES SET img=v_img_orig WHERE id=p_id;
 +    commit;
 +        
 +     --create trumbnail image
 +    SELECT img.IMG,img.PREVIEW
 +        INTO v_img_orig,v_img_preview
 +        FROM CON_IMAGES img
 +    WHERE img.id=p_id
 +         FOR UPDATE;
 +         
 +    begin
 +        -- create the preview image
 +        v_img_orig.processCopy('fileFormat=JFIF CompressionQuality=MAXINTEGRITY  maxScale=126 126',v_img_preview);
 +        -- only copy
 +        --v_img_orig.copy(v_img_preview);        
 +    EXCEPTION
 +        WHEN ORDSYS.ORDImageExceptions.NULL_DESTINATION THEN
 +            DBMS_OUTPUT.PUT_LINE('The destination is null');
 +        WHEN ORDSYS.ORDImageExceptions.DATA_NOT_LOCAL THEN
 +            DBMS_OUTPUT.PUT_LINE('Data is not local');
 +        WHEN ORDSYS.ORDImageExceptions.NULL_LOCAL_DATA THEN
 +            DBMS_OUTPUT.PUT_LINE('dest.source.localData attribute is null');
 +        when others then
 +             DBMS_OUTPUT.PUT_LINE('Find this SQL ERROR:: '|| SQLCODE || ' - '||SQLERRM);    
 +    end;
 +    
 +    UPDATE CON_IMAGES SET preview=v_img_preview WHERE id=p_id;
 +    commit;
 + 
 +  END;
 +/
 +
 +</code>
 +
 +
 +Damit das Image Objekt auch verwendet werden kann, muss es zuvor initialisiert werden.
 +
 +Das kann ohne weitere Eigenschaften "leer" erfolgen mit **ORDSYS.ORDImage.init()** für das am Anfang noch leere Preview Image oder mit folgenden Konstruktor **ORDImage('file','IMG_ARCHIVE',p_name)** um eine BFile Referenz auf das Bild im  DB Direktory laden zu können oder mit eben als BLOB direkt in die Datenbank laden mit **v_img_orig.importFrom(v_ctx,'file','IMG_ARCHIVE',p_name);**.
 +
 +Beispiel für das Laden mit der obigen Routine über SQL*Plus:
 +<code sql>
 +delete CON_IMAGES;
 +
 +commit;
 +
 +set serveroutput on
 +
 +begin
 +    for i in 1 .. 13
 +    loop
 +      loadConImg ( p_id     => i
 +                 , p_name   => to_char(i)||'.JPG'
 +                 , p_remark => 'This is image '||to_char(i));
 +    end loop;
 +end;
 +
 +
 +select * from CON_IMAGES;
 +</code>
 +
 +=== Objekt Eigenschaften von ORDSYS.ORDImage ausgeben ===
 +
 +Die wichtigsten Metadaten eines Bildes werden in dem Objekt ORDSYS.ORDImage als Attribute gespeichert.
 +
 +Ausgeben mit:
 +<code sql>
 +set serveroutput on
 +
 +DECLARE
 + v_image ORDSYS.ORDImage;
 +BEGIN
 + SELECT img 
 +    INTO v_image
 +   FROM CON_IMAGES img
 +  WHERE id  = 1; 
 + 
 + DBMS_OUTPUT.PUT_LINE('image width        = ' || v_image.getWidth());
 + DBMS_OUTPUT.PUT_LINE('image height       = ' || v_image.getHeight());
 + DBMS_OUTPUT.PUT_LINE('image size         = ' || v_image.getContentLength());
 + DBMS_OUTPUT.PUT_LINE('image file type    = ' || v_image.getFileFormat());
 + DBMS_OUTPUT.PUT_LINE('image type         = ' || v_image.getContentFormat());
 + DBMS_OUTPUT.PUT_LINE('image compression  = ' || v_image.getCompressionFormat());
 + DBMS_OUTPUT.PUT_LINE('image mime type    = ' || v_image.getMimeType());
 + 
 +END;
 +/
 +
 +</code>
 +
 +Bzw. in SQL ausgeben:
 +
 +<code sql>
 +select   i.id
 +       , i.img.getHeight() height
 +       , i.img.getWidth() width
 +       , i.img.getMimetype() mimetype
 +       , i.img.getFileFormat() fileformat
 +       , i.img.getContentLength() length
 +from CON_IMAGES i ORDER BY i.id
 +/
 +</code>
 +
 +===EXIF Daten aus dem Bildern auslesen===
 +
 +
 +Beispiel:
 +<code sql>
 +set serveroutput on
 +
 +DECLARE 
 +  v_image     ORDSYS.ORDImage; 
 +  v_metadata  XMLSequenceType; 
 +BEGIN 
 +
 +  SELECT img 
 +    INTO v_image
 +   FROM CON_IMAGES img
 +  WHERE id  = 1; 
 + 
 +  v_metadata := v_image.getMetadata('ALL'); 
 + 
 +  -- print the namespace of each metadata document
 +  FOR i in 1..v_metadata.count LOOP
 +    DBMS_OUTPUT.PUT_LINE('namespace: ' || v_metadata(i).getNamespace() );
 +     DBMS_OUTPUT.PUT_LINE('-----------------------');
 +    DBMS_OUTPUT.PUT_LINE('CLOB Value: ' || v_metadata(i).getCLOBVal());    
 +  END LOOP; 
 +  
 + 
 +  EXCEPTION 
 +  WHEN ORDSYS.ORDImageExceptions.NULL_LOCAL_DATA THEN 
 +    DBMS_OUTPUT.PUT_LINE('source local data is null'); 
 +  WHEN ORDSYS.ORDImageExceptions.NULL_SOURCE THEN 
 +    DBMS_OUTPUT.PUT_LINE('source is null'); 
 +  WHEN OTHERS THEN
 +    RAISE;
 +END; 
 +/
 +</code>
 +
 +Am einfachsten wird das am Anfang beim Laden gelesen und dann gleich in einer eigenen CLOB / XML Spalte gespeichert um später weiter verarbeitet werden zu können.
 +
 +
 +
 +----
 +
 +----
 +
 +
 +
 +====APEX 5.1 Integration ====
 +
 +=== Ein Bild darstellen ===
 +
 +In Apex 5 kann sehr einfach ein Bild auf ein auf einer Seite über ein Page Item vom Typ **"Display Image"** dargestellt werden.
 +
 +Dazu muss aber das Bild in einer BLOB Spalte vorliegen!
 +
 +In unseren Fall liegt das Bild aber in einem Objekt vom Typ  ORDSYS.ORDImage, d.h. wir müssen einfach nur den BLOB in dem Objekt auslesen.
 +
 +
 +Als **"Based on"** wählen wir **"Blob Column returned by SQL Statement"** .
 +
 +SQL:
 +<code sql>
 +SELECT img.preview.source.localData     
 +        FROM CON_IMAGES img
 +    WHERE img.id=1
 +</code>
 +
 +{{ :prog:apex:apex_display_image_page_item_v01.png | Display Image with a page Item}}
 +----
 +
 +=== Bilder in einem Bericht darstellen ===
 +
 +Leider geht es nicht so einfach mit einen "Interactive Report", wird einfach nur die BLOB Spalte im Bericht referenziert wird nur ein "[unsupported data type]" angezeigt. 
 +
 +
 +Wird nun die Image Spalte auf den Typ  "Display Image" gesetzt, brauchen wir einen View auf unsere Daten um die BLOB Spalte im Objekt in der Apex Maske auswählen zu können, Apex muss das selber erkennen, wir können die Spalte nicht mit "img.source.localData" einfach selber angeben.
 +
 +SQL für die BLOB View:
 +<code sql>
 +CREATE OR REPLACE VIEW CONBOOK.V_CON_IMAGES_BLOB
 +AS 
 +SELECT   ID
 +      , NAME
 +      , img.img.getMimetype() mimetype      
 +      , REMARKS
 +      , img.img.source.localData IMG
 +      , img.PREVIEW.source.localData as PREVIEW
 +        FROM CON_IMAGES img;
 +</code>
 +
 +{{ :prog:apex:apex_display_image_interactiv_report_v01.png | Type "Display Image" to show image in interactive report}}
 +
 +
 +
 +Fehler <fc #800000>"ORA-06502: PL/SQL: numeric or value error: character to number conversion error"</fc> 
 +
 +In der eigentlichen Berichtsabfrage darf nicht der BLOB des Bildes, sondern die Größe des Bildes muss referenziert werden.
 +
 +<code sql>
 +SELECT  img.preview.getContentLength()  as preview_image
 +      , ID
 +      , NAME
 +      , REMARKS 
 + FROM CON_IMAGES img order by ID
 +</code>
 +
 +Und schon funktioniert es!
 +
 +Siehe auch => http://www.oralytics.com/2016/09/how-to-display-blob-image-in-apex-report.html
 +
 +----
 +
 +=== Bild bearbeiten===
 +
 +
 +Über die Methode http://docs.oracle.com/database/121/AIVUG/ch_imgref.htm#AIVUG80485 **process()** kann das Bild Objekt direkt in der Datenbank bearbeitet werden.
 +
 +
 +Dazu wird in APEX einfach diese Funktion als Source für ein Image Display Item aufgerufen und dabei das entsprechende Kommando übergeben.
 +
 +In der folgenden Routine wird die Watermark Funktion verwandt um im Fehlerfall den SQL Fehler  direkt in das Bild zu schreiben.
 +
 +Achtung! Hier ist noch ein böser Bug! der Temporäre Speicher wird nicht freigeben wenn die Watermark Funktion verwendet wird! 
 +
 +Beispiel Code um ein Bild zu verarbeiten:
 +<code sql>
 +create or replace function imgConverter(p_img_id number,p_command varchar2 default 'maxScale 400 400')
 +return blob
 +is
 +   v_img_orig ORDSYS.ORDImage;
 +   v_img_work ORDSYS.ORDImage;
 +   v_img_blob_error blob;
 +   v_img_blob blob;
 +   
 +   v_command varchar2(4000):=p_command;
 +   
 +   
 +   --- Error handling
 +   v_watermark_prop ORDSYS.ORD_STR_LIST;   
 +   v_message varchar2(32000);
 +   v_error boolean:=true;
 +   v_logging varchar2(2000);
 +   
 +begin
 +    -- get the original image
 +    SELECT img.IMG
 +      INTO v_img_orig
 +      FROM CON_IMAGES img
 +    WHERE img.id=p_img_id;
 +   
 +    -- init the blob
 +     dbms_lob.createtemporary(v_img_blob     , true, DBMS_LOB.SESSION);
 +     dbms_lob.createtemporary(v_img_blob_error, true, DBMS_LOB.SESSION);
 +     
 +   begin
 +        
 +        ORDSYS.ORDImage.processCopy( 
 +             imageblob  => v_img_orig.source.localData
 +            ,command    => v_command
 +            ,dest       => v_img_blob);
 +        
 +        v_error:=false;
 +    
 +    EXCEPTION
 +        WHEN ORDSYS.ORDImageExceptions.NULL_DESTINATION THEN
 +            v_message:='The destination is null';
 +            v_error:=true;
 +        WHEN ORDSYS.ORDImageExceptions.DATA_NOT_LOCAL THEN
 +            v_message:='Data is not local';
 +            v_error:=true;
 +        WHEN ORDSYS.ORDImageExceptions.NULL_LOCAL_DATA THEN
 +            v_message:='dest.source.localData attribute is null';
 +            v_error:=true;
 +        when others then
 +            v_message:='Find this SQL ERROR:: '|| SQLCODE || ' - '||SQLERRM;    
 +            v_error:=true;
 +    end;
 +     
 +     if v_error then     
 +         -- print the error into the image as Watermark
 +         --'position=bottomright'
 +         v_watermark_prop := ordsys.ord_str_list(
 +                  'font_name=Arial',
 +                  'font_style=bold',
 +                  'font_size=20',
 +                  'text_color=red',
 +                  'position_x=10',
 +                  'position_y=20',
 +                  'transparency=1'
 +                );
 +
 +        
 +        dbms_lob.createtemporary(v_img_blob_error, true, DBMS_LOB.SESSION);       
 +         
 +        ORDSYS.ORDImage.applyWatermark(
 +                 imageBlob              => v_img_orig.source.localData   
 +                ,added_text           =>  substr(v_message,1,100)
 +                ,dest                  => v_img_blob_error    
 +                ,logging               => v_logging    
 +                ,watermark_properties => v_watermark_prop
 +            );
 +        v_img_work:=ORDSYS.ORDImage(v_img_blob_error);
 +        -----------------------------------------
 +        -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1    
 +        -- dummy process to free memory
 +        -- BUG with applyWatermark !!
 +        -- if you call ORDSYS.ORDImage.processCopy the memory will be freed sucessfull
 +        -- strange behavior
 +        -- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1
 +        -----------------------------------------
 +        ORDSYS.ORDImage.processCopy( 
 +             imageblob  => v_img_orig.source.localData
 +            ,command    => 'maxScale 200 200'
 +            ,dest       => v_img_blob);
 +     else
 +        v_img_work:=ORDSYS.ORDImage(v_img_blob);
 +     end if;   
 +     
 +    
 +     
 +     -- Free the temporary LOB
 +     --DBMS_LOB.CLOSE(v_img_blob);
 +     DBMS_LOB.FREETEMPORARY(v_img_blob_error);
 +     DBMS_LOB.FREETEMPORARY(v_img_blob);
 +
 +    
 +    
 +     return v_img_work.source.localData ; -- UTL_RAW.CAST_TO_RAW(v_logging); --
 +     
 +    
 +     
 +end imgConverter; 
 +</code>
 +
 +Demnächst Mehr
 +
 +== Problem mit ORDImage.applyWatermark - data cartridge error IMG-00003: exhausted memory while processing image IMG-003: out of memory in (native) awt jpeg decode- ==
 +
 +Da ich ja im obigen Code den BLOB nicht mehr so wirklich freigeben kann, laufen ich schnell nach ein paar Versuchen bei den obigen Oracle Fehler.... daher auch das etwas umständliche Kopieren der LOB's, leider hat das nicht wirklich geholfen, nach 8 Versuchen ist Schluss.... aber nur wenn die Methode **ORDImage.applyWatermark** betroffen ist!
 +
 +<code>
 +ERROR:
 +ORA-29400: data cartridge error
 +IMG-00003: exhausted memory while processing image
 +IMG-003: out of memory in (native) awt jpeg decode
 +ORA-06512: at "ORDSYS.ORDIMERRORCODES", line 75
 +ORA-06512: at "ORDSYS.ORDIMERRORCODES", line 65
 +ORA-06512: at "ORDSYS.ORDIMG_PKG", line 471
 +ORA-06512: at "ORDSYS.ORDIMAGE", line 1623
 +ORA-06512: at "CONBOOK.IMGCONVERTER", line 67
 +ORA-06512: at line 1
 +</code>
 +
 +Erste Lösungen:
 +
 +Java Pool Size vergrößert
 +
 +<code sql>
 +alter system set java_pool_size=256M scope=memory sid='*';
 +
 +-- kontrolle der aktuellen Verwendung mit:
 +
 +select * from v$javapool;
 +
 +</code>
 +
 +Dann funktioniert es etwas länger, Speicher läuft trotzdem voll .....
 +
 +Laut Support Node => "ORDSYS.ORDImage Methods Fail Or Slow Down After Extended Processing; Consume Increasing Amounts Of Memory (Doc ID 267880.1)" ist das Problem seit längeren evlt. bekannt, hier hilft wohl nur einen eigenen Bug dazu für 12c bei Oracle neu zu öffnen.
 +
 +Ärgerlich ...
 +
 +
 +<fc #008000>**Solution**</fc>
 +
 +Nach dem Aufruf von **ORDSYS.ORDImage.applyWatermark** nochmals eine gültige Operation mit **ORDSYS.ORDImage.processCopy** ausführen um den Stack der Session wieder richtig aufzuräumen.
 +
 +Funktioniert, ist aber nicht sehr schön ..... 8-O
 +
 +
 +
 +----
 +
 +=== Bilder hochladen ===
 +
 +Wie aber nun die Bilder über die Weboberfläche hochladen?
 +
 +
 +In APEX 5 wird intern die Tabelle APEX_APPLICATION_TEMP_FILES für das hochladen von Dateien verwendet. 
 +
 +
 +Aus dieser Tabelle holen wir uns die Daten und schreiben die Daten in unsere Bild Tabelle.
 +
 +
 +Danach nicht vergessen das Bild in der APEX_APPLICATION_TEMP_FILES auch wieder zu löschen ( View auf wwv_flow_file_objects$)!
 +
 +
 +Um die Datei auszuwählen ein Page Item vom Typ "File Browse" anlegen (in diesem Beispiel mit dem Namen P1_FILESELECTION )
 +
 +Einen Submit Button auf der Page anlegen ( Action "Submit Page")
 +
 +Für die eigentliche Logik des Umkopieren der Daten dann ein Stück PL/SQL verwenden um die Daten in unsere Struktur einzulesen.
 +
 +
 +
 +Der PL/SQL code für den "After Submit" Process der Apex Seite:
 +<code sql>
 +declare
 +  v_file_count pls_integer:=0;
 +  
 +  v_img_orig ORDSYS.ORDImage;
 +  v_img_preview ORDSYS.ORDImage;
 +  
 +  v_id CON_IMAGES.id%type;
 +  
 +  v_message varchar2(4000):='Prozessing File Insert'||'<br/>';
 +  
 +begin 
 +    if :P1_FILESELECTION is not null then
 +    
 +     v_message:= v_message||' Name of P1_FILESELECTION is '||:P1_FILESELECTION||'<br/>';
 +
 +        select count(ID) into v_file_count
 +            from apex_application_temp_files
 +            where name = :P1_FILESELECTION;
 +
 +        if v_file_count > 0  then
 +              for rec in (select
 +                    id,
 +                    application_id,
 +                    name,
 +                    filename,
 +                    mime_type,
 +                    created_on,
 +                    blob_content
 +                from apex_application_temp_files where name = :P1_FILESELECTION ) loop
 +                   begin
 +                   
 +                    v_message:= v_message||' Read Image with filename '||rec.filename||'<br/>'; 
 +                       insert into CON_IMAGES (ID, NAME, REMARKS,img,preview) 
 +                        values ( CON_IMAGES_SEQ.nextval
 +                                , rec.filename
 +                                , rec.filename ||' Mime type'||rec.mime_type||' Uploaded at'||to_char(rec.created_on,'dd.mm.yyyy hh24:mi')
 +                                , ORDSYS.ORDImage.init()
 +                                , ORDSYS.ORDImage.init() )
 +                        RETURNING id,img INTO v_id,v_img_orig;
 +
 +                        v_img_orig:=ORDSYS.ORDImage(rec.blob_content);
 +
 +                         UPDATE CON_IMAGES SET img=v_img_orig WHERE id=v_id;
 +                        commit;
 +
 +                            --create trumbnail image
 +                        SELECT img.IMG,img.PREVIEW
 +                            INTO v_img_orig,v_img_preview
 +                            FROM CON_IMAGES img
 +                        WHERE img.id=v_id
 +                             FOR UPDATE;
 +
 +
 +                            -- create the preview image
 +                            v_img_orig.processCopy('fileFormat=JFIF CompressionQuality=MAXINTEGRITY  maxScale=126 126',v_img_preview);
 +                            -- only copy
 +                            --v_img_orig.copy(v_img_preview);        
 +
 +
 +                        UPDATE CON_IMAGES SET preview=v_img_preview WHERE id=v_id;
 +                        commit;
 +
 +                         EXCEPTION
 +                            WHEN ORDSYS.ORDImageExceptions.NULL_DESTINATION THEN
 +                                v_message:=v_message||' The destination is null'||'<br/>';
 +                            WHEN ORDSYS.ORDImageExceptions.DATA_NOT_LOCAL THEN
 +                                 v_message:=v_message||' Data is not local'||'<br/>';
 +                            WHEN ORDSYS.ORDImageExceptions.NULL_LOCAL_DATA THEN
 +                                 v_message:=v_message||' dest.source.localData attribute is null'||'<br/>';
 +                            when others then
 +                                  v_message:=v_message||' Find this SQL ERROR:: '|| SQLCODE || ' - '||SQLERRM;    
 +                        end;
 +
 +                end loop; 
 +                
 +                -- clean the tempfile
 +                begin
 +                    delete apex_application_temp_files  where name = :P1_FILESELECTION;
 +                    commit;
 +                EXCEPTION    
 +                    when others then
 +                       v_message:=v_message||' clean tempfile '|| SQLCODE || ' - '||SQLERRM||'<br/>';    
 +                 end;
 +        end if;
 +    end if; 
 +    
 +    apex_application.g_print_success_message := '<span style="color:yellow">'|| v_message || '</span>';
 +end;
 +</code>
 +
 +
 +----
 +
 +----
 +
 +====Bilder vergleichen ====
 +
 +
 +
 +
 +
 +Wir legen uns daher nun eine Tabelle mit ein paar Basis Bilder an um den Vergleichsalgorithmus zu testen.
 +
 +
 +<code sql>
 +drop table con_img_templates;
 +
 +CREATE TABLE con_img_templates (
 +   ID            NUMBER(13)
 +  ,name          VARCHAR2(256) NOT NULL
 +  ,remarks       VARCHAR2(4000)
 +  ,img_template  ORDSYS.ORDIMAGE
 +  ,signature     ORDSYS.ORDImageSignature
 +)
 +LOB(img_template.source.localData)     STORE AS SECUREFILE
 +;
 + 
 + 
 +ALTER TABLE CONBOOK.con_img_templates ADD (
 +  CONSTRAINT con_img_templates_PK
 +  PRIMARY KEY
 +  (ID)
 +  ENABLE VALIDATE);
 +
 +create sequence CONBOOK.con_img_templates_SEQ;
 +
 +</code>
 +
 +
 +In diese Tabelle laden wir nun ein blaues,rotes,gelbes Bild mit 100*100Pixel.
 +
 +<code sql>
 +CREATE OR REPLACE procedure CONBOOK.loadTemplateImg (p_id number
 +                                       , p_name varchar2
 +                                       , p_remark varchar2)
 + as
 +   
 +   v_img_sig   ORDSYS.ORDImageSignature;
 +   v_img_orig ORDSYS.ORDImage;
 +   v_ctx RAW(4000) := NULL;
 +BEGIN
 +
 +    -- save metadata and return a referenz on the img object
 +    insert into con_img_templates (ID, NAME, REMARKS,img_template,signature) 
 +      values (p_id,p_name,p_remark,ORDImage('file','IMG_ARCHIVE',p_name),ORDImageSignature.init())
 +      RETURNING img_template,signature INTO v_img_orig,v_img_sig;
 +    
 +    -- read the image data to the temporary object
 +    v_img_orig.import(v_ctx);
 +    v_img_sig.generateSignature(v_img_orig);
 +         
 +    -- insert the temporary object into the image tabee    
 +    UPDATE con_img_templates SET img_template=v_img_orig,signature=v_img_sig WHERE id=p_id;
 +    commit;  
 +     
 +END;
 +/
 +</code>
 +
 +Laden:
 +<code sql>
 +delete con_img_templates;
 +
 +commit;
 +
 +set serveroutput on
 +
 +begin
 +  
 +    loadTemplateImg ( p_id     => con_img_templates_SEQ.nextval
 +                 , p_name   => 'gruen.png'
 +                 , p_remark => 'This is image gruen');
 +    
 +    loadTemplateImg ( p_id     => con_img_templates_SEQ.nextval
 +                 , p_name   => 'weiss.png'
 +                 , p_remark => 'This is image weiss');          
 +    
 +    loadTemplateImg ( p_id     => con_img_templates_SEQ.nextval
 +                 , p_name   => 'blau.png'
 +                 , p_remark => 'This is image blau');                      
 +    
 +    loadTemplateImg ( p_id     => con_img_templates_SEQ.nextval
 +                 , p_name   => 'gelb.png'
 +                 , p_remark => 'This is image gelb');     
 +    
 +    loadTemplateImg ( p_id     => con_img_templates_SEQ.nextval
 +                 , p_name   => 'rot.png'
 +                 , p_remark => 'This is image rot');                                          
 +end;
 +
 +
 +select * from con_img_templates;
 +commit;
 +</code>
 +
 +
 +<code sql>
 +alter table con_images add (signature ORDSYS.ORDImageSignature);
 +update con_images set signature=ORDImageSignature.init();
 +</code>
 +
 +Vergleichen über den Score:
 +
 +<code sql>
 +DECLARE
 +     v_i1_img       ORDSYS.ORDImage;
 +     v_i2_img       ORDSYS.ORDImage;
 +     v_i1_img_sig   ORDSYS.ORDImageSignature;
 +     v_i2_img_sig   ORDSYS.ORDImageSignature;
 +     v_score FLOAT;
 +     v_sim float;
 +     v_weight varchar2(256):='color="0.4",texture="0.10",shape="0.3", location="0.2"';
 +     v_name varchar2(255);
 +BEGIN
 +
 +    -- read image
 +    select img,signature,name into  v_i1_img , v_i1_img_sig ,v_name from CON_IMAGES where id =6 for update;
 +
 +     v_i1_img_sig.generateSignature(v_i1_img);
 +
 +    for rec in (select img_template
 +                     ,signature
 +                     ,name from con_img_templates  for update)
 +    loop
 +         -- Compare two images for similarity based on image color:
 +         v_score:=ORDSYS.ORDImageSignature.evaluateScore(v_i1_img_sig, rec.signature,v_weight);
 +         
 +         v_sim:=ORDSYS.ORDImageSignature.ISSIMILAR(v_i1_img_sig, rec.signature, v_weight, 75);
 +         
 +         DBMS_OUTPUT.PUT_LINE('The score for compare '||rec.name||' with image ' ||v_name||' is ' || v_score);
 +         DBMS_OUTPUT.PUT_LINE('The sim score for simalar '||rec.name||' with image ' ||v_name|| 'is ' || v_sim);
 +         DBMS_OUTPUT.PUT_LINE('-----------------');
 +     end loop;
 +     
 +     commit;
 +     
 +END;
 +/
 +
 +</code>
 +
 +see => https://docs.oracle.com/cd/B14117_01/appdev.101/b10829/mm_imgref002.htm#sthref896
 +
 +
 +Um ein Bild zu suchen muss immer zuvor ein Beispiel Bild vorgegeben werden, mit diesem wird verglichen
 +See => https://docs.oracle.com/cd/B14117_01/appdev.101/b10840/mm_cbr.htm#i605493
 +
 +
 +----
 +
 +----
 +
 +
 +==== Quellen ====
 +
 +==Doku==
 +
 +Oracle Multimedia User's Guide 12c => http://docs.oracle.com/database/121/IMURG/toc.htm
 +
 +
 +==Support==
 +
 +  * Information Center: Oracle Multimedia/Oracle interMedia (Doc ID 1546315.2)
 +
 +==Web==
 +  
 +Bücher:
 +
 +  * https://books.google.de/books?id=-dbeFbCswAYC&pg=PA449&lpg=PA449&dq=Average+Color+describes&source=bl&ots=u8NlsKfAes&sig=Q9iPUomZZRusvShAQhEYNEka24Q&hl=en&sa=X&ved=0ahUKEwjvp9X3id3PAhXJK5oKHaezCjYQ6AEINTAE#v=onepage&q=Average%20Color%20describes&f=false
 +  
 +Blogs:
 + 
 +  * https://www.doag.org/formes/pubfiles/6352025/docs/Publikationen/DOAGNews/2014/05-14/2014-05-News-Carsten-Czarski-Bildbearbeitung-in-der-Datenbank.pdf
 +  * http://www.oralytics.com/2016/09/how-to-display-blob-image-in-apex-report.html
 +  * https://storm-petrel.com/orablog/2015/08/31/apex5-upload-blob-with-file-browse/
 +  * http://www.morganslibrary.org/reference/plsql/multimedia_a.html
 +
 +Bild in Apex per Java Script Modal größer darstellen
 +  * http://qaiumer.blogspot.com/2017/08/modal-images-large-image-zoom-from.html
 +
 +
 +==Audio==
 +
 +  * http://vincentdeelen.blogspot.de/2013/09/embedding-media-in-your-apex-application.html
"Autor: Gunther Pipperr"
prog/oracle_multimedia_12c.txt · Zuletzt geändert: 2019/01/13 10:06 von gpipperr