Chapter 8. Media in Object Types

This chapter looks in greater detail at the nature and characteristics of the different kinds of media objects and the specific needs for text, audio, image, and video applications. Through a study of this chapter the reader will develop a broad overview of the role of media objects within database development and should then be able to understand

  • The general features of a variety of media object types and their deployment in relational and object tables.

  • The role played by SQL objects to develop more complex objects.

Media Objects

In Chapter 3 we learned that object types have the general structure shown in Figure 8.1.

Classes and object types.

Figure 8.1. Classes and object types.

A key concept in SQL:1999 is that user-defined data types would make it easier for applications developers to work with complex and unstructured data. A user-defined data type is a theoretical construct that is implemented in Oracle as an object type. In an Oracle implementation, an object type is equivalent in the concept of a class in UML, with three kinds of components. It must have a name that uniquely identifies it within the database schema, it can have attributes that are either built-in types or other object types, and methods that describe the operations that can be applied to the object type known as member functions or procedures. In an object type there may be several attributes. These attributes will normally have built-in data types drawn from the traditional system-defined data types, such as INTEGER, CHARACTER, etc., or may be object types, such as a set of color values. As we found in Chapter 3 an object type is one created by or for the database developer. This concept of TYPE has an advantage that only certain operations can be allowed, that is, are valid for a given type. For example, arithmetic operations will only be valid for a numeric data type; finding the time intervals between two dates can only apply to date-time data types. When object types are created, the developer can also specify the operations (methods) that can be applied to them.

Even in the original relational model there was no restriction on the kinds of things that could be defined as types, but this theoretical ability has only been available in practice recently. So now we can have types made up from maps, images, and videos by using object types that we studied in Chapter 3, such as SI_StillImage type. The values of a type may only be manipulated by the operators defined on that domain. For example, SI_StillImage type has an operator called SI_Thumbnail(height,width) that would derive a new thumbnail image from the specified SI_StillImage object using the height and width provided as parameters.

In Chapter 3 we listed the attributes of the interMedia object types, for example, the ORDImage object type. Every object type has methods associated with it that deal with

  • The construction of instances of the type.

  • Setting and getting individual attribute values.

  • The specific nature of the media type, such as image processing operations.

Although Oracle interMedia provides a set of image, audio, and video object types sufficient for most common application requirements, including popular Web formats, these types can be extended to support many application-specific requirements, for example:

  • New or specialized formats

  • New compression and decompression schemes (codecs)

  • Specialized indexes

  • Customized query optimization and methods

  • New data sources

  • Specialized data-processing algorithms

Applications can easily add multiple image, audio, and video columns, or mixed columns containing any of these types as objects to existing and new relational tables.

Before we look at the different media types individually we need to get an understanding of ORDSource. This is a special object type from which all the media types derive properties and methods. The ORDSource type has a set of methods that are basic to all the interMedia types. In addition, the other types (image, audio, and video) have their own specialized methods that we cover separately later in this chapter.

In UML the class is not a collection of objects, it is a definition of the object’s data and operations. In the same way, interMedia ORDAudio, ORDDoc, ORDImage, and ORDVideo object types provide wrapper methods from ORDSource to do the following:

  • Set the source of the data as local or external (ORDSource.setLocal) depending on whether the data is within the database or in the external file system.

  • Modify the time an object was last updated (ORDSource.setUpdateTime).

  • Set information about the external source type, location, and name of the data (ORDSource.setSourceInformation) that we need when we load the data.

  • Transfer data into or out of the database (ORDSource.importFrom).

  • Obtain information about the local data content, such as its length, location, or its handle to the BLOB, put the content into a temporary BLOB, or delete it, for example, using the ORDSource.getContentInTempLob() method.

  • Access source data by opening it, reading it, writing to it, trimming it, and closing it, for example, using the ORDSOURCE.trim method.

We can see how this system works by taking ORDImage as an example. The ORDSource object type is incorporated in all the specific media types and examples of its attributes are shown in Table 8.1 for image media. We do not call its methods directly, instead users are advised to use those methods provided for the specific types. There are a number of methods available to manipulate the image instances.

This means that when ORDSYS.ORDImage is used as a data type for a column in a table that column will include all attributes of the ORDSource type and the ORDImage type. These are shown below with sample data for the Picture Book case study. Table 8.1 (a) displays specific image attributes. The MIME type is used to specify the nature of the data in the body of a MIME entity, by giving media type and subtype identifiers. The MIME header field is simply a set of parameters, specified in an attribute/value notation (see Chapter 2). In general, the top-level media type is used to declare the general type of data, while the subtype specifies a specific format for that type of data. Table 8.1 (b) shows the corresponding values for the attributes of the source attribute of the ORDImage type (which is of type ORDSource). This tells us that all the media data is local and stored in BLOBS.

Table 8.1. (a) ORDImage Attributes with Sample Data

Source

MIME Type

Height

Width

Content Length

File Format

Content Format

Compression Format

cats

image/jpeg

132

147

301,000

JFIF

24BITRGB

JEPG

chardonnay

image/jpeg

223

157

80,000

JFIF

24BITRGB

JEPG

europa

image/gif

150

150

9,820

GIFF

24BITRGB

GIFLZW

frank

image/tiff

221

224

15,700

TIFF

24BITRGB

None

goldfinch

image/bmp

200

200

117,000

BMPF

24BITRGB

None

isaac

image/tiff

334

266

99,100

TIFF

8BITBW

None

kiran

image/jpeg

480

640

80,000

JFIF

24BITRGB

JEPG

Table 8.1. (b) ORDSource Attributes with Sample Data

Object

localData

srcType

srcLocation

srcName

updateTime

Local

cats

BLOB

FILE

C:image

Cats.jpg

02/11/02:12:26

1

chardonnay

BLOB

FILE

C:image

Chardonnay.jpg

02/11/02:12:26

1

europa

BLOB

FILE

C:image

Europa1.gif

22/11/01:21:46

1

frank

BLOB

FILE

C:image

Frank300.tif

2/11/02:12:26

1

goldfinch

BLOB

FILE

C:image

Goldfinc.bmp

02/11/02:12:26

1

isaac

BLOB

FILE

C:image

Isaac.tif

9/19/02:07:08

1

kiran

BLOB

FILE

C:image

Kiran.jpg

19/09/02:17:58

1

Note:

The metadata values (height, width, etc.) can be captured from the media during the insertion of the instances by extraction from the media metadata rather than being entered by the user (see Section 8.3.3). The three ORDSource attributes (srcType, srcLocation, srcName) are only required for external media sources but are important information for loading the image media into the database.

Methods Available for ORDImage Object Type

interMedia supports image processing, such as image format transcoding, image cutting, image scaling, and generating thumbnail images. In addition, specifically when the destination image file format is RAW Pixel (RPIX) format or Microsoft Windows Bitmap (BMPF) image format, interMedia supports a variety of operators for changing the format characteristics.

We will start by creating a new table to illustrate the ORDImage methods:

CREATE TABLE photos
  (ID                    NUMBER NOT NULL,
   IMAGE                 ORDSYS.ORDIMAGE)
   LOB (IMAGE.SOURCE.LOCALDATA) STORE AS (CHUNK 32K)

We can now use the methods of ORDImage, which can be invoked in two ways:

object_typename.method()

Or we can use it with an expression such as a PL/SQL variable:

object_expression.method()

Now we can add an image using the INIT() method, described in Chapter 3, to initialize the image column as an empty BLOB, followed by the importFrom method, which will accept an external image file and import this into the database. This is illustrated by the next PL/SQL procedure:

CREATE or replace PROCEDURE img_import
AS
   img     ORDSYS.ORDIMAGE;
   ctx     raw(64) :=null;
BEGIN
   INSERT INTO photos(id, image)
   VALUES (4310,ORDSYS.ORDIMAGE.INIT());
      img.importFrom(ctx,'file','PHOTO_DIR','graduation.jpg')
            returning image into img;
   UPDATE  photos SET image=img WHERE id=4310;
END;

In this procedure we use the declaration

ctx    raw(64)  :=null;

This is for the source plug-in context information and should be allocated and initialized to NULL. We will use this kind of variable for all the different media types.

The statement

INSERT INTO photos(id, image)
   VALUES (4310,ORDSYS.ORDIMAGE.INIT());

effects the creation of an empty image in the row identified by 4310. The importFrom method stores image data in the database from the directory named as 'PHOTO_DIR' and implicitly calls the setProperties() method to set the height, width, fileFormat, and other object fields appropriately extracted from the image metadata.

This is the full specification of the method:

img.importFrom(ctx,'file','PHOTO_DIR','graduation.jpg'),

The object types include a number of data manipulation methods, for example, specifically for image media using ORDImage:

  • Format and compression conversion

  • Scaling

  • Cropping

  • Copying

The first set of methods we will study are concerned with the status of images before or after processing. For example, processCopy() and process() are member functions of ORDSYS.ORDIMAGE that can access and manipulate the following attributes:

  • Source

  • Content length

  • Width

  • Height

  • MIME type

  • File format

  • Content format

  • Compression format

Note there are operators of the same name that process BFILES and BLOBS through the relational interface. We can use these operators in the statement such as object_name.setProperties(). In the following procedure an image is selected from the database and copied into a variable obj that is used with the setProperties() method to extract the values of some image attributes that can then be displayed.

CREATE OR REPLACE PROCEDURE get_image_props
AS
 obj ORDSYS.ORDimage;
BEGIN
 SELECT p.image INTO obj FROM photos p
  WHERE p.id = 4310 FOR UPDATE;
 obj.setProperties();
 DBMS_OUTPUT.PUT_LINE('Image file format: ' ||
obj.getFileformat);
 DBMS_OUTPUT.PUT_LINE('Image Compression: ' ||
obj.getCompressionFormat);
 DBMS_OUTPUT.PUT_LINE('Image Content format: ' ||
obj.getContentformat);
 DBMS_OUTPUT.PUT_LINE('Image Mime Type: ' ||
obj.getMimeType);
 DBMS_OUTPUT.PUT_LINE('Image size: ' ||
obj.getContentLength);
 DBMS_OUTPUT.PUT_LINE('Image Height: ' || obj.getHeight);
 DBMS_OUTPUT.PUT_LINE('Image Width: ' || obj.getWidth);
 UPDATE  photos p set p.image = obj
   WHERE  p.id = 4310;
 COMMIT;
END;

When we execute this procedure we find the following.

SQL> execute get_image_props
Image file format: JFIF
Image Compression: JPEG
Image Content format: 24BITRGB
Image Mime Type: image/jpeg
Image size: 73874
Image Height: 360
Image Width: 564

Properties extracted from the interMedia object types can be stored in an XML-formatted CLOB or in individual relational columns as we showed in Table 8.1.

Both process methods process() and processCopy() carry out three types of operations:

  1. Image formatting—change the layout of the data within the image storage but do not change the semantic content or visual appearance of the image (e.g., converting a 24-bit image to 8 bits; color to greyscale; compression).

  2. Image processing—change the way the image looks (e.g., contrast; cut, flip, gamma, which corrects the brightness of the image; mirror; rotate; scale; quantize, which will change a number of properties including dither). (See Chapter 2.)

  3. Format—specific—only for raw pixel or BMPF (e.g., changes channel order, R,G,B).

The main difference between the process() and processCopy() methods is that the latter method accepts separate source and destination ORDImage instances so the original image and the changed image are both retained. In the case of process() method, the source and destination ORDImage instances are the same so the original image becomes the destination image and is written into the same storage space as the source image replacing it so that it is permanently altered. For example:

Object_name.processCopy(VERB, new_object_name)

Object_name.process(VERB)

In general when we use these process methods, any number of operators can be combined as long as the command statement makes sense. In Figure 8.2 we can see some of the effects of using process verbs on the same source image: (a) is the original image, (b) is the result of using the cut verb, and (c) is the result of using two verbs, gamma and rotate. Some operators only work with certain image formats, for example, JPEG, while others require data in raw pixel format.

Image processing within the database.

Figure 8.2. Image processing within the database.

When we use these methods the IN parameter relates to a number of operators—process verbs—included in a single method. The process verbs include:

  • Flip

  • Gamma

  • Contrast

  • Quantize

  • Tiled

  • FileFormat

  • MaxScale

The full list of verbs is displayed in Table 8.2. FileFormat is the single most important detail when specifying the output for process() method. Its value determines the range of content and compression formats allowed and whether or not compression quality will be useful.

Table 8.2. Image Processing Verbs

Process Verb

Effect

Usage Example

Rotate

Changes orientation

‘rotate=45‘

Gamma

Changes RGB values to make image lighter or darker

’gamma=”0.3”’

Contrast

Changes pixels range

Contrast 150 210

Cut

Crops image to rectangle from upper left value to lower right

Cut 00 200 200

Scale

Changing scale (e.g., to produce a thumbnail)

scale=2

  

scale=”0.51”

  

scale=”0.15”

compressionQuality

Expressed as integer(=>0 and <=100)

compressionQuality=50

 

MAXCOMPRATIO (smallest image, lowest quality)

compressionQuality=MAXCOMPRATIO

 

HIGHCOMP

compressionQuality=HIGHCOMP

 

MEDCOMP default

compressionQuality=MEDCOMP

 

LOWCOMP

compressionQuality=LOWCOMP

 

MAXINTEGRITY (largest image, best quality)

compressionQuality=MAXINTEGRITY

 

An integer value between 0 and 100

compressionQuality=50

compressionFormat

Specifies the compression algorithm to encode the image data, such as HUFFMAN3, FAX3, and FAX4—common in TIFF images

compressionFormat=JPEG

contentFormat

Concerned with 8-bit ... monochrome, etc.

 
 

Use 256 colors with lookup table

contentFormat=8bitlut

 

Use 24-bit true color

contentFormat=24bitrgb

fileFormat

Changes output to specified file format

fileFormat=TIFF

fixedScale

Scales to fixed size in pixels (width, height)

fixedScale=32 32

maxScale

Scales to maximum size preserving aspect ratio

maxScale=50 50

flip

Swap scan lines from top to bottom

flip

mirror

Swap columns of an image from left to right

mirror

tiled

Forces output to be tiled. for TIFF only.

tiled

xScale

Scale on x-axis by given factor.

xScale=”0.1”

yScale

Scale on y-axis by given factor.

yScale=”0.1”

Page

Used with “multipage” images produced by some scanners. For TIFF only.

Page=0

Quantize

ERRORDIFFUSION ORDEREDDITHER THRESHOLD MEDIANCUT

quantize=ordereddither

Note: Quotes are required around floating point values to correctly interpret values according to the user’s NLS_TERRITORY setting.

Following this approach we can change an image into a thumbnail using processCopy(), combined with the scale verbs:

BEGIN
 SELECT image, thumb INTO obj_1, obj_2
  FROM photos
  WHERE id = img_id FOR UPDATE;
  obj_1.processCopy('maxScale=32 32', obj_2);
 UPDATE photos SET thumb = obj_2
  WHERE id=img_id;
 COMMIT;
End;

In this example we have used processCopy() because we want to keep the original image and the thumbnail. This example takes the stored image into the variable obj_1 and uses the processCopy() method to generate and store the thumbnail in obj_2. The statement

obj_1.processCopy('maxScale=32 32', obj_2);

follows the same pattern for all the process verbs (i.e., input image + process verb = output image). See Table 8.3 and Figure 8.2.

Table 8.3. Verbs used with methods Process() and ProcessCopy()

Input Image

Process Verb

Output Image

GIF file

‘fileformat=jfif’

JPEG file

JPEG

‘maxscale=200 200’

JPEG file

JPEG file

‘fileformat=tiff scale=“0.4”

Outputs TIFF file

TIFF file

‘fileFormat=giff rotate=90’

Gives GIF file

The gamma processing verb changes the R,G,B band values of the image. The values gamma1, gamma2, and gamma3 are the denominators of the gamma exponent applied to the input image. If only one value is specified, then that value is applied to all color components (either gray, or red, green, and blue) of the input image as shown in Figure 8.2(c). If three values are specified then gamma1 is applied to the red component of the image, gamma2 to the green component, and gamma3 to the blue component.

To brighten an image, specify gamma values greater than 1.0; typical values are in the range 1.0 to 2.5. To darken an image, specify gamma values smaller than 1.0 (but larger than 0).

The mirror operator places an image’s scanlines in inverse order such that the pixel columns are swapped from left to right. This operator accepts no values.

The rotate and gamma operators are illustrated in the following procedures.

CREATE OR REPLACE PROCEDURE image_process1
AS
 obj ORDSYS.ORDimage;
BEGIN
 SELECT p.image INTO obj FROM photos p
  WHERE p.id = 4310 FOR UPDATE;
obj.process('rotate=45 gamma="0.3"'),--rotate and darken
 obj.process('quantize=ordereddither'),
 DBMS_OUTPUT.PUT_LINE('Image file format: ' ||
obj.getFileformat);
 DBMS_OUTPUT.PUT_LINE('Image Compression: ' ||
obj.getCompressionFormat);
 DBMS_OUTPUT.PUT_LINE('Image Content format: ' ||
obj.getContentformat);
 DBMS_OUTPUT.PUT_LINE('Image Mime Type: ' ||
obj.getMimeType);
 DBMS_OUTPUT.PUT_LINE('Image size: ' ||
obj.getContentLength);
DBMS_OUTPUT.PUT_LINE('Image Height: ' || obj.getHeight);
DBMS_OUTPUT.PUT_LINE('Image Width: ' || obj.getWidth);
 UPDATE  photos p set p.image = obj
   WHERE  p.id = 4310;
 COMMIT;
END;

The procedure above illustrates how we can perform image processing by selecting an image from the database and using the process method to produce the changes in orientation and color. The cut verb will select a rectangular area from upper left (x,y) with dimensions width, height. In the next example the cut verb is specified.

CREATE OR REPLACE PROCEDURE image_process2
 AS
  obj ORDSYS.ORDimage;
 BEGIN
  SELECT p.image INTO obj FROM photos p
   WHERE p.id = 4310 FOR UPDATE;
  obj.process('cut=0 0 200 200'),
  obj.process('contrast=150 210'),
  obj.process('flip'),
  obj.process('mirror'),
  DBMS_OUTPUT.PUT_LINE('Image file format: ' ||
obj.getFileformat);
  DBMS_OUTPUT.PUT_LINE('Image Compression: ' ||
obj.getCompressionFormat);
  DBMS_OUTPUT.PUT_LINE('Image Content format: ' ||
obj.getContentformat);
  DBMS_OUTPUT.PUT_LINE('Image Mime Type: ' ||
obj.getMimeType);
  DBMS_OUTPUT.PUT_LINE('Image size: ' ||
obj.getContentLength);
 DBMS_OUTPUT.PUT_LINE('Image Height: ' || obj.getHeight);
 DBMS_OUTPUT.PUT_LINE('Image Width: ' || obj.getWidth);
  UPDATE  photos p set p.image = obj
    WHERE  p.id = 4310;
  COMMIT;
 END;

We can see the difference in the images in Figure 8.2 and 8.3 but in addition we can see the results of the properties:

  • <SQL> execute image_process2

  • Image file format: JFIF

  • Image compression: JPEG

  • Image content format: 24BITRGB

  • Image MIME type: image/jpeg

  • Image size: 3012

  • Image height: 200

  • Image width: 200

Examples of effects of processing verbs.

Figure 8.3. Examples of effects of processing verbs.

The quantize verb (see Figure 8.3 for its affect) is used to improve the quality of a poor image by using a specific quantize method such as

  • ERRORDIFFUSION

  • ORDEREDDITHER

  • THRESHOLD

  • MEDIANCUT

The Quantize verb is used in the procedure image_process1 in a statement such as

quantize=ordereddither

There are two forms of the contrast operator. We can use

Contrast =<p>

where <p> maps a percentage of the pixel values, p, to the entire output range. Or,

Contrast=<lower> <upper>

This linearly maps the input image’s pixels in the range between upper and lower to the entire output range. It is also possible to map the color bands (R,G,B) to different ranges (e.g., Contrast 150 210).

Dealing with Image Metadata

There are specialized methods available for dealing with image metadata that are described in Chapter 2. ORDImage has methods to get and write the metadata into special XML documents.

The photos table stores two instances of an image: the full-size photograph and a thumbnail image. This table can also store up to four different image metadata documents. These documents are stored in the columns named metaORDImage, metaEXIF, metaIPTC, and metaXMP, and represent image metadata from the ORDImage, EXIF, IPTC, and XMP metadata formats, respectively. The metadata columns are of type XMLType, and they are bound to the corresponding metadata XML schemas that interMedia provides. We can modify the photos table to create a table that holds the metadata as well.

CREATE TABLE photos_meta
                   ( id           NUMBER PRIMARY KEY,
                     description  VARCHAR2(40),
                     metaORDImage XMLTYPE,
                     metaEXIF     XMLTYPE,
                     metaIPTC     XMLTYPE,
                     metaXMP      XMLTYPE,
                     image        ORDSYS.ORDIMAGE,
                     thumb        ORDSYS.ORDIMAGE )
LOB(image.source.localdata)  -- storage images with 32K chunk
  STORE AS (chunk 32k)
LOB(thumb.source.localdata)  -- but the thumbnails with only
16k
  STORE AS (chunk 16k)
-- and bind the XMLType columns to the interMedia metadata
schemas
XMLType COLUMN metaORDImage
  XMLSCHEMA "http://xmlns.oracle.com/ord/meta/ordimage"
  ELEMENT "ordImageAttributes"
XMLType COLUMN metaEXIF
  XMLSCHEMA "http://xmlns.oracle.com/ord/meta/exif"
  ELEMENT "exifMetadata"
XMLType COLUMN metaIPTC
  XMLSCHEMA "http://xmlns.oracle.com/ord/meta/iptc"
  ELEMENT "iptcMetadata"
XMLType COLUMN metaXMP
  XMLSCHEMA "http://xmlns.oracle.com/ord/meta/xmp"
  ELEMENT "xmpMetadata";

The following PL/SQL procedure extracts metadata from an image and stores it in the specified metadata columns in the photos_meta table. This procedure demonstrates the getMetadata() method, which returns an array of XML documents. The root element of each document is examined to determine the metadata type. The UPDATE statement stores the documents in the corresponding columns in the photos_meta table.

The getMetadata() Method

The ORDImage getMetadata method is a member function that accepts the metadata type as a string parameter that specifies the types of embedded metadata to extract and return an XMLSequenceType, for example, getMetadata(metadata type). It extracts the specified types of metadata from the image and returns an array of schema-valid XML documents. If no matching metadata is found, an empty array is returned.

The input parameter can be the metadata type specified as follows: ALL, ORDIMAGE, XMP, EXIF, and IPTC-IIM. The default value is ALL. When the value of the input parameter metadata type is ALL, and more than one type of supported metadata is present in the image, this method returns several XML documents, one for each type of metadata found. For other values of the input parameter, the method returns zero, if the metadata of that type were absent or a single XML document conforms to one of the metadata standards XMP, EXIF, and IPTC-IIM. Each document returned is stored as an instance of XMLType, and is based on one of the metadata schemas. The method XMLType.getNamespace() can be used to determine the type of metadata represented in that document.

CREATE OR REPLACE PROCEDURE extractMetadata(inID IN INTEGER)
IS
  img               ORDSYS.ORDIMAGE;
  metav           XMLSequenceType;
  meta_root     VARCHAR2(40);
  xmlORD       XMLType;
  xmlXMP        XMLType;
  xmlEXIF        XMLType;
  xmlIPTC        XMLType;

BEGIN
 -- select the image
SELECT image INTO img
FROM photos_meta WHERE id = inID;
-- extract all the metadata
metav := img.getMetadata( 'ALL' );

-- process the result array to discover what types of metadata
were returned

FOR i IN 1..metav.count() LOOP
  meta_root := metav(i).getRootElement();
  CASE meta_root
    WHEN     'ordImageAttributes' THEN xmlORD := metav(i);
    WHEN     'xmpMetadata' THEN xmlXMP := metav(i);
    WHEN      'iptcMetadata' THEN xmlIPTC := metav(i);
    WHEN      'exifMetadata' THEN xmlEXIF := metav(i);
    ELSE NULL;
  END CASE;
END LOOP;

-- Update metadata columns
--
UPDATE photos_meta
SET metaORDImage = xmlORD,
    metaEXIF = xmlEXIF,
    metaIPTC = xmlIPTC,
    METAXMP = xmlXMP
WHERE id = inID;

END;

The putMetadata() Method

This method accepts XML data in the form of a valid XML document and a string that specifies its metadata type. The XMLType should contain a schema valid XML document for the indicated metadata type. If the value of the metadata type parameter is XMP, the root element should contain a well-formed RDF document. This is the default type. For example:

putMetadata(xml Data IN NOCOPY XMLType, metadata type IN
VARCHAR2 DEFAULT 'XMP' encoding IN VARCHAR2 DEFAULT 'UTF-8'),

This specifies the character encoding to be used in the image file. Valid values are UTF-8, UTF-16, UTF-16BE, and UTF-16LE. The default is UTF-8. Why is this necessary?

Different image file formats support different encodings, and may restrict the binary metadata packet size. The putMetadata() method creates a binary packet suitable for embedding in the target image file. The packet is encoded according to the value of the encoding parameter. If the value of the metadata type parameter is XMP, a new XMP packet is written to the image, replacing any existing XMP packets. A binary metadata packet generated from the same XML document input may have different sizes for different encodings. The following are the restrictions of the supported image formats:

  • GIF89a supports UTF-8 encoding only.

  • JPEG requires a binary packet size of less than 65,502 bytes.

  • TIFF requires a binary packet size of less than 4 gigabytes.

The following PL/SQL procedure demonstrates the putMetadata() method. This procedure accepts six arguments. The entry_id argument identifies the image in the photos_meta table to be updated. The remaining arguments (title, creator, date, description, and copyright) are strings that will be formatted into an XMP packet and embedded within the target image.

This example creates an XML document instance based on the interMedia XML schema for XMP metadata. The schema for XMP metadata defines a single, global element <xmpMetadata>. The <xmpMetadata> element contains a single, well-formed RDF document. The RDF document contains a single <RDF> element that is derived from the RDF namespace. This RDF document is constructed using elements defined by the Dublin Core Schema (see Chapter 2).

The call to the putMetadata() method embeds the metadata document into the image file. The UPDATE statement stores the new image and the new metadata back in the photos_meta table.

CREATE OR REPLACE PROCEDURE write_metadata
( entry_id IN VARCHAR2,
                          title IN VARCHAR2,
                          creator IN VARCHAR2,
                          date IN VARCHAR2,
                          description IN VARCHAR2,
                          copyright IN VARCHAR2 )
IS
       img            ORDSYS.ORDImage;
       xmp            XMLType;
       buf              VARCHAR2(5000);
BEGIN
-- select the image
SELECT image INTO img
FROM photos_meta WHERE id = entry_id FOR UPDATE;

-- Create the XMP packet it must be schema valid
-- to "http://xmlns.oracle.com/ord/meta/xmp"
-- and contain an <RDF> element. This example uses
-- the Dublin Core schema.

buf := '<xmpMetadata xmlns="http://xmlns.oracle.com/ord/meta/
xmp"
        xsi:schemaLocation="http://xmlns.oracle.com/ord/meta/
xmp
          http://xmlns.oracle.com/ord/meta/xmp"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>
  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-
syntax-ns#">
  <rdf:Description about="" xmlns:dc="http://purl.org/dc/
elements/1.1/">';

IF title IS NOT NULL THEN
  buf := buf || '<dc:title>' || htf.escape_sc(title) || '</
dc:title>';
END IF;

IF creator IS NOT NULL THEN
  buf := buf || '<dc:creator>' || htf.escape_sc(creator)
             || '</dc:creator>';
END IF;
IF date IS NOT NULL THEN
  buf := buf || '<dc:date>' || htf.escape_sc(date)
             || '</dc:date>';
END IF;
IF description IS NOT NULL THEN
  buf := buf || '<dc:description>' ||
htf.escape_sc(description)
             || '</dc:description>';
END IF;
IF copyright IS NOT NULL THEN
  buf := buf || '<dc:copyright>' || htf.escape_sc(copyright)
             || '</dc:copyright>';
END IF;

buf := buf || '
  </rdf:Description>
  </rdf:RDF>
  </xmpMetadata>';
-- create the XML document
xmp := XMLType.createXML(buf, 'http://xmlns.oracle.com/ord/
meta/xmp'),

-- write the metadata
img.putMetadata( xmp, 'XMP' );

-- update the image
UPDATE photos_meta SET image = img,
    metaXMP = xmp
WHERE id = entry_id;

END;

interMedia can work with DICOM images in basically the same way as GIF or TIFF images but we would need to create a table to hold the metadata that refers to the appropriate XML schema. This is illustrated by creating another version of the photos_meta table called medicalImages.

   CREATE TABLE medicalImages
                             (id number primary key,
                              description VARCHAR2(40),
                              metadata XMLType,
                              image ORDSYS.ORDIMAGE,
                              thumb ORDSYS.ORDIMAGE)
   LOB (image.source.localdata) -- store images with 32K chunk
     STORE AS (chunk 32K)
   LOB (thumb.source.localdata) -- but the thumbnails with only
   16K
     STORE AS (chunk 16K)
   -- and bind the XMLType columns to the interMedia metadata
   columns
   XMLType column metadata
     XMLSCHEMA "http://xmlns.oracle.com/ord/meta/dicomImage"
     ELEMENT "DICOM_IMAGE";

We also provide a specialized method getDicomMetadata() to extract the metadata.

CREATE OR REPLACE PROCEDURE extractDicomMetadata(inID
INTEGER)
IS
   local_image        ORDSYS.ORDIMAGE;
   local_id           INTEGER;
   dicom_metadata     XMLType := NULL;
BEGIN
  SELECT image INTO local_image FROM medicalImages WHERE id =
inID;
   -- extract DICOM metadata
   dicom_metadata :=
local_image.getDicomMetadata('imageGeneral'),
   IF (dicom_metadata IS NULL) THEN
      DBMS_OUTPUT.PUT_LINE('metadata is NULL'),
   ELSE
     UPDATE medicalImages SET metadata = dicom_metadata where
id = inID;
   END IF;
   -- let us print the namespace of the XML document
containing the
   -- dicom metadata that we just extracted
   DBMS_OUTPUT.PUT_LINE('namespace: ' ||
dicom_metadata.getNamespace());

END;

The method is very similar to the getMetadata() method but the string parameter that specifies the type of DICOM metadata to extract has only one valid value, imageGeneral. All other values are ignored.

The DICOM standard includes a complete set of encoding rules for medical images. These encoding rules are also called transfer syntax. Oracle interMedia provides DICOM encoding rules that support metadata extraction and image content processing. Metadata extraction is supported by the getDicomMetadata() and setProperties() methods. Image content support is provided through the processCopy() and setProperties() methods.

Methods Available for ORDAudio Object Type

The ORDAudio object type has the following attributes:

  • Description

  • Source

  • Format

  • MIME type

  • Comments

  • Encoding

  • Sample size and rate

  • Number of channels

  • Compression and duration

We can create a table to hold our family music such as:

CREATE TABLE AUDIO_ord
          (ID             NUMBER NOT NULL,
           DESCRIPTION    VARCHAR2(40) NOT NULL,
           AUDIO          ORDSYS.ORDAUDIO)

We will need to initialize the interMedia column, using the ORDAudio.INIT() method just as we did for images, before we can insert the audio data from a file in the directory. In this example we would have created the directory object AUDIO_DIR and granted access to users.

CREATE or replace PROCEDURE AUDI0_SAMPLE_import
AS
   my_aud      ORDSYS.ORDAUDIO;
   ctx     raw(64) :=null;
BEGIN
   INSERT INTO  AUDIO_ORD(id,description,audio)
       VALUES (1743,'Nocturne in C-sharpe Minor Chopin',
       ORDSYS.ORDaudio.INIT())
   RETURNING audio INTO my_aud;

my_aud.importFrom(ctx,'file','AUDIO_DIR','pianist_01.mp3'),
   UPDATE  AUDIO_ORD SET audio=my_aud WHERE id=1743;
END;

This procedure uses the ORDAudio.INIT() method to initialize the BLOB within the ORDAudio object type. The ctx variable is used to hold the context information for the source. The importFrom() method transfers audio data from the specified external audio data source, in this case AUDIO_DIR directory, which must exist before we can use this method. The audio data is inserted into the source.localData attribute (of the embedded ORDSource object type) within the database.

The next procedure illustrates how audio data can be retrieved from the database, then its properties captured by the setProperties() method and stored in the appropriate attributes of the audio object type within the database.

CREATE OR REPLACE PROCEDURE audio_process1
AS
 obj ORDSYS.ORDAudio;
 ctx RAW(64) :=NULL;
BEGIN
 SELECT p.audio INTO obj FROM audio_ord p
  WHERE p.id = 1743 FOR UPDATE;
  obj.setProperties(ctx,FALSE);
 DBMS_OUTPUT.PUT_LINE('Audio file format: ' ||
obj.getFormat);
 DBMS_OUTPUT.PUT_LINE('Audio Compression: ' ||
obj.getCompressionType);
 DBMS_OUTPUT.PUT_LINE('Audio encoding: ' || obj.getEncoding);
 DBMS_OUTPUT.PUT_LINE('Audio Sampling Rate: ' ||
obj.getSamplingRate);
 DBMS_OUTPUT.PUT_LINE('Audio Duration: ' ||
obj.getAudioDuration);
DBMS_OUTPUT.PUT_LINE('Audio size: ' || obj.getSampleSize);
UPDATE audio_ord p
   SET p.audio = obj
   WHERE p.id = 1743;
COMMIT;
 EXCEPTION
  WHEN ORDSYS.ORDAudioExceptions.METHOD_NOT_SUPPORTED THEN
   DBMS_OUTPUT.PUT_LINE('METHOD_NOT_SUPPORTED caught'),
   WHEN OTHERS THEN
   DBMS_OUTPUT.PUT_LINE('EXCEPTION CAUGHT'),
 END;

When we execute the procedure we can check the properties.

SQL> EXECUTE audio_process1
Audio file format: MPGA
Audio Compression: LAYER3
Audio encoding: LAYER3
Audio Sampling Rate: 44100
Audio Duration: 250
Audio size:

The setProperties() method reads the audio metadata to capture the values of the object attributes and then stores them in the object attributes in the database. In this way the attributes of the audio data for which values are available are captured: compression type, duration, encoding type, format, MIME type, number of channels, sampling rate, and sample size. In this case the statement

obj.setProperties(ctx,FALSE);

shows the setComments parameter is FALSE. It would populate the comments field of the object with a rich set of format and application properties in XML form if the value of the setComments parameter is TRUE. The default value is FALSE. If the property cannot be extracted from the media source, then the respective attribute is set to NULL as in the above example where there is no value for the audio size.

We can process the audio data using the special method called processAudioCommand, which allows us to send a command and related arguments to the format plug-in for processing. We use this method to send any audio commands and their respective arguments to the format plug-in. Commands are not interpreted; they are taken and passed through to a format plug-in to be processed. We can extend support to a new format that is not understood by the ORDAudio object by preparing a package such as ORDPLUGINS.ORDX_<format>_AUDIO that supports that format.

Methods Available for ORDVideo Object Type

We’ll start with a suitable table for the family to store its video data:

CREATE TABLE VIDEO_ord
  (ID              NUMBER NOT NULL,
   DESCRIPTION     VARCHAR2(40) NOT NULL,
   VIDEO           ORDSYS.ORDVIDEO)

ORDVideo has the following attributes:

  • Description

  • Source

  • Height/width

  • Format

  • MIME type

  • Comments

  • Bit rate

  • Sample size and rate

  • Number of frames, rate, resolution

  • Number of colors

  • Compression and duration

There are separate methods to manipulate these attributes but one of the most useful is setProperties() again since it reads the video data to get the values of the video object’s attributes and then stores them in the ORDVideo object. This method sets the properties for each of the attributes of the video data for which values are available: format, height, width, frame resolution, frame rate, video duration, number of frames, compression type, number of colors, and bit rate.

The method also populates the comments field of the object with a rich set of format and application properties in XML form if the value of the setComments parameter is TRUE.

We should begin using the init() method as soon as possible to allow you to more easily initialize the ORDVideo object type, especially if the ORDVideo type evolves and attributes are added in a future release. INSERT statements left unchanged using the default constructor (which initializes each object attribute) will fail under these circumstances. This can be achieved by the following statement.

BEGIN
 INSERT INTO video_ord (id, description, video)
 VALUES (1234,'Pond life video', ORDSYS.ORDVideo.init());
 COMMIT;
END;

We can then move video data from the specified external data source into the local source, using the importFrom() method:

CREATE OR REPLACE PROCEDURE VIDEO_imp
 AS
  obj ORDSYS.ORDVideo;
  ctx RAW(64) :=NULL;
BEGIN
  SELECT P.VIDEO INTO obj FROM video_ORD p
     WHERE p.id = 1234 FOR UPDATE;
  DBMS_OUTPUT.PUT_LINE('setting and getting source'),
  DBMS_OUTPUT.PUT_LINE('--------------------------'),
  -- Import data:

obj.importFrom(ctx,'file','VIDEO_DIR','CYCLIDIUM_GLAUCOMA.MOV
'),
  -- Check size:
  DBMS_OUTPUT.PUT_LINE('Length is '
    ||TO_CHAR(obj.getContentLength(ctx)));
  UPDATE VIDEO_ORD p SET P.video = obj WHERE id = 1234;
  COMMIT;
  EXCEPTION
        WHEN ORDSYS.ORDSourceExceptions.METHOD_NOT_SUPPORTED
THEN
         DBMS_OUTPUT.put_line('Source METHOD_NOT_SUPPORTED
caught'),
        WHEN
ORDSYS.ORDSourceExceptions.SOURCE_PLUGIN_EXCEPTION THEN
         DBMS_OUTPUT.put_line('SOURCE PLUGIN EXCEPTION
caught'),
        WHEN ORDSYS.ORDVideoExceptions.METHOD_NOT_SUPPORTED
THEN
         DBMS_OUTPUT.put_line('VIDEO METHOD_NOT_SUPPORTED
EXCEPTION caught'),
        WHEN ORDSYS.ORDVideoExceptions.VIDEO_PLUGIN_EXCEPTION
THEN
         DBMS_OUTPUT.put_line('VIDEO PLUGIN EXCEPTION
caught'),
        WHEN OTHERS THEN
         DBMS_OUTPUT.PUT_LINE('EXCEPTION Caught'),
END;

In this procedure we have used a number of exceptions to trap problems with the source and the video plugin. For example note that the ORDSourceExceptions.METHOD_NOT_SUPPORTED is raised when the importFrom( ) method is called but the method is not supported by the source plug-in being used. Similarly, the VIDEO_PLUGIN_EXCEPTION is raised when the video plug-in raises an exception. Here is an example of the use of setProperties():

CREATE OR REPLACE PROCEDURE video_props
 AS
   obj ORDSYS.ORDVideo;
   ctx RAW(64) :=NULL;
  BEGIN
   SELECT p.video INTO obj FROM VIDEO_ORD p
     WHERE p.id  = 1234 FOR UPDATE;
   obj.setProperties(ctx,FALSE);
   UPDATE VIDEO_ORD p SET p.video = obj
     WHERE p.id = 1234;
   COMMIT;
   EXCEPTION
    WHEN ORDSYS.ORDVideoExceptions.VIDEO_PLUGIN_EXCEPTION THEN
     DBMS_OUTPUT.PUT_LINE('ORDVideoExceptions.VIDEO_PLUGIN_EXCEPTION
caught'),
    WHEN OTHERS THEN
     DBMS_OUTPUT.PUT_LINE('exception raised'),
  END;

The statement obj.setProperties(ctx,FALSE) operates on the video stored into the obj variable. The subsequent UPDATE statement stores the properties captured back into the database with the actual video data. In this case the setComments() parameter is set to FALSE.

Object type

We can use get methods to retrieve individual attribute values or we can use the getAllAttributes method to generate a string that contains the main settings.

CREATE OR REPLACE PROCEDURE get_video_props
AS
 obj ORDSYS.ORDVideo;
 tempLob   CLOB;
 ctx RAW(64) :=NULL;
BEGIN
 SELECT p.video INTO obj FROM video_ord p
  WHERE p.id  = 1234;
 DBMS_OUTPUT.PUT_LINE('getting comma separated list of all
attributes'),
 DBMS_OUTPUT.PUT_LINE('--------------------------------------
-------' );
 DBMS_LOB.CREATETEMPORARY(tempLob, FALSE, DBMS_LOB.CALL);
 obj.getAllAttributes(ctx,tempLob);

DBMS_OUTPUT.PUT_LINE(DBMS_LOB.substr(tempLob,DBMS_LOB.getLeng
th(tempLob),1));
 COMMIT;
 EXCEPTION
  WHEN ORDSYS.ORDVideoExceptions.METHOD_NOT_SUPPORTED THEN
   DBMS_OUTPUT.PUT_LINE('VIDEO METHOD_NOT_SUPPORTED EXCEPTION
caught'),
  WHEN OTHERS THEN
   DBMS_OUTPUT.PUT_LINE('EXCEPTION CAUGHT'),
END;

Looking at the output of this procedure we can see that the obj.getAllAttributes(ctx,tempLob) statement produces a string that includes a list of video data attributes separated by comma (,) (i.e., format, MIME type, width, height, format, frameResolution, frameRate, videoDuration, numberOfFrames, compressionType, numberOfColors, and bitRate).

SQL> EXECUTE get_video_props
getting comma separated list of all attributes
---------------------------------------------
format=MOOV,mimeType=video/
quicktime,width=160,height=120,frameResolution=NULL,frameRate
=24,videoDuration=17,numberOfFrames=408,compressionType=RPZA,
numberOfColors=16,bitRate=NULL

These video data attributes are available from the header of the formatted video data and can be extracted from the video data itself. The statement

DBMS_OUTPUT.PUT_LINE(DBMS_LOB.substr(tempLob,DBMS_LOB.getLeng
th(tempLob),1));

is used to store the extracted data in a temporary CLOB, which is manipulated by the DBMS_LOB package to produce the formatted string.

The next procedure shows how to set up an alternative approach, selecting the attribute values one by one.

CREATE OR REPLACE PROCEDURE get_video_ATTRIBUTES
 AS
  obj ORDSYS.ORDVideo;
  ctx RAW(64) :=NULL;
  res INTEGER;
  width INTEGER;
  height INTEGER;
 BEGIN
  SELECT p.video INTO obj FROM video_ord p
   WHERE p.id  = 1234;
  DBMS_OUTPUT.PUT_LINE('getting attributes'),
  DBMS_OUTPUT.PUT_LINE('---------------------------------------------' );
 obj.getFrameSize(width, height);
  DBMS_OUTPUT.PUT_LINE('width :' || width);
  DBMS_OUTPUT.PUT_LINE('height :' || height);
  res := obj.getFrameResolution();
  DBMS_OUTPUT.PUT_LINE('resolution : ' ||res);
 res:= obj.getNumberOfColors();
 DBMS_OUTPUT.PUT_LINE('number of colors : ' ||res);
 res:= obj.getNumberOfFrames();
 DBMS_OUTPUT.PUT_LINE('number of frames : ' ||res);
  COMMIT;
  EXCEPTION
   WHEN ORDSYS.ORDVideoExceptions.METHOD_NOT_SUPPORTED THEN
     DBMS_OUTPUT.PUT_LINE('VIDEO METHOD_NOT_SUPPORTED EXCEPTION caught'),
   WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('EXCEPTION CAUGHT'),
 END;

Sample output:

                   getting attributes
                   ---------------------------------------------
                   width : 160
                   height : 120
                   resolution :
                   number of colors : 16
                   number of frames : 408

As in the case of ORDAudio, setProperties() will extract the available object attributes but when the property cannot be extracted, the attribute is set to null, as in the cas of reolution.

Methods Available for ORDDoc Object Type

The purpose of the ORDDoc object type is to integrate the storage, retrieval, and management of heterogeneous media data within the database. The ORDDoc type can store any heterogeneous media data including audio, image, and video data in a database column. Instead of having separate columns for audio, image, text, and video objects, we can use one column of ORDDoc objects to represent all types of multimedia. ORDDoc can automatically extract metadata from data of a variety of popular audio, image, and video data formats.

ORDDoc has the following attributes:

  • Source

  • File format

  • MIME type

  • Content length

  • Comments

ORDDoc methods can also be used to extract application attributes and store them in the comments attribute of the object in XML form. The comments attribute is a CLOB so that can hold a large amount of text.

The family may want to store heterogeneous data in a table that uses the ORDSY.ORDDoc object types to store media instances, such as favorite recipes with images of the product. First we would create a suitable table.

CREATE TABLE doc_ord
  (ID                NUMBER NOT NULL,
   DESCRIPTION       VARCHAR2(40),
   my_doc            ORDSYS.ORDDOC)

As before we need to initialize the ORDDoc object instance that sets the embedded BLOB data type to EMPTY_BLOB, using the special INIT() method.

BEGIN
INSERT INTO doc_ord (id,description,my_doc)
   VALUES (1242, 'A recipe for Hungarian
Goulash',ORDSYS.ORDDoc.init('file', 'FILE_DIR',
'recipe.doc'));
END;

In the following procedure the importFrom() method is used to transfer data from the external source into the local database.

CREATE OR REPLACE PROCEDURE DOC_imp
AS
  obj ORDSYS.ORDDoc;
  ctx RAW(64) :=NULL;
BEGIN
  SELECT my_doc INTO obj FROM doc_ord
    WHERE id=1242 FOR UPDATE;
  DBMS_OUTPUT.PUT_LINE('setting and getting source'),
  DBMS_OUTPUT.PUT_LINE('--------------------------'),
  -- set source to a file
  -- import data
  obj.importFrom(ctx,'file','FILE_DIR','recipe.doc',FALSE);
  -- check size
  DBMS_OUTPUT.PUT_LINE('Length:'||
      TO_CHAR(DBMS_LOB.GETLENGTH(obj.getContent)));
  DBMS_OUTPUT.PUT_LINE(obj.getSource());
  UPDATE doc_ord SET my_doc=obj WHERE id=1242;
  COMMIT;
  EXCEPTION
    WHEN ORDSYS.ORDSourceExceptions.METHOD_NOT_SUPPORTED THEN
      DBMS_OUTPUT.PUT_LINE
         ('ORDSourceExceptions.METHOD_NOT_SUPPORTED caught'),
    WHEN ORDSYS.ORDDocExceptions.DOC_PLUGIN_EXCEPTION THEN
      DBMS_OUTPUT.put_line('DOC PLUGIN EXCEPTION caught'),
END;

This gives the following results:

SQL> execute doc_imp
setting and getting source
--------------------------
Length: 43520
file://FILE_DIR/recipe.doc

This object type has a slightly different importFrom() method that has a parameter set_prop with IN and data type BOOLEAN. This is a value that determines whether the setProperties() method is called. If the value of this parameter is TRUE, then the setProperties() method is called to read the media data to get the values of the object attributes and store them in the object attributes; otherwise, if the value is FALSE, the set Properties() method is not called. The default value is FALSE as in this case.

In the above examples we have used the interMedia object types as composite data types for columns in relational tables. Alternatively, we can create our own object types based on interMedia object types and methods. Here is an example of an image type that can be used for text-based retrieval through anotation stored in the description attribute:

CREATE TYPE AnnotatedImage AS OBJECT
    ( image ORDSYS.ORDImage,
      description CLOB,
      MEMBER PROCEDURE SetProperties(
SELF IN OUT AnnotatedImage),
      MEMBER PROCEDURE Copy(
dest IN OUT AnnotatedImage),
      MEMBER PROCEDURE ProcessCopy(
command IN VARCHAR2,
      dest IN OUT AnnotatedImage)
    );

In this case we have specified three methods as part of the type. Using stored procedures as methods gives a number of advantages. Since stored procedures only require the calling parameters, the transmission of whole results sets or intermediate tables required for SQL statements is avoided and network traffic can be reduced. Stored procedures are executed in compiled format that greatly reduces code execution times. Stored procedures are also a way of controlling development and are an essential part of the object-relational development.

Two different kinds of methods can be created:

  1. Function or procedure member methods are used to process information and can accept arguments. Methods that are functions always return a value.

  2. Comparison methods that have a distinct purpose to deal with the comparison of object types that are much more complex than the traditional data types.

The member procedures are specified in the type body as follows.

CREATE TYPE BODY AnnotatedImage AS
  MEMBER PROCEDURE SetProperties(SELF IN OUT AnnotatedImage)
IS
  BEGIN
    SELF.image.setProperties();
    SELF.description :=
        'This is an example of using Image object as a
subtype';
  END SetProperties;
  MEMBER PROCEDURE Copy(dest IN OUT AnnotatedImage) IS
  BEGIN
    SELF.image.copy(dest.image);
    dest.description := SELF.description;
  END Copy;
  MEMBER PROCEDURE ProcessCopy(command IN VARCHAR2,
          dest IN OUT AnnotatedImage) IS
  BEGIN
    SELF.Image.processCopy(command,dest.image);
    dest.description := SELF.description;
  END ProcessCopy;
END;

In the statement

SELF.image.setProperties();

the setProperties() method is called with an empty parameter list because its arguments are the attributes of the object of which it is a member, the image attribute of the type AnnotatedImage. This is called a selfish style of invocation. In general, object methods are invoked by using the style Type_name.method() or object_expression.method().

After creating the new type, you can use it as you would any other type, for example, as a data type in a relational table.

CREATE TABLE annotated_photos
(id         NUMBER,
 an_image   AnnotatedImage)

When we insert this into the table we will invoke the INIT() method of the interMedia image data type ORDImage. For example, to use an image as an external BFILE source we would state, as follows.

INSERT INTO annotated_photos
 VALUES
 (1001,
     AnnotatedImage(ORDSYS.ORDImage.init('file',
        'PHOTO_DIR','raven.bmp'),'')
 )

We can use the following procedure with this table:

CREATE OR REPLACE PROCEDURE proc_annotate
AS
    myimage AnnotatedImage;
BEGIN
    SELECT an_image
    INTO myimage
    FROM ANNOTATED_PHOTOS
    WHERE id = '1002';
    myimage.SetProperties;
    DBMS_OUTPUT.PUT_LINE
        ('This image has a description of a raven '),
    DBMS_OUTPUT.PUT_LINE(myimage.description);
    UPDATE  ANNOTATED_PHOTOS
   SET an_image = myimage;
END;

If we execute the procedure we get the following output:

SQL> EXECUTE proc_annotate;
This image has a description of a raven
This is an example of using Image object as a subtype

Note that one of the messages has come from the table column and one from the type method.

Using object types gives a much wider choice to the developer but one question is what kind of type to select. interMedia provides the ability to extract content and format metadata from media sources (image, audio, and video files), and collects and organizes this metadata as an XML formatted CLOB. Once metadata has been extracted and stored, you can index the metadata for powerful full text and thematic media searches using Oracle Text. Thus, the database can be queried to locate the media data based on the metadata extracted from the media. The development of methods and member functions are discussed in later chapters dealing with PL/SQL and Java.

We can use object-relational concepts to develop object types based on interMedia object types as shown

Methods Available for ORDDoc Object Type

We can see that this definition of the photo_type includes several object types and a function. Some of the attributes are themselves complex. The description attribute has a photo_detail_t data type and the image attribute is specified with SI_StillImage data type. We do not have to list the methods available with this object type as they are encapsulated and available to photo_type. We can also specify methods associated with the photo_type object that reflect real-world user requirements. Therefore, for the photo_type we could have a method that extracted details of the description of the photo. We could also store the photo_type in object tables where each row of the object table corresponds to a single photo_type object and the columns of the table are the attributes of the photo_type.

SI_StillImage Object Type

This is a special object type that provides compatibility with the SQL/MM part of the SQL:1999 standard (see Chapter 3). This object type has an extended list of attributes, shown in Table 8.4. As with the other interMedia types, the SI_StillImage media data will be held in a BLOB in an encapsulated ORDSource object that is the data type of the content_SI attribute. The structure of this object type is complex in that it embeds ORDSource, includes attributes specified in SQL:1999, and includes some attributes that have proved useful for the ORDImage object type but are not yet part of the standard (e.g., MIME type and compression format). As this is a highly composite object type it has many methods available. Another difference is that this object type will need to use the DBMS_LOB package to manipulate the BLOB data type embedded in this object type.

Table 8.4. Attributes of SI_StillImage Object Type

Attribute

Type

Comment

content_SI

ORDSYS.ORDSOURCE

SQL Standard—an ORDSource object that contains the binary image or BLOB

contentLength_SI

INTEGER

Length of the image in bytes

format_SI

VARCHAR2(4000)

Image format

height_SI

INTEGER

The number of lines of the image

width_SI

INTEGER

The number of columns of the image

Oracle attribute extensions:

mimeType_ora

VARCHAR2(4000)

The MIME type information—not in SQL standard

contentFormat_ora

VARCHAR2(4000)

Type of image (monochrome, etc. )

compressionFormat_ora

VARCHAR2(4000)

Compression algorithm

retainFeatures_SI

INTEGER

Flag that indicates whether or not image features will be extracted and cached

Oracle extension attributes to cache image features:

averageColorSpec_ora

SI_Color

Cached SI_Color object

colorsList_ora

colorsList

Cached array of colors

frequenciesList_ora

colorFrequenciesList

Cached array of color frequencies

colorPositions_ora

colorPositions

Cached array of color positions

textureEncoding_ora

textureEncoding

The cached array of textures

SI_StillImage Methods

We will focus on this object type’s methods but the SQL/MM standard requires that for each StillImage constructor or method, there is an equivalent SQL function or procedure. Each function or procedure is presented with its equivalent constructor or method. Although the description, parameters, usage notes, and exceptions, subsections frequently refer to the method, these subsections are also applicable to the equivalent SQL function or procedure. To quote from the Oracle InterMedia Reference Manual, “All SQL functions and procedures are created as standalone functions in the ORDSYS schema with invoker rights. A public synonym with the corresponding function or procedure name is created for all SQL functions and procedures.” Therefore, we do not need to specify the schema name when a function or procedure is called. For example, use ORDSYS.SI_MkAvgClr(averageColor) to make the call without the synonym, and use SI_MkAvgClr(averageColor) to make the call based on the method with the synonym. All database users can call these functions and procedures.

The object type can be used as the data type of columns in a table, for example:

CREATE TABLE photos_SI
(id          NUMBER PRIMARY KEY,
                    description VARCHAR2(40) NOT NULL,
                    location    VARCHAR2(40),
                    image       SI_StillImage,
                    thumb       SI_StillImage)

There are three groups of SI_StillImage methods:

  1. Constructor methods

  2. Basic image-processing methods

  3. Advanced image feature extraction methods (covered in Chapter 11)

There are three different types of constructor methods (summarized in Table 8.5) for the SI_StillImage object type, and it is strongly suggested that these are used in preference to the default constructor.

Table 8.5. Constructor Methods for SI_StillImage

Constructor Method Name

Function

Comment

SI_StillImage(content)

Initalizes the image and extracts parameters from image file

Accepts BLOB parameter used with DBMS_BLOB package

SI_StillImage(content, explicitFormat)

Constructs an SI_StillImage object from a specified image and a format

Useful for unsupported image formats

SI_StillImage(content, explicitFormat, height, width)

Constructs an SI_StillImage value from a specified image

Useful for unsupported image formats

SI_MkStillImage1()

Makes a new SI_StillImage object

Initializes the SI_StillImage attributes with values extracted from the image

Using SI_StillImage(content)

This is used to construct the type by initializing the SI_StillImage attributes as follows:

  • content_SI.localData is initialized with the specified image.

  • contentLength_SI is initialized with the length of the image extracted from the specified image.

  • format_SI is initialized with the format of image extracted from the specified image.

  • height_SI is initialized with the height of image extracted from the specified image.

  • width_SI is initialized with the width of image extracted from the specified image.

Using the DBMS_LOB Package

We can use a special package DBMS_LOB provided for manipulating LOBS. The DBMS_LOB package also processes BFILES. DBMS_LOB is a package that is based on working with LOB locators. It consists of a number of routines for manipulating LOBS. Most of these are listed in Table 8.6, together with a brief note on their purpose and an example of their use. Before users can access the package, the SYS user must either execute both dbmslob.sql and prvtlob.plb scripts or execute the catproc.sql script. Then users can be granted privileges to use the package.

Table 8.6. Routines Provided by DBMS_LOB Package

DBMS_LOB Routines

Purpose

Example of Use

DBMS_LOB.OPEN

Open the BFILE

DBMS_LOB.OPEN(Lob_loc, DBMS_LOB.LOB_READONLY);

DBMS_LOB.READ

Read data from a LOB starting at a specified offset

DBMS_LOB.READ(Lob_loc, Amount, Position, Buffer);

DBMS_LOB.WRITE

Write data to a LOB from a specified offset

DBMS_LOB.WRITE (locator, amount, offset, text)

DBMS_LOB.WRITEAPPEND

Write data to the end of a LOB

DBMS_LOB.WRITEAPPEND(lob_loc, amount, text)

DBMS_LOB.SUBSTR

Return part of a LOB value starting at a specified offset

SELECT DBMS_LOB.SUBSTR(note,5,12)

DBMS_LOB.INSTR

Return the numerical position of part of a LOB value

SELECT DBMS_LOB.INSTR(note,’ Rian’)

DBMS_LOB.GETLENGTH

Gets the length of a LOB

SELECT DBMS_LOB.GETLENGTH(note)

DBMS_LOB.TRIM

Trims a LOB value to the specified shorter length

DBMS_LOB.TRIM( lob_loc, no_bytes)

DBMS_LOB.CREATETEMPORARY

Creates a temporary LOB that exists for a session and is useful if a LOB is being changed and then stored again

 

DBMS_LOB.COPY

Copies part or the whole of a LOB to another LOB

DBMS_LOB.COPY(to_lob, from_lob, no_bytes, from_offset, to_offset)

DBMS_LOB.APPEND

Appends the content of a LOB to another LOB

DBMS_LOB.APPEND(to_lob, from_lob)

DBMS_LOB.COMPARE

Compares to similar LOB types

DBMS_LOB.COMPARE(lob_1, lob_2, no_bytes, offset1,offset2)

DBMS_LOB.ERASE

Erases part or the whole of a LOB, starting at a specified offset

DBMS_LOB.ERASE (lob_loc, no_bytes, offset)

DBMS_LOB.LOADFROMFILE

Loads BFILE data into an internal LOB

DBMS_LOB.LOADFROMFILE( from_lob, to_lob, no_bytes, from_offset, to_offset)

DBMS_LOB.CLOSE

Close the BFILE

DBMS_LOB.CLOSE(Lob_loc);

The following example demonstrates how to insert an image into a StillImage object column using the PL/SQL routine DBMS_LOB.LOADFROMFILE.

CREATE OR REPLACE PROCEDURE SI_Image_imp
AS
   lobd  blob;
   fils  BFILE := BFILENAME('PHOTO_DIR','raven.bmp'),
BEGIN
   DBMS_LOB.CREATETEMPORARY(lobd, TRUE);
   DBMS_LOB.fileopen(fils, DBMS_LOB.file_readonly);
   DBMS_LOB.LOADFROMFILE(lobd, fils,
DBMS_LOB.GETLENGTH(fils));
   DBMS_LOB.FILECLOSE(fils);
   INSERT INTO  photos_si (id, description, image)
       VALUES(1235, 'Raven averages 24 inches',
new ORDSYS.SI_StillImage(lobd));
   DBMS_LOB.FREETEMPORARY(lobd);
   COMMIT;
END;

In this procedure we specify the location of the image file and BFILENAME function adds the data into the variable fils, which is a BFILE. Then we create a temporary BLOB by using the DBMS_LOB package, open the BFILE, and load the file into it. The BFILE is closed and then the temporary LOB used as the IN parameter for the SI_StillImage() method is used to insert the data into the object.

Using SI_StillImage(content, explicitFormat)

We can also use a constructor that lets us specify the image format, height, and width when the specified image is an unsupported image format by using the following statement:

newimage := NEW SI_StillImage(lobd, 'psp', 570, 1168);

This constructor has the advantage that we can specify the image format when the specified image is in an unsupported image format and initializes the SI_StillImage attributes as follows:

  • content_SI.localData is initialized with the specified image.

  • contentLength_SI is initialized with the length of the image extracted from the specified image.

  • format_SI is initialized with the specified image format.

  • height_SI is initialized with the height of the image extracted from the specified image.

  • width_SI is initialized with the width of the image extracted from the specified image.

If the constructor function is not able to extract the height and width values from the specified image, then we can assign value to them as follows:

myImage.height_SI := height
myImage.width_SI := width

The following procedure illustrates this, where a Paint Shop Pro image is stored into a temporary BLOB, and since this is a proprietory format, the height and width cannot be extracted, so these are assigned:

CREATE OR REPLACE PROCEDURE SI_Image_imp_format
AS   lobd BLOB;
   fils BFILE := BFILENAME('PHOTO_DIR','cats.psp'),
   newimage SI_StillImage;
   height NUMBER;
   width NUMBER;
   myimage SI_StillImage;

BEGIN
   -- Put the blob in a temporary LOB:
   DBMS_LOB.CREATETEMPORARY(lobd, TRUE);
   DBMS_LOB.FILEOPEN(fils, DBMS_LOB.FILE_READONLY);
   DBMS_LOB.LOADFROMFILE(lobd, fils,
DBMS_LOB.GETLENGTH(fils));
   DBMS_LOB.FILECLOSE(fils);
   -- Create a new SI_StillImage object for this image (which
has an
   -- unsupported format):
   newimage := NEW SI_StillImage(lobd, 'psp'),
   -- If the stored height and width values are NULL, the
following will set
   -- them appropriately. Alternatively, you could use the
   -- SI_StillImage(content, explicitFormat, height,width)
constructor:
   height := 570;
   width := 1168;
   IF (newimage.SI_Height is NULL) THEN
      newimage.height_SI := height;
   END IF;
   IF (newimage.SI_Width is NULL) THEN
      newimage.width_SI := width;
   END IF;
    -- Insert the image into the si_media table, then free the
temp LOB
   INSERT INTO  photos_si (id, description, image)
       VALUES (33, 'two siamese cats',newimage);
   DBMS_LOB.FREETEMPORARY(lobd);
   -- Make sure that the height and width were stored as
expected:
   SELECT image INTO myimage FROM PHOTOS_SI WHERE id=33;
   height := myimage.SI_height;
   width := myimage.SI_width;
   DBMS_OUTPUT.PUT_LINE('Height is ' || height || ' pixels.'),
   DBMS_OUTPUT.PUT_LINE('Width is ' || width ||  ' pixels.'),
   COMMIT;
END;

The explicitFormat parameter must be the same as the format extracted from the image otherwise an error will be returned. An error will also be generated if the explicitFormat parameter value indicates an unsupported format but the format extracted is not NULL.

Note: query the SI_IMAGE_FORMATS view in SI_INFORMTN_ SCHEMA for a list of the supported image formats.

Using SI_StillImage(content, explicitFormat, height, width)

This constructor lets you specify the image format, height, and width when the specified image is an unsupported image format. It is very similar to the previous constructor method except that it allows you to specify values for the height and width of images with unsupported formats. It is not intended to be used to change an image into a thumbnail.

CREATE OR REPLACE PROCEDURE SI_Image_exp_format
AS
   lobd BLOB;
   fils BFILE := BFILENAME('FILE_DIR','cats.psp'),
   newimage SI_StillImage;
   height NUMBER;
   width NUMBER;
   myimage SI_StillImage;
BEGIN
   -- Put the blob in a temporary LOB:
   DBMS_LOB.CREATETEMPORARY(lobd, TRUE);
   DBMS_LOB.FILEOPEN(fils, DBMS_LOB.FILE_READONLY);
   DBMS_LOB.LOADFROMFILE(lobd, fils,
DBMS_LOB.GETLENGTH(fils));
   DBMS_LOB.FILECLOSE(fils);
   -- Create a new SI_StillImage object for this image (which
has an
   -- unsupported format)
   newimage := SI_StillImage(lobd, 'psp', 570, 1168);
   -- Insert the image into the si_media table, then free the
temp BLOB
   INSERT INTO  photos_si (id, description, image)
       VALUES (33, 'two siamese cats',newimage);
   DBMS_LOB.FREETEMPORARY(lobd);
   -- Make sure that the height and width were stored as
expected
        SELECT image INTO myimage
        FROM photos_si WHERE id=33;
   height := myimage.SI_height;
   width := myimage.SI_width;
   DBMS_OUTPUT.PUT_LINE('Height is ' || height || ' pixels.'),
   DBMS_OUTPUT.PUT_LINE('Width is ' || width ||  ' pixels.'),
   COMMIT;
END;

Using SI_MkStillImage1()

An alternative approach will create a new SI_StillImage object using the SI_MkStillImage1() function and the PL/SQL package DBMS_LOB.LOADFROM FILE:

CREATE OR REPLACE PROCEDURE SI_Image_imp2
 AS
    lobd blob;
    fils BFILE := BFILENAME('PHOTO_DIR','robin.bmp'),
 BEGIN
    DBMS_LOB.CREATETEMPORARY(lobd, TRUE);
    DBMS_LOB.FILEOPEN(fils, dbms_lob.file_readonly);
    DBMS_LOB.LOADFROMFILE(lobd, fils,
dbms_lob.getlength(fils));
    DBMS_LOB.FILECLOSE(fils);
    INSERT INTO photos_si (id,description, image)
      VALUES (1236, 'small bird red breast',
SI_MkStillImage1(lobd));
    DBMS_LOB.FREETEMPORARY(lobd);
    COMMIT;
 END;

Methods for Image Processing

The SI_StillImage object type has a number of important methods, listed in Table 8.7.

Table 8.7. SI_StillImage Object Type Methods

Image Processing Method

Function

Comment

SI_ClearFeatures

Disables image feature caching and sets feature attributes to NULL

Used to remove the processing overhead associated with feature synchronization

SI_InitFeatures()

Extracts the image features and caches them in the SI_StillImage object

This method is recommended for users needing image matching

SI_Thumbnail()

Derives a thumbnail image, size is 80 × 80 pixels from the specified SI_StillImage object

Preserves the image aspect ratio so the resulting thumbnail size will be as close to 80 × 80 pixels as possible

SI_Thumbnail(height, width)

Derives a thumbnail image of specified size

Does not preserve the image aspect ratio

SI_InitFeatures() extracts the image features and caches them in the SI_StillImage object. This method needs to be called once, after which SI_StillImage will manage the image features such that every time the image is processed, new image features will automatically be extracted. This method is recommended for users who will be image matching.

This method is not in the first edition of the SQL/MM Still Image standard, but has been accepted for inclusion in the next version. The following procedure will extract the image features and cache them in an SI_StillImage object.

CREATE OR REPLACE PROCEDURE SI_FEATURES_IMP
  AS
  myimage SI_StillImage;
BEGIN
  SELECT IMAGE INTO myimage FROM photos_SI
     WHERE id = 1239 FOR UPDATE;
  myimage.SI_InitFeatures;
  UPDATE photos_SI
   SET IMAGE = myimage where id=1239;
  DBMS_OUTPUT.PUT_LINE('Image feature caching enabled'),
  COMMIT;
END;
SQL> execute si_features_imp
Image feature caching enabled

PL/SQL procedure successfully completed.

In contrast, SI_ClearFeatures() disables image feature caching and sets the value of all internal image feature attributes to NULL. We would call this method to remove the processing overhead associated with feature synchronization if we were not interested in image matching. This method does nothing for unsupported image formats. This method is not in the first edition of the SQL/MM StillImage standard, but it has been accepted for inclusion in the next version.

CREATE OR REPLACE PROCEDURE SI_CLEAR_FEATURES
  AS
   myimage SI_StillImage;
BEGIN
  SELECT IMAGE INTO myimage FROM photos_SI
     WHERE id = 1239 FOR UPDATE;
  UPDATE photos_SI
   SET IMAGE = myimage where id=1239;

  myimage.SI_ClearFeatures;
  DBMS_OUTPUT.PUT_LINE('Image feature caching disabled'),
  COMMIT;
END;

There are two methods for producing a thumbnail image from a SI_Image instance. SI_Thumbnail() derives a thumbnail image from the specified SI_StillImage object. The default thumbnail size is 80 × 80 pixels. Because this method preserves the image aspect ratio, the resulting thumbnail size will be as close to 80 × 80 pixels as possible.

CREATE OR REPLACE PROCEDURE SI_Image_thumb
 AS
   myimage SI_StillImage;
    myThumbnail SI_StillImage;
    height number;
    width number;
 BEGIN
   SELECT image INTO myimage FROM  photos_SI WHERE id = 1239;
   width := myimage.SI_width;
   height := myimage.SI_height;
   DBMS_OUTPUT.PUT_LINE('Height is ' || height || ' pixels.'),
   DBMS_OUTPUT.PUT_LINE('Width is ' || width ||  ' pixels.'),
   myThumbnail := myimage.SI_Thumbnail;
   width := myThumbnail.SI_width;
   height := myThumbnail.SI_height;
   DBMS_OUTPUT.PUT_LINE('Height is ' || height || ' pixels.'),
   DBMS_OUTPUT.PUT_LINE('Width is ' || width ||  ' pixels.'),
 UPDATE photos_SI
 SET thumb = myThumbnail
 WHERE id =1239;
 END;
SQL> execute SI_Image_thumb
Height is 1320 pixels.
Width is 1407 pixels.
Height is 75 pixels.
Width is 80 pixels.

PL/SQL procedure successfully completed.

Alternatively, we can generate a new thumbnail image from the specified SI_StillImage object using the height and width specified. This method does not preserve the aspect ratio. Create a new thumbnail image from an SI_StillImage object with the specified height and width using the SI_Thumbnail(height, width) method:

CREATE OR REPLACE PROCEDURE SI_Image_thumb_size
AS
   myimage SI_StillImage;
   myThumbnail SI_StillImage;
   height number;
   width number;
BEGIN
  SELECT image INTO myimage FROM Photos_si WHERE id = 1235;
  width := myimage.SI_width;
  height := myimage.SI_height;
  DBMS_OUTPUT.PUT_LINE('Height is ' || height || ' pixels.'),
  DBMS_OUTPUT.PUT_LINE('Width is ' || width ||  ' pixels.'),
  myThumbnail := myimage.SI_Thumbnail(129,121);
  width := myThumbnail.SI_width;
  height := myThumbnail.SI_height;
  DBMS_OUTPUT.PUT_LINE('Height is ' || height || ' pixels.'),
  DBMS_OUTPUT.PUT_LINE('Width is ' || width ||  ' pixels.'),
UPDATE photos_SI
SET thumb = myThumbnail
WHERE id = 1235;
END;
Procedure created.

SQL> execute SI_Image_thumb_size
Height is 200 pixels.
Width is 200 pixels.
Height is 129 pixels.
Width is 121 pixels.

PL/SQL procedure successfully completed.

There are a number of attributes associated with the requirements for image matching. These are covered in Chapter 13 on advanced query processing.

Object Tables

We can use user-defined types in two ways: to specify an attribute in a relational table or to generate an object table from the type. There are good design reasons why we should only create one object table for each user-defined type in order to maintain consistency throughout the database; otherwise, as explained later, we may end up with dangling REFs.

An object table is a special kind of table that holds objects and provides a relational view of the attributes of those objects. In Chapter 3 we created an object table from a photo_ord type based on the interMedia ORDImage type.

CREATE TYPE photo_ty AS OBJECT
 (   id          NUMBER,
            description VARCHAR2(40),
            location    VARCHAR2(40),
            image       ORDSYS.ORDIMAGE,
            thumb       ORDSYS.ORDIMAGE);

Then we created the object table:

CREATE TABLE photo_ty_tab OF photo_ty
(CONSTRAINT PK_photo_ty_tab PRIMARY KEY(id))

Note: In Oracle, object tables will not be listed in the system table called tab and cannot be shown by the query SELECT * FROM TAB, but we can use DESCRIBE to look at the structure of objects and object tables.

When an object table is formed, each object forms a complete row of the object table:

  • Objects that appear in object tables are called row objects.

  • Every row object in an object table has an associated object identifier (OID).

  • The OID uniquely identifies the object in an object table.

  • The OID can be used to construct object references to row objects that are an alternative to foreign keys.

  • The OID allows object types and relational tables to refer to the row objects in the object table.

Oracle automatically assigns a unique system-generated identifier called the OID for each row object. Object references are used to fetch and navigate objects. We can regard the use of the OID as a compromise as it could be said to conflict with relational theory and it is not very meaningful in an object-relational database. Oracle manages object access by creating and maintaining an index of the OID column of the object table.

We specified a primary key for the photo_table, using the ID attribute. Oracle recommends the use of primary-key based identifiers for more efficient loading of the object table because system-generated object identifiers need to be remapped by the DBMS using user-specified keys.

Summary

In this chapter we have covered the basic methods of the ORDSYS object types focusing on the constructor and image-processing methods. These methods allow rich media to be stored in the specialized object types in the ORDSource object type either internally in the database or externally. We have illustrated how routine image-processing operations can be carried out with the ORDImage object type without removing the images from the database or using specialized image-processing software. Some image processing can also be carried out with the SI_StillImage object type that is included for interoperability purposes.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset