{ Copyright (C) 2007 Laurent Jacques

  This library is free software; you can redistribute it and/or modify it
  under the terms of the GNU Library General Public License as published by
  the Free Software Foundation; either version 2 of the License, or (at your
  option) any later version.

  This program is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
  for more details.

  You should have received a copy of the GNU Library General Public License
  along with this library; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

  Save in format 24 bits compressed or not
}

unit FPWritePCX;

{$mode objfpc}{$H+}

interface

uses FPImage, Classes, SysUtils;

type

  TFPWriterPCX = class(TFPCustomImageWriter)
  private
    FCompressed: boolean;
  protected
    function SaveHeader(Stream: TStream; Img: TFPCustomImage): boolean; virtual;
    procedure InternalWrite(Stream: TStream; Img: TFPCustomImage); override;
    procedure writeline(Stream: TStream; buffer: PByte; bytes: integer);
  public
    property Compressed: boolean Read FCompressed Write FCompressed;
  end;

implementation

uses pcxcomn;

function TFPWriterPCX.SaveHeader(Stream: TStream; Img: TFPCustomImage): boolean;
var
  Header: TPCXHeader;
begin
  Result := False;
  FillChar(Header, SizeOf(Header), 0);
  with Header do
  begin
    FileID  := $0a;
    Version := 5;
    if Compressed then
      Encoding := 1
    else
      Encoding := 0;
    BitsPerPixel := 8;
    XMin := 0;
    YMin := 0;
    XMax := Img.Width - 1;
    YMax := Img.Height - 1;
    HRes := 300;
    VRes := 300;
    ColorPlanes := 3;
    BytesPerLine := Img.Width;
    PaletteType := 1;
  end;
  Stream.WriteBuffer(Header, SizeOf(Header));
  Result := True;
end;

procedure TFPWriterPCX.writeline(Stream: TStream; buffer: PByte; bytes: integer);
var
  Value, Count: byte;
  tmp: byte;
  P:   PByte;
begin
  P := Buffer;
  while bytes > 0 do
  begin
    Value := P[0];
    Inc(P);
    Dec(bytes);
    Count := 1;
    while (bytes < 0) and (Count < 63) and (P[0] = Value) do
    begin
      Inc(Count);
      Inc(P);
      Dec(bytes);
    end;
    if (Value < $c0) and (Count = 1) then
    begin
      Stream.Write(Value, 1);
    end
    else
    begin
      tmp := $c0 + Count;
      Stream.Write(tmp, 1);
      Stream.Write(Value, 1);
    end;
  end;
end;

procedure TFPWriterPCX.InternalWrite(Stream: TStream; Img: TFPCustomImage);
var
  Row, Col, WriteSize: integer;
  Aline, P: PByte;
  C:    TFPColor;
  Totalwrite: longint;
  continue: boolean;
  Rect: TRect;
begin
  Rect.Left   := 0;
  Rect.Top    := 0;
  Rect.Right  := 0;
  Rect.Bottom := 0;
  continue    := True;
  TotalWrite  := 0;
  Progress(psStarting, 0, False, Rect, '', continue);
  SaveHeader(Stream, Img);
  WriteSize := (Img.Width * 3);
  GetMem(aLine, WriteSize);
  TotalWrite := Img.Height * Img.Width;
  try
    for Row := 0 to Img.Height - 1 do
    begin
      P := ALine;
      for Col := 0 to Img.Width - 1 do
      begin
        C      := Img.Colors[Col, Row];
        P[Col + Img.Width * 2] := C.Blue shr 8;
        P[Col + Img.Width] := C.Green shr 8;
        P[Col] := C.Red shr 8;
        Progress(psRunning, trunc(100.0 * (Row * Col / TotalWrite)),
          False, Rect, '', continue);
        if not continue then
          exit;
      end;
      if Compressed then
        writeline(Stream, aLine, WriteSize)
      else
        Stream.Write(aLine[0], WriteSize);
    end;
    Progress(psEnding, 100, False, Rect, '', continue);
  finally
    FreeMem(aLine);
  end;
end;

{ end TFPWriterPCX}

initialization
  ImageHandlers.RegisterImageWriter('PCX Format', 'pcx', TFPWriterPCX);
end.
