GDI+ и многокадровые изображения в формате TIFF

В отличие от других растровых графических форматов, формат TIFF (Tag Image File Format)  позволяет:

  • создавать многокадровые (multiframe) файлы
  • указывать количество бит на пиксель в сохраняемом изображении
  • использовать четыре различных алгоритма сжатия

Формат обладает исключительной гибкостью. Вы можете выбрать свой алгоритм сжатия и количество бит на пиксель для каждого кадра, сохранённого в TIFF файле.

В этой статье рассматриваются все аспекты работы с форматом TIFF из приложений Visual FoxPro.

Преобразование графических форматов в GDI+

GDI+ позволяет достаточно просто преобразовывать изображения из одного формата в другой; для этого функции сохранения изображения (например, GdipSaveImageToFile) достаточно просто передать ClsID соответствующего кодека. В следующем примере выполняется преобразование изображения из формата BMP в формат TIFF.

  
 DECLARE Long GdipLoadImageFromFile IN Gdiplus.dll String cFile, Long @ nativeImage
 DECLARE Long GdipSaveImageToFile IN Gdiplus.dll Long nativeImage, String cFile, ;
         String EncoderClsID, String EncoderParameters
 DECLARE Long GdipDisposeImage IN Gdiplus.dll Long nativeImage

 lcInputFile = STRCONV("InputFile.bmp" + CHR(0), 5)
 lcOutputFile = STRCONV("OutputFile.tif" + CHR(0), 5)
 lnImage = 0
 GdipLoadImageFromFile(lcInputFile, @lnImage)
 lqEncoderClsID_TIFF = 0h05F47C55041AD3119A730000F81EF32E
 GdipSaveImageToFile(lnImage, lcOutFile, lqEncoderClsID_TIFF, NULL)
 GdipDisposeImage(lnImage)
 

Функция GdipLoadImageFromFile считывает исходное изображение из файла InputFile.bmp в память компьютера, а функция GdipSaveImageToFile сохраняет это изображение в формате TIFF в файле OutputFile.tif. Эти функции требуют, чтобы имена файлов передавались им как нуль-терминированные строки в формате Unicode.

Значения ClsID кодеков GDI+ перечислены в следующей таблице:

Тип графического формата ClsID декодера Бинарное значение ClsID

BMP

{557CF400-1A04-11D3-9A73-0000F81EF32E} 0h00F47C55041AD3119A730000F81EF32E
JPEG {557CF401-1A04-11D3-9A73-0000F81EF32E} 0h01F47C55041AD3119A730000F81EF32E
GIF {557CF402-1A04-11D3-9A73-0000F81EF32E} 0h02F47C55041AD3119A730000F81EF32E
TIFF {557CF405-1A04-11D3-9A73-0000F81EF32E} 0h05F47C55041AD3119A730000F81EF32E
PNG {557CF406-1A04-11D3-9A73-0000F81EF32E} 0h06F47C55041AD3119A730000F81EF32E

Замечание
Бинарные значения ClsID вы можете использовать только в девятой версии Visual FoxPro. В предыдущих версиях необходимо использовать Windows API функции для выполнения преобразования символьного представления ClsID, указанного в таблице, в двоичное.

Microsoft предупреждает, что значения ClsID кодеков могут отличаться в различных версиях библиотеки GDI+. Поэтому более правильным будет использование специального механизма, предоставляемого функциями GdipGetImageEncodersSize и GdipGetImageEncoders, позволяющего получить значение ClsID кодека для заданного графического формата изображения. Скорее всего, такая необходимость появится в Windows Vista.

Структура EncoderParameters

В рассмотренном выше примере при вызове функции GdipSaveImageToFile ей не передаётся указатель на структуру EncoderParameters (это последний, четвёртый параметр функции); вместо него указан NULL. Действительно, вы можете конвертировать любой поддерживаемый в GDI+ графический формат в другой и без использования этой структуры. Но, если вы хотите управлять качеством сохраняемого изображения формата JPEG или если вы создаёте многокадровые TIFF файлы или TIFF файлы, использующие алгоритмы сжатия и управления цветовой палитрой изображения, то тогда вы должны использовать структуру EncoderParameters для управления параметрами кодека.

Фактически структура EncoderParameters представляет собой массив из вложенных структур. Первое поле этой структуры содержит четыре байта для хранения целочисленного значения, определяющего количество вложенных в неё структур. Каждая из вложенных структур содержит следующие поля:

Байты Наименование
поля в MSDN
Назначение
1-16 Guid GUID, идентифицирующий передаваемый кодеку параметр
17-20 NumbersOfValue Целое число, определяющее количество элементов параметра (например, если параметр — массив)
21-24 Type Целое число, определяющее тип данных передаваемого параметра
25-28 Value Указатель на область памяти, в которой сохранено значение передаваемого параметра

Замечание
Microsoft постоянно использует глобальные идентификаторы в своих новых разработках; не осталась в стороне и GDI+. Хотя на самом деле здесь мы имеем не что иное, как описание некоей функции кодека, которой передаётся один-единственный параметр.

Таким образом, поле Guid определяет, как именно кодек должен обработать передаваемый ему в структуре параметр. Значения поля Guid Для формата TIFF перечислены в следующей таблице.

Наименование в MSDN GUID - бинарное представление Описание

 EncoderSaveFlag

0hFC66222940ACBF478CFCA85B89A655DE Определяет, что сохраняется многокадровый TIFF файл
 EncoderCompression 0h9D739DE0D4CCEE448EBA3FBF8BE4FC58 Определяет используемый алгоритм сжатия файла (кадра)
 EncoderColorDept 0h5570086666AD7C4C9A1838A2310B8337 Определяет количество бит на пиксель в сохраняемом TIFF файле (кадре)

Значения поля Type перечислены в следующей таблице:

Значение Наименование в MSDN Назначение

 1

 EncoderParameterValueTypeByte 8-ми разрядное целое без знака
2  EncoderParameterValueTypeASCII Нуль-терминированная символьная строка
3 EncoderParameterValueTypeShort 16-ти разрядное целое без знака
4 EncoderParameterValueTypeLong 32-х разрядное целое без знака
5 EncoderParameterValueTypeRational Определяет, что параметр - массив из двух 32-х разрядных целых чисел без знака, представляющих дробь, в числителе которой - первое число, в знаменателе - второе.
6 EncoderParameterValueTypeLongRange Определяет, что параметр - массив из двух 32-х разрядных целых чисел без знака, представляющих диапазон значений. Первое число определяет минимальное, а второе - максимальное значение диапазона.
7 EncoderParameterValueTypeUndefined Определяет, что параметр - массив байтов, который может содержать значения любого типа
8 EncoderParameterValueTypeRationalRange Определяет, что параметр - массив из четырех 32-х разрядных целых чисел без знака. Первые два числа представляют одну дробь, вторые два числа   вторую дробь. Эти дроби представляют диапазон рациональных чисел. Первая дробь определяет минимальное, а вторая максимальное значение диапазона.

При работе с форматом TIFF значение передаваемого кодеку параметра представляет собой одно 32-х разрядное целое число, поэтому значение поля NumberOfValues всегда должно быть равно единице, а значение поля Type — четырём (EncoderParameterValueTypeLong, 32-х разрядное целое без знака).

Поле Value содержит указатель на область памяти, в которой находится значение параметра. Как следует из сказанного выше, размер этой памяти должен быть равен 4-м байтам.
Вы можете распределить необходимую память как внутри процесса, так и глобально. Я обычно предпочитаю последний способ.

В следующей таблице приведены допустимые значения параметра, передаваемого в структуре, управляющей созданием многокадрового TIFF (с полем Guid, содержащим EncoderSaveFlag):

Наименование константы в MSDN Значение Описание
 EncoderValueMultiFrame 18 Определяет, что в файл будут добавляться кадры
 EncoderValueFlush 20 Определяет, что запись многокадрового файла завершена
 EncoderValueFrameDimensionPage 23 Определяет, что в файл добавляется очередной кадр

Ниже показан фрагмент кода, демонстрирующий способ создания структуры EncoderParameters в Visual FoxPro.

 
 #DEFINE EncoderSaveFlag        0hFC66222940ACBF478CFCA85B89A655DE
 #DEFINE EncoderValueMultiFrame 18
 
 hGlobal = GlobalAlloc(0x0040, 4)                              && Выделяем глобальную память
 = SYS(2600, hGlobal, 4, BINTOC(EncoderValueMultiFrame, "4RS") && Заносим в неё значение
 lcEncoderParams = BINTOC(1, "4RS")                            && 1 вложенная структура 
 lcEncoderParams = lcEncoderParams + EncoderSaveFlag           && Поле Guid
 lcEncoderParams = lcEncoderParams + BINTOC(1, "4RS")          && Поле NumberOfValues
 lcEncoderParams = lcEncoderParams + BINTOC(4, "4RS")          && Поле Type
 lcEncoderParams = lcEncoderParams + BINTOC(hGlobal, "4RS")    && Поле Value 
 

Для хранения значения параметра в примере при помощи функции GlobalAlloc распределяется фиксированная глобальная память Windows.

Запись многокадровых изображений в формате TIFF

Создание многокадрового изображения TIFF несколько отличается от записи обычного файла. Самый первый кадр, как обычно, записывается функцией GdipSaveImageToFile. Для добавления каждого следующего кадра используется функция GdipSaveAddImage, а функция GdipSaveAdd играет роль завершающего аккорда, добавляя в файл признак его окончания. Всем этим функциям передаётся указатель на структуру EncoderParameters, при этом передаваемое в структуре значение параметра (указатель на параметр хранится в поле Value) для каждой из этих функций будет различным:

  • EncoderValueMultiFrame — для функции GdipSaveImageToFile

  • EncoderValueFrameDimensionPage — для функции GdipSaveAddImage

  • EncoderValueFrameDimensionPage — для функции GdipSaveAdd

В листинге 1 приведён код процедуры, создающей многокадровый TIFF файл.
 

 Листинг 1. Процедура создания многокадрового TIFF файла

 
 #DEFINE EncoderClsID_TIFF               0h05F47C55041AD3119A730000F81EF32E
 #DEFINE EncoderSaveFlag                 0hFC66222940ACBF478CFCA85B89A655DE 
 #DEFINE EncoderValueMultiFrame          18
 #DEFINE EncoderValueFlush               20
 #DEFINE EncoderValueFrameDimensionPage  23 

 LOCAL i, lnStatus, loDialogBox, lcInputFiles, lnCount, lcPath, lcOutputFile, lcFile
 LOCAL lnImage, lnNewImage, lcEncoderParameters, hGlobal, laFiles[1]
 *
 * Объявляем необходимые API функции
 *
 DECLARE Long GdipLoadImageFromFile IN Gdiplus.dll String, Long @
 DECLARE Long GdipSaveImageToFile IN Gdiplus.dll Long, String, String, String
 DECLARE Long GdipSaveAddImage IN Gdiplus.dll Long, Long, String
 DECLARE Long GdipSaveAdd IN Gdiplus.dll Long, String
 DECLARE Long GdipDisposeImage IN Gdiplus.dll Long
 DECLARE Long GlobalAlloc IN WIN32API Long, Long
 DECLARE Long GlobalFree IN WIN32API Long
 *
 * Создаём объект Microsoft Common Dialog для множественного выбора файлов
 *
 loDialogBox = CREATEOBJECT('MSComDlg.CommonDialog') 
 WITH loDialogBox 
    .MaxFileSize = 16500
    .Flags = 0x200 + 0x80000 
    .DialogTitle = "Выберите файлы для сохранения в формате TIFF"
    .Filter = "BMP|*.bmp|JPEG|*.jpg|GIF|*.gif|PNG|*.png|TIFF|*.tif|Все файлы (*.*)|*.*" 
    .FilterIndex = 1 
    .ShowOpen 
    lcInputFiles = .FileName 
 ENDWITH 
 loDialogBox = NULL
 IF EMPTY(lcInputFiles)
    RETURN 
 ENDIF 
 *
 * Разбор полученной строки с именами исходных файлов
 *
 lnCount = ALINES(laFiles, lcInputFiles, 1, CHR(0))
 IF lnCount = 1                   && В списке только один файл
    lcPath = ""                   && ... очищаем путь...
 ELSE 
    lcPath = laFiles[1] + "\"     && Первый элемент массива содержит путь,
    = ADEL(laFiles, 1)            && а остальные - спецификации файлов
    lnCount = lnCount - 1         && 
 ENDIF 
 *
 * Запрашиваем спецификацию файла TIFF для сохранения исходных изображений
 *
 lcOutputFile = PUTFILE("Сохранить в", "result", "tif")
 IF EMPTY(lcOutputFile)
    RETURN 
 ENDIF 
 *
 * Считываем в память первый файл из списка
 *
 lcFile = STRCONV(lcPath + laFiles[1] + CHR(0), 5) && Имя файла -> в Unicode
 lnImage = 0
 lnStatus = GdipLoadImageFromFile(lcFile, @lnImage)
 IF lnStatus > 0
    = MESSAGEBOX("Ошибка при чтении исходного файла" + STR(lnStatus))
    RETURN 
 ENDIF 
 *
 * Формируем структуру EncoderParameters
 *
 hGlobal = 0
 IF lnCount = 1
    lcEncoderParameters = NULL
 ELSE 
    hGlobal = GlobalAlloc(0x0040, 4)
    lcEncoderParameters = BINTOC(1, "4RS")
    lcEncoderParameters = lcEncoderParameters + EncoderSaveFlag
    lcEncoderParameters = lcEncoderParameters + BINTOC(1, "4RS")
    lcEncoderParameters = lcEncoderParameters + BINTOC(4, "4RS")
    lcEncoderParameters = lcEncoderParameters + BINTOC(hGlobal, "4RS")
    = SYS(2600, hGlobal, 4, BINTOC(EncoderValueMultiFrame, "4RS"))
 ENDIF 
 *
 * Записываем первый кадр файла
 *
 lcFile = STRCONV(lcOutputFile + CHR(0), 5)
 lnStatus = GdipSaveImageToFile(lnImage, lcFile, EncoderClsID_TIFF, lcEncoderParameters)
 IF lnStatus = 0
    IF lnCount > 1
 *
 * Изменяем значение параметра, передаваемого в структуре lcEncoderParameters,
 * для функции GdipSaveAddImage
 *
       = SYS(2600, hGlobal, 4, BINTOC(EncoderValueFrameDimensionPage, "4RS"))
 *
 * Организуем цикл для чтения / записи файлов
 *
       FOR i = 2 TO lnCount
          lcFile = STRCONV(lcPath + laFiles[i] + CHR(0), 5) && Имя файла -> в Unicode
          lnNewImage = 0
          lnStatus = GdipLoadImageFromFile(lcFile, @lnNewImage)
          IF lnStatus > 0
             EXIT 
          ENDIF 
          lnStatus = GdipSaveAddImage(lnImage, lnNewImage, lcEncoderParameters)
          GdipDisposeImage(lnNewImage)
          IF lnStatus > 0
             EXIT 
          ENDIF 
       ENDFOR 
 *
 * Изменяем значение параметра, передаваемого в структуре lcEncoderParameters,
 * для функции GdipSaveAdd
 *
       = SYS(2600, hGlobal, 4, BINTOC(EncoderValueFlush, "4RS"))
 *
 * Дописываем признак конца файла
 *
       lnStatus = GdipSaveAdd(lnImage, lcEncoderParameters)
    ENDIF 
 ENDIF 
 *
 * Чистим память
 *
 GdipDisposeImage(lnImage)
 IF hGlobal != 0
    GlobalFree(hGlobal)
 ENDIF 
 = MESSAGEBOX(IIF(lnStatus = 0, "OK", "Ошибка" + STR(lnStatus)))
  

В процедуре используется объект Microsoft Common Dialog, позволяющий выбрать произвольное количество файлов для копирования в TIFF файл.

После запуска процедуры на выполнение выделите в появившемся диалоговом окне Common Dialog файлы, а затем в диалоге Save As укажите спецификацию (путь и имя) TIFF файла, в который будут помещены выбранные изображения.

Первоначально в память считывается первый файл из списка, возвращённого Common Dialog. Если выбран только один файл, то структура EncoderParameters не формируется, а переменной lcEncoderParameters присваивается значение NULL.
Если выбрано несколько файлов, то в структуру помещается информация, определяющая режим записи изображения (т.е. в поле Guid заносится значение EncoderSaveFlag, определяющее идентификатор скрытого метода GDI+, управляющего созданием многокадрового изображения, а параметр, указатель на который хранится в поле Value, получает значение EncoderValueMultiFrame).

Если в TIFF файл записывается более одного кадра, то при помощи функции SYS(2600) значение параметра заменяется на EncoderValueFrameDimensionPage, после чего в цикле последовательно считываются в память остальные файлы из списка, а функция GdipSaveAddImage добавляет полученные изображения к выходному файлу.
Когда все исходные файлы обработаны,  вызывается функция GdipSaveAdd, завершающая запись в выводной файл. Перед вызовом этой функции значение передаваемого в структуре параметра заменяется на EncoderColorDept.

Функция GdipDisposeImage освобождает занимаемую считанным изображением память, а функция GlobalFree возвращает Windows память, распределённую для передаваемого в структуре параметра функцией GlobalAlloc.

Чтение многокадровых TIFF файлов

После считывания многокадрового TIFF файла в память при помощи функции GdipLoadImageFromFile вы должны определить количество размерностей (dimensions) и количество кадров в каждой размерности.

Замечание
GDI+ создаёт TIFF файл только с одной размерностью; по-видимому, другие производители могут создавать многоразмерные TIFF.

Делается это при помощи функций GdipImageGetFrameDimensionsCount, GdipImageGetFrameDimensionsList и GdipImageGetFrameCount.

Функция GdipImageGetFrameDimensionsCount возвращает количество размерностей TIFF файла:

 
lnDim = 0
lnStatus = GdipImageGetFrameDimensionsCount(nativeImage, @lnDim)
  

Функция GdipImageGetFrameDimensionsList заполняет массив значениями GUID размерностей. Перед её вызовом вы должны создать строку для сохранения возвращаемых GUID (т.е. длина этой строки д.б. равна 16 байтам, умноженным на количество размерностей TIFF файла):

 
 lcDimensionIDs = REPLICATE(CHR(0), 16 * lnDim)
 lnStatus = GdipImageGetFrameDimensionsList(nativeImage, @lcDimensionIDs, lnDim)
 

Каждая размерность TIFF файла может содержать произвольное количество кадров. Для того, чтобы получить доступ к этим кадрам, вы должны извлечсь из lcDimensionIDs строку длиной 16 байт конкретного GUID; так, GUID первой размерности располагается, начиная с первого байта строки, GUID второй размерности располагается, начиная с 17-го байта, и т.д.

Функция GdipImageGetFrameCount возвращает количество кадров выбранной размерности:

 
 lcDimensionID = SUBSTR(lcDimensionIDs, 1, 16)  && Извлекаем GUID первой размерности
 lnCount = 0
 lnStatus = GdipImageGetFrameCount(nativeImage, lcDimensionID, @lnCount)
 

Если вы собираетесь извлекать кадры из TIFF файла, созданного средствами GDI+, то, вместо применения рассмотренных выше функций, можете воспользоваться заранее предопределённым значением для lcDimensionID:

 
 #DEFINE FrameDimensionPage   0h86DC627480617E4C8E3FEE7333A7A483
 * Здесь ваш код загрузки TIFF-файла в память
 lnCount = 0
 lnStatus = GdipImageGetFrameCount(nativeImage, FrameDimensionPage, @lnCount)
 
так как GDI+ создаёт одноразмерные TIFF файлы.

Функция GdipImageSelectActiveFrame перемещает указатель внутри области, в которую загружено изображение, на указанный кадр:

 
 lnStatus = GdipImageSelectActiveFrame(nativeImage, lcDimensionID, nFrame)
 

Номер кадра передаётся функции в переменной nFrame. Нумерация кадров начинается с нуля.

После установки указателя на нужный кадр вы можете сохранить его при помощи функции GdipSaveImageToFile или выполнить иные действия, разрешённые в GDI+ (нарисовать в окне формы, распечатать на принтере, рисовать на этом кадре и т.д.).

В листинге 2 приведён код процедуры, извлекающей кадры из TIFF файла
 

 Листинг 2. Процедура извлечения кадров из многокадрового TIFF файла

 
 #DEFINE EncoderClsID_PNG 0h06F47C55041AD3119A730000F81EF32E
 
 LOCAL i, j, lcInputFile, lcOutFolder, lcFile, lnImage, lnCount, lnDim, lnStatus
 LOCAL lcDimensionIDs, lcDimensionID 
 
 DECLARE Long GdipImageGetFrameDimensionsCount IN Gdiplus.dll Long, Long @
 DECLARE Long GdipImageGetFrameDimensionsList IN Gdiplus.dll Long, String @, Long
 DECLARE Long GdipImageGetFrameCount IN Gdiplus.dll Long, String, Long @
 DECLARE Long GdipImageSelectActiveFrame IN Gdiplus.dll Long, String, Long
 DECLARE Long GdipLoadImageFromFile IN Gdiplus.dll String, Long @
 DECLARE Long GdipDisposeImage IN Gdiplus.dll Long
 DECLARE Long GdipSaveImageToFile IN Gdiplus.dll Long, String, String, String

 lcInputFile = GETFILE("tif")
 IF EMPTY(lcInputFile)
    RETURN
 ENDIF 
 lcOutFolder = GETDIR()
 IF EMPTY(lcOutFolder)
    RETURN 
 ENDIF 
 lcFile = STRCONV(lcInputFile + CHR(0), 5)
 lnImage = 0
 lnStatus = GdipLoadImageFromFile(lcFile, @lnImage)
 IF lnStatus > 0
    = MESSAGEBOX("Ошибка чтения файла" + STR(lnStatus))
    RETURN
 ENDIF 

 lnDim = 0
 lnStatus = GdipImageGetFrameDimensionsCount(lnImage, @lnDim)
 IF lnStatus = 0
    lcDimensionIDs = REPLICATE(CHR(0), 16 * lnDim)
    lnStatus = GdipImageGetFrameDimensionsList(lnImage, @lcDimensionIDs, lnDim)
 ENDIF 
 FOR j = 1 TO lnDim                 && Сканирование размерностей
    IF lnStatus = 0
       lcDimensionID = SUBSTR(lcDimensionIDs, 16 * (j - 1) + 1, 16)
       lnCount = 0
       lnStatus = GdipImageGetFrameCount(lnImage, lcDimensionID, @lnCount)
       IF lnStatus = 0
           FOR i = 1 TO lnCount     && Сканирование кадров в размерности
              lnStatus = GdipImageSelectActiveFrame(lnImage, lcDimensionID, i-1)
              IF lnStatus = 0
                  lcFile = lcOutFolder + "Output" + LTRIM(STR(j)) + LTRIM(STR(i)) + ".png"
                  lcFile = STRCONV(lcFile + CHR(0), 5)
                  lnStatus = GdipSaveImageToFile(lnImage, lcFile, EncoderClsID_PNG, NULL)
                  IF lnStatus > 0
                     EXIT
                  ENDIF 
              ENDIF 
           ENDFOR 
        ENDIF 
     ENDIF 
 ENDFOR 

 GdipDisposeImage(lnImage)
 = MESSAGEBOX(IIF(lnStatus = 0, "OK", "Ошибка" + STR(lnStatus)))
 

После запуска процедуры в диалоговом окне Open, вызываемом функцией GetFile(), выберите TIFF файл, и затем в диалоговом окне, вызываемом функцией Getdir(), укажите папку для сохранения кадров в виде отдельных файлов.
Процедура сохраняет кадры в файлах формата PNG, присваивая им имена "OutputNM.png", где "N" — номер размерности, а "M" — номер кадра в размерности.

Использование алгоритмов сжатия

Для формата TIFF вы можете использовать один из следующих алгоритмов сжатия:
 
Наименование в MSDN Значение Описание
 EncoderValueCompressionLZW 2  Сжатие по алгоритму LZW
 EncoderValueCompressionCCITT3 3  Сжатие по алгоритму CCITT3
 EncoderValueCompressionCCITT4 4  Сжатие по алгоритму CCITT4
 EncoderValueCompressionRle 5  Сжатие по алгоритму Rle
 EncoderValueCompressionNone 6  Сжатие не выполняется

В GDI+ по умолчанию используется алгоритм сжатия LZW. Алгоритмы CCITT3, CCITT4 и Rle могут применяться только к монохромным файлам (чёрно-белым), в которых для хранения пикселя используется один бит.

По умолчанию в GDI+ применяется сжатие по алгоритму LWZ. Если вы хотите отменить сжатие или использовать другой алгоритм, то добавьте в структуру EncoderParameters вложенную структуру, полю Guid которой присвойте значение EncoderCompression.

Замечание
Алгоритм LWZ по эффективности сжатия сопоставим с JPEG; качество изображения при таком сжатии теряется. Поэтому, если вам необходимо сохранить высокое качество изображения, откажитесь от его сжатия.

В следующем фрагменте кода показано формирование структуры EncoderParameters для создания многокадрового TIFF без сжатия исходных файлов.

 
 #DEFINE EncoderSaveFlag                 0hFC66222940ACBF478CFCA85B89A655DE
 #DEFINE EncoderCompression              0h9D739DE0D4CCEE448EBA3FBF8BE4FC58
 #DEFINE EncoderValueMultiFrame          18
 #DEFINE EncoderValueFlush               20
 #DEFINE EncoderValueFrameDimensionPage  23 
 #DEFINE EncoderValueCompressionNone     6 
 
 hGlobalMulti = GlobalAlloc(0x0040, 4)   && Распределяем глобальную память
 hGlobalCompr = GlobalAlloc(0x0040, 4)   &&
 
 = SYS(2600, hGlobalMulti, 4, BINTOC(EncoderValueMultiFrame, "4RS")
 = SYS(2600, hGlobalCompr, 4, BINTOC(EncoderValueCompressionNone, "4RS")

 lcEncoderParams = BINTOC(2, "4RS")                              && 2 вложенных структуры 
 lcEncoderParams = lcEncoderParams + EncoderSaveFlag             && Поле Guid 1-й структуры
 lcEncoderParams = lcEncoderParams + BINTOC(1, "4RS")            && Поле NumberOfValues
 lcEncoderParams = lcEncoderParams + BINTOC(4, "4RS")            && Поле Type
 lcEncoderParams = lcEncoderParams + BINTOC(hGlobalMulti, "4RS") && Поле Value
 lcEncoderParams = lcEncoderParams + EncoderCompression          && Поле Guid 2-й структуры
 lcEncoderParams = lcEncoderParams + BINTOC(1, "4RS")            && Поле NumberOfValues
 lcEncoderParams = lcEncoderParams + BINTOC(4, "4RS")            && Поле Type
 lcEncoderParams = lcEncoderParams + BINTOC(hGlobalCompr, "4RS") && Поле Value
 

Как видите, для каждой вложенной структуры распределяется глобальная память Windows; указатели на распределённые блоки хранятся в переменных hGlobalMulti и hGlobalCompr. Не забудьте вернуть эту память после создания TIFF файла!

Управление количеством бит на пиксель

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

Для управления количеством бит на пиксель вы должны добавить в структуру EncoderParameters вложенную структуру, присвоив её полю Guid значение EncoderColorDept. Так же распределите для этой структуры блок памяти, указатель на которую поместите в поле Value. Запишите в распределённую память значение количества бит на пиксель.