Полезное для программистов:

Фриланс
Новости
Статьи
   
Рубрики:


Использование декодеров и енкодеров GDI+ для загрузки и сохранения изображений

Поиск:
GDI+ - это новая графическая технология от фирмы Microsoft, предоставляющая дополнительные графические возможности программам независимых разработчиков. Она входит в состав Windows XP, а для большинства других операционных систем требуется установка дополнительного файла. Если Вы работаете в Windows 98, Windows ME, Windows NT4.0 SP6 или Windows 2000, то скопируйте файл gdiplus.dll (1,56 МБ/791 КБ(в архиве)) в папку с программой или в системную папку (любую по выбору /windows/system32, /windows, для Win2000 /WINNT/system32, /WINNT).

  Библиотека является объектной потому для доступа к ее объектам необходимо использовать интерфейсы. Нужные для работы модули прикреплены в архиве (headers.rar). Распакуйте его в папку с программой. Из них нужно подключать GDIPAPI, GDIPOBJ, GDIPUTIL.

  Поскольку классы GDI+ не совместимы с VCL, то удобно преобразовывать изображения в формат BMP, который можно загрузить в поток, а вот загружать и сохранять из потока в поток делфийский класс TBitmap уже умеет. Остается одна проблема, для работы с потоками класс должен уметь реализовывать интерфейс IStream. К сожалению все наследники абстрактоного класса TStream его не реализуют, для этого нужно использовать специальный класс-адаптер TStreamAdapter, который это умеет делать. Итак загружаем изображение.

Код

uses GDIPAPI, GDIPOBJ, GDIPUTIL;

var
Bitmap : TBitmap;

procedure LoadFromFile(aFile : AnsiString);
var
  Filejpg      : TGPImage;//Класс GDI+ обеспечивающий загрузку и сохранение изображений
  mem          : TMemoryStream;//Поток в памяти, который будет получать Битмап
  aptr         : IStream;//Интерфейс который будет реализован при помощи TStreamAdapter
  encoderClsid : TGUID;//GUID - класса изображений
  n            : Int64;
begin
  aptr := nil;
  if FileExists(aFile)
  then
    begin
      Filejpg       := TGPImage.Create(aFile);//создаем класс используя имя файла
      Bitmap        := TBitmap.Create;//Создаем битмап
      mem           := TMemoryStream.Create;//Создаем класс потока
      aptr          := TStreamAdapter.Create(mem, soReference) as IStream;
   //Создаем класс адаптер, который все фунции интерфейса реализует при помощи нашего
   //потока в памяти mem.
      GetEncoderClsid('image/bmp', encoderClsid);//Получаем GUID битмапа
      Filejpg.Save(aptr, encoderClsid);//Сохраняем изображение в поток
      aptr.Seek(0, 0, n);//Сдвигаем указатель потока в начало.
      Bitmap.LoadFromStream(mem);//Загружаем данные из потока в Битмап
      Filejpg.Free;//уничтожаем класс изображения
      aptr := nil;//Освобождаем интерфейс
      mem.Free;//уничтожаем поток в памяти.
    end;
end;


  Для справки, в GDI+ доступны декодеры: 
  •  bmp
  •  jpeg
  •  gif
  •  emf
  •  wmf
  •  tiff
  •  png
  •  icon
Это значит что изображения всех этих типов можно загружать в TGPImage.

  После обработки изображений вам наверняка нужно его сохранить в файл. Для этого проделываем обратные операции. Записываем Битмап(Bitmap : TBitmap) в поток, из потока создаем объект изображение GDI+ TGPImage, и используя его метод Save сохраняем его в файл. В процедуру передается параметр ftype который определяет тип сохраняемой картинки из тех что поддерживаются енкодеромЕнкодер поддерживает следующие форматы:
  • 'image/bmp'
  • 'image/jpeg'
  • 'image/gif'
  • 'image/tiff'
  • 'image/png'
Код

procedure SavetoFile(aFile, ftype: AnsiString;
                                Fcompression : Integer = 100);
var
  imgFile          : TGPImage;
  mem              : TMemoryStream;
  aptr             : IStream;
  encoderClsid     : TGUID;
  imgtype          : WideString;
  encoderParameters: TEncoderParameters;//задает параметры енкодера (в данном случае
                               //используется для того чтобы задать степеь сжатия jpeg)
  param            : ULONG;

begin
  mem     := TMemoryStream.Create;
  Bitmap.SaveToStream(mem);//Загружаем битмап в поток
  mem.Seek(0, soFromBeginning);//устанавливаем позицию потока в начало

  aptr    := TStreamAdapter.Create(mem, soReference) as IStream;
  imgFile := TGPImage.Create(aptr);
  imgtype := ftype;//преобразуем анси строку в юникод
  GetEncoderClsid(imgtype, encoderClsid);//получаем GUID нужного нам енкодера
  
  if ftype = 'image/jpeg' //для jpeg устанавливаем дополнительные параметры
  then
    Begin
      encoderParameters.Count := 1;//устанавливаем всего один параметр
      encoderParameters.Parameter[0].Guid := EncoderQuality;//степень сжатия
      encoderParameters.Parameter[0].Type := EncoderParameterValueTypeLong;//тип
                                            //параметра длинно целое (integer)
      encoderParameters.Parameter[0].NumberOfValues := 1;
      param := Fcompression;                //указываем что устанавливаем параметр
                                            //сжатие
      encoderParameters.Parameter[0].Value := @param;
      imgFile.Save(aFile, encoderClsid, @encoderParameters)//все данные настройки              
                         //заданы передаем их в функцию Save для сохранения в файл
    end
  else
    imgFile.Save(aFile, encoderClsid);//если используем дефолтные настройки то
                                      //encoderParameters просто не передаем.
  imgFile.Free;
  aptr := nil;
  mem.Free;
end;


  В заключение хочу заметить что методы SaveLoad, конструктор Create класса TGPImage перегружены для использования как потоков так и строк-путей к файлу с различными расширенными параметрами так и без них.


Облегченный вариант от Snowy для конвертации BMP->PNG
Код

unit PngGDIP;
interface
uses Windows;
const WINGDIPDLL = 'gdiplus.dll';
type
  Status = (
    Ok,
    GenericError,
    InvalidParameter,
    OutOfMemory,
    ObjectBusy,
    InsufficientBuffer,
    NotImplemented,
    Win32Error,
    WrongState,
    Aborted,
    FileNotFound,
    ValueOverflow,
    AccessDenied,
    UnknownImageFormat,
    FontFamilyNotFound,
    FontStyleNotFound,
    NotTrueTypeFont,
    UnsupportedGdiplusVersion,
    GdiplusNotInitialized,
    PropertyNotFound,
    PropertyNotSupported
  );
  TStatus = Status;
  GpStatus          = TStatus;
  ImageCodecInfo = packed record
    Clsid             : TGUID;
    FormatID          : TGUID;
    CodecName         : PWCHAR;
    DllName           : PWCHAR;
    FormatDescription : PWCHAR;
    FilenameExtension : PWCHAR;
    MimeType          : PWCHAR;
    Flags             : DWORD;
    Version           : DWORD;
    SigCount          : DWORD;
    SigSize           : DWORD;
    SigPattern        : PBYTE;
    SigMask           : PBYTE;
  end;
  TImageCodecInfo = ImageCodecInfo;
  PImageCodecInfo = ^TImageCodecInfo;
  GpImage = Pointer;
  DebugEventLevel = (
    DebugEventLevelFatal,
    DebugEventLevelWarning
  );
  DebugEventProc = procedure(level: DebugEventLevel; message: PChar); stdcall;
  GdiplusStartupInput = packed record
    GdiplusVersion          : Cardinal;       // Must be 1
    DebugEventCallback      : DebugEventProc; // Ignored on free builds
    SuppressBackgroundThread: BOOL;           // FALSE unless you're prepared to call
                                              // the hook/unhook functions properly
    SuppressExternalCodecs  : BOOL;           // FALSE unless you want GDI+ only to use
  end;                                        // its internal image codecs.
  TGdiplusStartupInput = GdiplusStartupInput;
  PGdiplusStartupInput = ^TGdiplusStartupInput;
  NotificationHookProc = function(out token: ULONG): Status; stdcall;
  NotificationUnhookProc = procedure(token: ULONG); stdcall;
  GdiplusStartupOutput = packed record
    NotificationHook  : NotificationHookProc;
    NotificationUnhook: NotificationUnhookProc;
  end;
  TGdiplusStartupOutput = GdiplusStartupOutput;
  PGdiplusStartupOutput = ^TGdiplusStartupOutput;
  EncoderParameterValueType = Integer;
  TEncoderParameterValueType = EncoderParameterValueType;
  EncoderParameter = packed record
    Guid           : TGUID;   // GUID of the parameter
    NumberOfValues : ULONG;   // Number of the parameter values
    Type_          : ULONG;   // Value type, like ValueTypeLONG  etc.
    Value          : Pointer; // A pointer to the parameter values
  end;
  TEncoderParameter = EncoderParameter;
  PEncoderParameter = ^TEncoderParameter;
  EncoderParameters = packed record
    Count     : UINT;               // Number of parameters in this structure
    Parameter : array[0..0] of TEncoderParameter;  // Parameter values
  end;
  TEncoderParameters = EncoderParameters;
  PEncoderParameters = ^TEncoderParameters;
  function GdipGetImageEncodersSize(out numEncoders: UINT; out size: UINT): GPSTATUS; stdcall;
  function GdipGetImageEncoders(numEncoders: UINT; size: UINT; encoders: PIMAGECODECINFO): GPSTATUS; stdcall;
  function GdiplusStartup(out token: ULONG; input: PGdiplusStartupInput; output: PGdiplusStartupOutput): Status; stdcall;
  procedure GdiplusShutdown(token: ULONG); stdcall;
  function GdipLoadImageFromFile(filename: PWCHAR; out image: GPIMAGE): GPSTATUS; stdcall;
  function GdipSaveImageToFile(image: GPIMAGE; filename: PWCHAR; clsidEncoder: PGUID; encoderParams: PENCODERPARAMETERS): GPSTATUS; stdcall;
  function GetImageEncodersSize(out numEncoders, size: UINT): TStatus;
  function GetImageEncoders(numEncoders, size: UINT; encoders: PImageCodecInfo): TStatus;
  function GetEncoderClsid(format: String; out pClsid: TGUID): integer;
implementation
function GdipGetImageEncodersSize; external WINGDIPDLL name 'GdipGetImageEncodersSize';
function GdipGetImageEncoders; external WINGDIPDLL name 'GdipGetImageEncoders';
function GdiplusStartup; external WINGDIPDLL name 'GdiplusStartup';
procedure GdiplusShutdown; external WINGDIPDLL name 'GdiplusShutdown';
function GdipLoadImageFromFile; external WINGDIPDLL name 'GdipLoadImageFromFile';
function GdipSaveImageToFile; external WINGDIPDLL name 'GdipSaveImageToFile';
function GetImageEncodersSize(out numEncoders, size: UINT): TStatus;
  begin
    result := GdipGetImageEncodersSize(numEncoders, size);
  end;
  function GetImageEncoders(numEncoders, size: UINT; encoders: PImageCodecInfo): TStatus;
  begin
    result := GdipGetImageEncoders(numEncoders, size, encoders);
  end;
function GetEncoderClsid(format: String; out pClsid: TGUID): integer;
var
  num, size, j: UINT;
  ImageCodecInfo: PImageCodecInfo;
Type
  ArrIMgInf = array of TImageCodecInfo;
begin
  num  := 0; // number of image encoders
  size := 0; // size of the image encoder array in bytes
  result := -1;
  GetImageEncodersSize(num, size);
  if (size = 0) then exit;
  GetMem(ImageCodecInfo, size);
  if(ImageCodecInfo = nil) then exit;
  GetImageEncoders(num, size, ImageCodecInfo);
  for j := 0 to num - 1 do
  begin
    if( ArrIMgInf(ImageCodecInfo)[j].MimeType = format) then
    begin
      pClsid := ArrIMgInf(ImageCodecInfo)[j].Clsid;
      result := j;  // Success
    end;
  end;
  FreeMem(ImageCodecInfo, size);
end;
end.


И пример использования.

Код

Program shot;
uses
  Windows, PngGDIP in 'PngGDIP.pas';
var
  token: dword;
  input: TGdiplusStartupInput;
  image: GPIMAGE;
  Clsid: TGUID;
begin
  image := nil;
  FillChar(input, SizeOf(input), 0);
  input.GdiplusVersion := 1;
  GdiplusStartup(token, @input, nil);
  GdipLoadImageFromFile('1.bmp', image);
  GetEncoderClsid('image/png', Clsid);
  GdipSaveImageToFile(image, '2.png', @ClsId, nil);
  GdiplusShutdown(token);
end.


Автор: Alexeis
Сайт: http://forum.vingrad.ru/





Файлы:
gdiplus.rar
headers.rar

Просмотров: 4590

 

 

Новые статьи:


Популярные:
  1. Как сделать цикличным проигрывание MIDI-файла?
  2. Создание AVI файла из рисунков
  3. Как устройство "отключить в данной конфигурации"?
  4. Kто в данный момент присоединен через Сеть?
  5. Как узнать количество доступной памяти?
  6. Как реализовать в RichEdit разноцветный текст?
  7. Как скрыть свое приложение от ProcessViewer
  8. Как программно нажать/скрыть/показ кнопку "Start"?
  9. Модуль работы с ресурсами в PE файлах
10. Функции вызова диалоговых окон выбора
11. Проверка граматики средствами Word'а из Delphi.
12. Модуль для упрощенного вызова сообщений
13. Функции для записи и чтение своих данных в, ЕХЕ- файле
14. Рекурсивный просмотр директорий
15. Network Traffic Monitor
16. Разные модули
17. Универсальная функция для обращения к любым экспортируем функциям DLL
18. Библиотека от VladS
19. Протектор для UPX'а
20. Еще об ICQ, сообщения по контакт листу?
21. Использование открытых интерфейсов
22. Теория и практика использования RTTI
23. Работа с TApplication
24. Примеры использования Drag and Drop для различных визуальных компонентов
25. Что такое порт? Правила для работы с портами
26. Симфония на клавиатуре
27. Загрузка DLL
28. Исправление автоинкремента
29. Взаимодействие с чужими окнами
30. Проверить дубляжи в столбце


 

 

 
 
На главную