Image Compression in Oracle APEX: A Java-Based Alternative to Oracle Multimedia


Introduction

In today's digital world, efficient management of media resources is crucial for the performance and scalability of web applications. Oracle 18c does not provide standard tools for image editing, posing challenges for developers. In this post, I will show you how to compress images directly in your Oracle database for free, saving storage space, improving loading times, and optimizing your application's performance.

Why Image Compression is Important

  • Cost Efficiency: Avoid additional costs for external tools or services.
  • Increased Performance: Faster loading times and improved application performance.
  • Better User Experience: Lower bounce rates and higher user satisfaction due to quick loading times.
  • Storage Management: Reducing required storage space in data-intensive applications.
  • Network Optimization: More efficient data transmission and reduced network load.
  • Compliance with Data Policies: Easier compliance with industry regulations concerning data volume.
  • Environmental Benefits: Lower energy consumption for data transmissions and storage.

Implementing a Java Class for Image Compression

We use a Java class called Make_thumbnail , which we import into our database via SQL Developer. This class allows us to compress images directly in the database without the need for external software.
Java
import java.sql.*; 
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import oracle.sql.*;
import oracle.jdbc.*;
import java.sql.Blob;
import javax.imageio.stream.ImageOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;


public class Make_thumbnail{

    public static java.sql.Blob resizeJpegCall (java.sql.Blob blob, int maxSize   ) throws Exception{
  

        // Quality muss zwischen 0.01 und 1.00 liegen, als Parameter wird 0-100 mitgegeben, 
        // daher hier noch mal durch 100 geteilt
        BufferedImage inputImage = ImageIO.read(blob.getBinaryStream()); 

        System.out.println("resizeJpegCall: Groesse des uebergebenen Blob: " + blob.length());              
        System.out.println("Original scaledWidth = " + inputImage.getWidth());              
        System.out.println("Original scaledHeight = " + inputImage.getHeight()); 
        
        int scaleFactorW = (int) (inputImage.getWidth() / maxSize );
        int scaleFactorH = (int) (inputImage.getHeight() / maxSize );

        int scaleResult = scaleFactorW > scaleFactorH ? scaleFactorW : scaleFactorH;

        //int scaledWidth = (int) (inputImage.getWidth() * percent_float );
        int scaledWidth = (int) (inputImage.getWidth() / scaleResult);
        //int scaledHeight = (int) (inputImage.getHeight() * percent_float );
        int scaledHeight = (int) (inputImage.getHeight() / scaleResult);
        System.out.println("scaledWidth = " + scaledWidth);              
        System.out.println("scaledHeight = " + scaledHeight); 

        // blob fuer den returnwert wird ueber eine DB-Connection erstellt
        oracle.jdbc.OracleConnection conn =  (oracle.jdbc.OracleConnection)new OracleDriver().defaultConnection();
        java.sql.Blob retBlob = conn.createBlob();
        // java.sql.Blob retBlob = java.sql.Blob.createTemporary(conn, true, oracle.sql.BLOB.DURATION_SESSION);      
        
        try {
  
       //       RenderedImage renderedImage = (RenderedImage)bufferedImage; 
              OutputStream os = retBlob.setBinaryStream(1L);
              ImageOutputStream ios = ImageIO.createImageOutputStream(os);
              
              /*
              In der Unterfunktion findet der eigentliche Resizen des JPEG statt

              */ 

              boolean result = resizeJpeg (inputImage, os, scaledWidth, scaledHeight )   ;
             if (result) {
  
                // Display message when image is converted
                // successfully
                System.out.println("Image resized successfully.");
                System.out.println("Groesse des Return Blob: " + retBlob.length());              
               
               return retBlob;
            }
            else {
  
                // Display message when image is not
                // converted successfully
                System.out.println( "Could not resize image.");
            }             
              
              

            } catch (IOException e) {
              // Display message when excception is thrown
              System.out.println("Error during resizing image.");
  
              // Print the line number
              // where the exception occured

                e.printStackTrace();
            }
               catch (SQLException e) {
               e.printStackTrace();
            }
               catch(IllegalArgumentException e) {
               e.printStackTrace();
            }           
              return retBlob;
        } 
    //    public static boolean resizeJpeg(BufferedImage inputImage, ImageOutputStream ios, int scaledWidth, int scaledHeight )  throws Exception{
  	

    public static boolean resizeJpeg(BufferedImage inputImage, OutputStream os, int scaledWidth, int scaledHeight )  throws Exception{
     if ( inputImage == null )
        return false;
     if ( os == null )
        return false;
     if ( scaledWidth == 0 )
        return false;        
     if ( scaledHeight == 0 )
        return false;             

        try {

            Image resultingImage = inputImage.getScaledInstance(scaledWidth, scaledHeight, Image.SCALE_DEFAULT);
            BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_RGB);
            outputImage.getGraphics().drawImage(resultingImage, 0, 0, null);
            ImageIO.write(outputImage, "jpg", os);

        return true;

        } catch (IOException e) {
        	  System.out.println("IOException");
            e.printStackTrace();
        return false;
        }
        catch(IllegalArgumentException e) {
            e.printStackTrace();
         return false;
        }
        finally {
            try {
                if (os != null) {
                    os.flush();
                    os.close();
                    System.out.println(
                    "Image resized  successfully.");
                 //return retBlob;
                }
            } catch (IOException e) {
                e.printStackTrace();
              return false;
            }
        }
    }
}

Setting Up the Database Function

After the Java class is compiled, we create a PL/SQL function in the database to handle the image compression.
SQL
CREATE OR REPLACE FUNCTION Make_thumbnail 
(
 P_IMAGE IN BLOB 
, MAXSIZE IN NUMBER 
) RETURN BLOB AS 
LANGUAGE JAVA NAME 'Make_thumbnail.resizeJpegCall(java.sql.Blob, int ) return java.sql.Blob';

Applying Image Compression

Now, with the following call, you can specify an image in the function, set the maximum compression level, and get the compressed image back. This can then be saved back in the database.
SQL
-- create table
CREATE TABLE test_images (
    id NUMBER,
    image BLOB,
    compressed_image BLOB
);

Run the Function

SQL
DECLARE
    -- Variable for the original image
    v_original_image BLOB;
    
    -- Variable for the compressed image
    v_compressed_image BLOB;

    -- Image ID to update
    v_image_id NUMBER := 1;  -- Change this based on your data

BEGIN
    -- Select the original image from the table
    SELECT image INTO v_original_image
    FROM test_images
    WHERE id = v_image_id;

    -- Call the Make_thumbnail function to compress the image
    v_compressed_image := Make_thumbnail(v_original_image, 500); -- 500 is the MAXSIZE parameter

    -- Update the table with the compressed image
    UPDATE test_images
    SET compressed_image = v_compressed_image
    WHERE id = v_image_id; 
END;

Conclusion

The ability to compress images for free offers many benefits, from performance enhancement to cost savings. By implementing the Make_thumbnail Java class and the corresponding database function, you can significantly boost the efficiency of your Oracle database.
{fullWidth}

0 $type={blogger}:

Kommentar veröffentlichen