APEX: Viewing Images and Videos from OCI Object Storage

Sydney NurseSydney Nurse
6 min read

I’m not going to answer this question as many of the examples and samples that explore beyond the simple UI calls, seem to involve some level of earnest coding and I’m no developer, so this .. this is not going to be pretty.

About this Post

Somethings in life are easy, simple, quick to understand and even quicker to drop onto a page, others are imagined to be. This article shares a solution that may be out there but I’ve lacked the endurance and skill to find.

This should be easy and there are many examples of accomplishing parts of this process but not a complete one.

I need to show embedded media that is stored on OCI Object Storage, that’s it.

Why is this even a discussion point?

Accessing Object Storage is different. There are many articles, books, discussions on the differences but for me the most poignant is unlike with file storage, you must use an Application Programming Interface (API) to access and manage objects.

OCI APIs typically require Authentication and some granted privileges or Authorisation.

Objects could be stored for Public access but not typical in enterprise environments. Although HTTP protocols and methods are used to manage the objects, the Object Storage service is not a Web or File Server, serving up its content to just anyone.

So, we must consume the API, retrieve our prized object in order to use it in our applications.

APEX and OCI Object Storage

APEX’s more recent releases offer Managing Static Application Files in Remote Storage and there are many posts on leveraging OCI Object Storage and even a LiveLab with step by step on how to Use Object Storage to Store Files in an APEX Application.

The Better File Storage in Oracle Cloud blog post is probably one of the most view, copied and reposted and it all lovely until you need to upload, download or delete an object.

💡
Hello, PL/SQL API !

I am hoping that after reading or following the above, you are well on your way to uploading / downloading objects using the PL/SQL Web_Service_Request Package.

The main call of interest is

apex_web_service.make_rest_request_b(
            p_url => L_IMAGE_URL,
            p_http_method => 'GET',
            p_credential_static_id => L_APEX_WEB_CREDENTIAL
            )

Embedding and Displaying Media Objects

Media in APEX is typically stored as a BLOB, having components to display its contents. The section on Understanding BLOB Support in Forms and Reports describes the declarative BLOB support to upload files in forms, and download or display files in reports.

By default, BLOB columns do not display in a report. Reports that include a BLOB column will display the text [unsupported data type] for the column. A report can include a download link to retrieve the object.

If the BLOB you are working with is an image, you can display it in a report using the type Display Image on a numeric column that calculates the size and if the length is 0, the BLOB is NULL and no image is displayed.

If the content is stored elsewhere then either URL or in the case of OCI Object Storage an API request is required.

What is available OOTB?

The Cards & Content Row components both allow image display, with the Card component supporting declarative attributes for the Image URLs, URL and BLOB columns.

Classic Reports have the Display Image type for columns.

The Display Image type is also supported by APEX Form region

Displaying Image BLOB

Using the Components above and the PL/SQL API APEX_WEB_SERVICE.REST_REQUEST_B we are able to display image files stored on Object Storage.

Sample Table: MEDIA

create table MEDIA (
    id                number generated by default on null as identity
                      constraint aicd_media_id_pk primary key,
    filename          varchar2(4000 char),
    url               varchar2(4000 char),
    mime_type         varchar2(4000 char)
);
💡
URL column is used to store the Object Storage URL. This could be dynamically built using substitution variables or values stored in a configuration table for the application.

Page Region: Images

  • Type => Cards

  • Source: Type => SQL Query

SELECT
   ID, FILENAME, MIME_TYPE, 
   apex_web_service.make_rest_request_b(
            p_url => URL,
            p_http_method => 'GET',
            p_credential_static_id => :G_APEX_WEB_CREDENTIAL
            ) AS IMAGE
   FROM MEDIA
  • Region: Attributes

    • Card: Primary Key => ID

    • Media: Source => BLOB Column

    • Media: BLOB Column => IMAGE

    • BLOB Attributes

      • Mime Type Column => MIME_TYPE

Supported Image file types should be loaded.

Displaying Video BLOB

As of release 24.1.1, APEX supports images declaratively but to view any other media or content object some advanced formatting is required.

HTML as a core web technology provides tags for video content and its source. Extending this a bit further with data URIs I am able to embed any kind of data as long as I specify its mime type.

I have chosen to base64 encode my content and leverage the data URI format for the video source.

SELECT
   ID, FILENAME, MIME_TYPE, 
    '<video controls>
    <source src="data:'|| MIME_TYPE || ';base64,' || APEX_WEB_SERVICE.BLOB2CLOBBASE64(apex_web_service.make_rest_request_b(
    p_url => URL,
    p_http_method => 'GET',
    p_credential_static_id => :G_APEX_WEB_CREDENTIAL
    ))
    ||'" type="' || MIME_TYPE|| '">
    Sorry, your browser does not support the video tag.
    </video>' AS VIDEO
   FROM MEDIA

Apply the Raw formatting by selecting Advanced Formatting for the Media attribute with the RAW escape filter to preserve the original item value and does not escape characters.

Something similar can be done for Page Forms using the Legacy PL/SQL Dynamic Content type.

This would require the blob content to be in a page item, so just remove the html tag when creating the form region.

SELECT
   ID, FILENAME, MIME_TYPE, 
    apex_web_service.make_rest_request_b(
    p_url => URL,
    p_http_method => 'GET',
    p_credential_static_id => :G_APEX_WEB_CREDENTIAL
    ) AS VIDEO
   FROM MEDIA

Initialise the Form Region and then reference the Page Item when using the APEX_UTIL.GET_BLOB_FILE_SRC in the PL/SQL Code.

For example for Page 103 the Form Region the Page Items would be P103_ID for the ID, P103_VIDEO for the BLOB Content and P103_MIME_TYPE for the MIME_TYPE columns.

htp.p('<video controls width="320" height="240" autoplay>
       <source src="'||apex_util.get_blob_file_src ('P103_VIDEO',:P103_ID, 
       p_content_disposition => 'inline')
       ||'" type="' || :P103_MIME_TYPE|| '">
       Sorry, your browser does not support the video tag.
       </video>');

Conclusion

Combining well documented techniques for APEX, PL/SQL and HTML we can view content stored on OCI Object Storage.

In this example, my use cases, I was able to embed both image and video content requested via the API source.

Would I recommend this?

Object size and network performance are the main concerns for implementing such a solution. Each object has to be requested from the object storage solution and considering the length of time it took to upload it there in the first instance, should give you an indicator how the download would compare.

For a single video, perhaps the app user will be fine or there will be ways to start streaming the object content, which I’ve not explored. Multiple medium to large video files … hopefully during your tests you will understand my concern.

Arguably getting this from the local database would be much faster if streaming is not an option.

Images, so far, no complaints on performance but these have been relatively small in contrast to the videos that I tested.

Legacy Components

In the last form based example I used the legacy PL/SQL Dynamic Content component. I can not give you any recommendations on using this component and hope there will be a replacement component support in the future.

1
Subscribe to my newsletter

Read articles from Sydney Nurse directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Sydney Nurse
Sydney Nurse

I work with software but it does not define me and my constant is change and I live a life of evolution. Learning, adapting, forgetting, re-learning, repeating I am not a Developer, I simply use software tools to solve interesting challenges and implement different use cases.