Язык программирования Delphi, работа с графикой Читаем PSD фалы:
Сегодня, как я и обещал я выкладываю пример на Delphi, который умеет загружать и отображать PSD файлы. На его написание я потратил три дня, и надеюсь, что проведённое мною время за компом окажется тебе полезным. Для понимания работы примера, тебе надо прочитать мои статьи про формат файла PSD.
На рисунке 1 ты можешь видеть форму сегодняшнего примера. Хотя тебе не придётся её создавать, потому что я не буду рассматривать весь исходник. Поэтому тебе придётся скачать мой в конце статьи.
Рис 1. Форма
Для реализации чтения, я создал компонент TPSDGraphic. Его я произвёл из TBitmap:
TPSDGraphic = class(TBitmap)
private
FPalette: array[0..767] of Byte;
procedure MakePalette(BPS: Byte; Mode: Integer);
public
procedure LoadFromStream(Stream: TStream); override;
end;
Анекдот:
Разговаривают два программиста.
- Слушай, вчера написал новый архиватор. Любой файл сжимает в 5 байт.
- Ну просто рулез!
- Ага. Сейчас работаю над разархиватором
TPSDGraphic = class(TBitmap) - означает, что TPSDGraphic происходит из TBitmap. А это означает что TPSDGraphic будет обладать теми же свойствами, что и TBitmap, и плюс то что объявил я. Для того, чтобы мой объект умел читать PSD файлы, я переписал функцию LoadFromStream объекта TBitmap. "override" в конце строки объявления означает, что я переписал функцию.
Теперь о моём примере. На форму я бросил одну кнопку и TImage. По нажатию кнопки я написал:
procedure TForm1.Button1Click(Sender: TObject);
var
r:TPSDGraphic;
begin
r:=TPSDGraphic.Create; //Создаю объект TPSDGraphic
r.LoadFromFile('1.psd'); //Загружаю его
Image1.Picture.Bitmap.Assign(r);// Копирую в TImage
r.Free; //Освобождаю объект
end;
Теперь посмотрим на кусочек от функции чтения файла:
procedure TPSDGraphic.LoadFromStream(Stream: TStream);
var
Header: TPSDHeader;
Count: Integer;
Compression: Word;
Decoder: TPackbitsRLE;
RLELength: array of Word;
Y: Integer;
BPS: Integer;
ChannelSize: Integer;
RawBuffer, Buffer: Pointer;
Run1, Run2, Run3, Run4: PByte;
Begin
with Stream do
begin
//Читаю из файла заголовок
ReadBuffer(Header, SizeOf(Header));
//Проверяю сигнатуру. Если она не равна 8BPS, то это не PSD файл
if Header.Signature <> '8BPS' then
raise Exception.Create('Неверный файл.');
//Теперь переворачиваю байты у всех параметров заголовка.
//Помнишь, я говорил про то, что в этом файле все байты перевёрнутые?
//Если не помнишь, то перечитай статью про формат PSD
with Header do
begin
Channels := Swap(Channels);
Rows := SwapLong(Rows);
Columns := SwapLong(Columns);
Depth := Swap(Depth);
Mode := Swap(Mode);
end;
//Определяю формат пиксела
case Header.Mode of
PSD_BITMAP: PixelFormat := pf1Bit;
PSD_DUOTONE, PSD_GRAYSCALE, PSD_INDEXED: PixelFormat := pf8Bit;
PSD_RGB: PixelFormat := pf24Bit;
PSD_CMYK: PixelFormat := pf24Bit;
PSD_MULTICHANNEL: ;
PSD_LAB: PixelFormat := pf24Bit;
end;
//Читаю размер следующего блока.
ReadBuffer(Count, SizeOf(Count));
Count := SwapLong(Count);
// Если должна существовать палитра, то читаю её
if Header.Mode in [PSD_BITMAP, PSD_GRAYSCALE, PSD_INDEXED] then
begin
if Header.Mode = PSD_INDEXED then ReadBuffer(FPalette, Count);
MakePalette(Header.Depth, Header.Mode);
end;
//Устанавливаю ширину и высоту.
Width := Header.Columns;
Height := Header.Rows;
//Проскакиваю следующие два блока, потому что я слишком мало о них знаю,
//да и для простого отображения эти блоки не нужны. Эти блоки важны при
//обработке изображений, а на отображение содержимого практически не
//влияют.1
ReadBuffer(Count, SizeOf(Count));
Count := SwapLong(Count);
Seek(Count, soFromCurrent);
ReadBuffer(Count, SizeOf(Count));
Count := SwapLong(Count);
Seek(Count, soFromCurrent);
// Обнуляю буфер
RawBuffer := nil;
// Читаю флаг компрессии
ReadBuffer(Compression, SizeOf(Compression));
Compression := Swap(Compression);
//Если данные сжаты то распаковываю их
if Compression = 1 then
Расппаковать
Else
Читать как есть
End;
Это кратенький алгоритм работы моей проги. Описать всю прогу нереально, потому что это займёт много времени. Если ты уже достаточно разобрался с программированием, то у тебя не возникнет проблем. Если нет, то всё ещё впереди. Если будешь работать над собой, то скоро со всем разберёшься.