VR
Virtual Reality On-line   Delphi
Новости   |     Журнал    |    Хаkер   |     Магазин   |   Проекты
[   Вход    ]
[Kарта сайтa]
[ Download  ]
[  Конкурс  ]
[  Анекдоты ]
[  Ссылки   ]
[  Реклама  ]
[ Почтальон ]
[ О проекте ]






TopList
Язык программирования Delphi, работа с графикой
Читаем PSD фалы
:
Logo

Сегодня, как я и обещал я выкладываю пример на Delphi, который умеет загружать и отображать PSD файлы. На его написание я потратил три дня, и надеюсь, что проведённое мною время за компом окажется тебе полезным. Для понимания работы примера, тебе надо прочитать мои статьи про формат файла PSD.

На рисунке 1 ты можешь видеть форму сегодняшнего примера. Хотя тебе не придётся её создавать, потому что я не буду рассматривать весь исходник. Поэтому тебе придётся скачать мой в конце статьи.
Logo
Рис 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;

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

Удачи!!!

 Исходники примера забирай здесь


Copyright©: Horrific aka Флёнов Михаил
Design by FMk group©