27.02.2016 0 min to read

Обработка изображений. Объект ORDImage

Category : Статьи

Для работы с мультимедиа объектами в БД Oracle существует такая замечательная вещь как Oracle Multimedia(изначально interMedia). Это средство позволяет хранить, обрабатывать и использовать мультимедиа-информацию различной природы. Это могут быть изображения, аудио и видеоданные. Для работы с каждым видом информации в Oracle Multimedia присутсвуют специальные объектные типы, позволяющие хранить информацию непосредственно в ячейках обычных таблиц, а также выполнять некоторый набор преобразований.

Для обработки изображений предназначен объектный тип ORDImage. Объекты данного типа позволяют с легкостью загрузить изображение в БД из файловой системы, где функционирует БД Oracle. В таблицах возможно создание полей с типом ORDImage, а следовательно, и хранение данных. Набор методов позволяет извлекать информацию о различных параметрах изображения, например формат, размер, вид сжатия изображения и т.д., а также выполнять элементарные преобразования с помощью методов process() и processCopy() с той лишь разницей, что первый метод изменяет исходные данные, а второй – возвращает копию с выполненными изменениями.

Некоторые нюансы в работе с объектами ORDImage возникают при использовании их только для преобразования изображения. Например, исходная графическая информация хранится в таблице в поле blob. Требуется сделать уменьшенное изображение и записать его в другое поле.

Допустим, исходное изображение хранится в таблице EMPLOYEES, в поле PHOTO. В таблице THUMBS предполагается хранить уменьшенные изображения для использования в каких-либо списках.

Последовательность действий достаточно проста: выбрать из таблицы исходное изображение, создать на его основе объект ORDImage, с помощью processCopy создать уменьшенную копию и записать результат в таблицу назначения. Здесь легко получить ошибку:

ORA-29400: data cartridge error
IMG-00710: unable to write to destination image
ORA-22275: invalid LOB locator specified

Это говорит о том, что для новой копии изображения не было выделено места в памяти. Выделить требуемую память можно как минимум двумя способами.

  1. создать объект ORDImage на основе заранее выбранного пустого поля из таблицы назначения (THUMBS);
  2. выделить временную память для обработки с помощью процедуры пакета DBMS_LOB – dbms_lob.createTemporary.

Первый вариант удобен для случаев, аналогичных нашей задаче – извлечь данные, преобразовать, записать в таблицу. Если же результат записывать в таблицу не планируется (например, планируется выгрузка в файл), то предпочтителен второй вариант.

Итак, подводя итог, код для решения поставленной задачи выглядит следующим образом:

declare
   oimg ORDImage;
   oimg_100 ORDImage := ORDImage.init();

   img blob;
   img_100 blob;

   v_emp number := 101;
begin
   -- получение исходного изображения
   select PHOTO into img from EMPLOYEES where employee_id = v_emp;
   -- создание на основе исходного изображения объекта ORDImage
   oimg := ORDSYS.ORDImage(img);

   -- выборка записи, в которую предполагается записать копию изображения
   -- запись должна быть выбрана в режиме FOR UPDATE
   select THMB_100 into img_100 from THUMBS where employee_id = v_emp for update;

   -- создание объекта ORDImage, связанного с полем назначения
   oimg_100 := ORDSYS.ORDImage(img_100);
   -- масштабирование изображения до размеров 100x100 с сохранением пропорций
   oimg.processCopy('maxScale=100 100', oimg_100);

   update THUMBS set
      thmb_100 = oimg_100.getContent()
   where employee_id = v_emp;
end;

 

Вариант для обработки во временной памяти:

declare
    oimg ORDImage;
    oimg_100 ORDImage := ORDImage.init();

    img blob;
    img_100 blob;

    v_emp number := 101;
begin
    -- получение исходного изображения
    select PHOTO into img from EMPLOYEES where employee_id = v_emp;
    -- создание на основе исходного изображения объекта ORDImage
    oimg := ORDSYS.ORDImage(img);
    -- выделение временной памяти
    dbms_lob.createTemporary(oimg_100.source.localData, true);

    oimg.processCopy('maxScale=100 100', oimg_100);
    img_100 := oimg_100.getContent();
    -- удаление выделенного временного пространства
    dbms_lob.freeTemporary(oimg_100.source.localData);
end;