program PCXShow;

uses
  crt, dos;

type
  ImgInfoHeader = record { вот это и есть запись. описывающая заголовок}
    Manufacturer : Byte;
    Version      : Byte;
    Encoding     : Byte;
    BitsPerPixel : Byte;
    Xmin, Ymin,
    Xmax, YMax   : Integer;
    HDPI         : Integer;
    VDPI         : Integer;
    Colormap     : array [0..15, 1..3] of Byte;
    Reserved     : Byte;
    NPlanes      : Byte;
    BytesPerLine : Integer;
    PaletteInfo  : Integer;
    Filler       : array [1..58] of Byte;
  end;
  ColType = record
    R, G, B : Byte;
  end;
  PalType = array [0..255] of ColType; {для удобства, палитру будем хранить в массиве}

procedure Set13h; {Устанавливаем режим экрана 320x200x256цветов}
var
  Rp : Registers;
begin
  Rp.Ax := $0013;
  Intr($10, Rp);
end;

procedure SetText; {Возвращаем текстовый режим}
var
  Rp : Registers;
begin
  Rp.Ax := $0003;
  Intr($10, Rp);
end;

procedure PutPixel(x, y : Integer; Color : Byte); {Записываем пиксель в видеопамять}
begin
  Mem[$A000:X+(Y*320)] := Color;
end;

procedure SetPal(ColorNo : Byte; R, G, B : Byte); {Задаёт цвету за номером ColorNo соответствующие значения RGB}
begin                                             
  Port[$3c8] := ColorNo;
  Port[$3c9] := R;
  Port[$3c9] := G;
  Port[$3c9] := B;
end;

procedure ShowPCX(x, y : integer; FileName : string); {Собственно сама процедура для вывода PCX}
var
  Img           : file;
  ImgHeader     : ImgInfoHeader;
  x_cur, y_cur  : Integer;
  i, b1, b2     : Byte;
  Pal           : PalType;
begin
  Assign(Img, FileName); {Инициализируем файловую переменную}
  Reset(Img, 1); {Открываем файл как нетипизированный}
  BlockRead(Img, ImgHeader, 128); {Считываем заголовок (128 байт!)}
  Seek(Img, FileSize(Img) - 768); {Находим конец файла и отступаем 768(размер палитры!) байт назад}
  BlockRead(Img, Pal, 768); {Считываем палитру}
  for i := 0 to 255 do {Для каждого из 256 цветов выполняем:}
  with Pal[i] do
  begin
    R := R shr 2; {shr 2 - это сдвиг всех битов в переменной на 2 позиции вправо}
    G := G shr 2; {это аналогично целочисленному делению на 4}
    B := B shr 2; {В файле значения R,G,B лежат в диапазоне 0..255. Зачем делить? Смотри ниже.}
    SetPal(i, R, G, B); {Устанавливаем цвет. Вот здесь значения RGB должны быть 0..63. Затем и делили}
  end;
  Seek(Img, 128); {Устанавливаем указатель сразу после заголовка}
  x_cur := 0; y_cur := 0; {Это координаты текущей точки рисунка} 
  while y_cur < ImgHeader.VDPI do {Выполняем, пока координата y_cur меньше высоты рисунка}
  begin
    BlockRead(Img, b1, 1); {Читаем байт}
    if ((b1 and $c0) = $c0) then {Это мы так мудрёно проверяем, установлены ли 2 старших бита}
    begin
      {Если установлены, значит младшие 6 младших битов содержат значение, }
      {указывающее, сколко раз следующий байт должен быть выведен на экран}
      BlockRead(Img, b2, 1); {Считываем этот самый следующиий байт}
      for i := 1 to (b1 and $3f) do {b1 and $3f - 'это мы получаем значение из младших 6 битов}
      begin
        PutPixel(x + x_cur, y + y_cur, b2); {Выводим пиксель}
        Inc(x_cur); {Увеличиваем x_cur}
        if x_cur > ImgHeader.HDPI - 1 then {Если x_cur больше ширины рисунка, значит}
        begin
          x_cur := 0; {x_cur в ноль}
          Inc(y_cur); {y_cur увеличиваем}
        end;
      end;
    end
    else
    begin
      {Если не установлены, значит просто выводим пиксель на экран}
      PutPixel(x + x_cur, y + y_cur, b1);
      Inc(x_cur);
      if x_cur > ImgHeader.HDPI - 1 then
      begin
        x_cur := 0;
        Inc(y_cur);
      end;
    end;
  end;
  Close(Img); {закрыли файл..............Уффф...Всё! :)}
end;

begin
  Set13h;
  ShowPCX(1, 1, '001.pcx');{}
  ReadKey;
  SetText;
end.