program macps;
(*
 * M. Kaczmarczik 12-Sep-85
 *
 * Utility for converting MacPaint files into ones suitable for
 * including in a Scribe document.
 * 
 * Credits:
 *
 * The conversion code and PostScr ipt prelude are from J. W. Peterson's
 * extract_top program for the LaserWriter.  The command parsing and
 * general style were inspired by E. Lavitsky's MacQms.
 *
 * History:
 *
 * 12-Sep-85	MPK	Initial version
 *)

include 'pas:pascmd.pas';
include 'pas:jsys.pas';

const
	Line_W_Def	= 52; 		(* Default # of bytes to extract *)
	S_Line_W_Def 	= '52 ';	(* Default is width of MacPaint *)
	Mac_H_Bytes	= 72;		(* window *)

	ScanlinesDef	= 240;		(* # of vertical scan lines to get *)
	S_ScanlinesDef  = '240 ';	(* Default is height of MacPaint *)
	Mac_V_Scan	= 720;		(* window *)

	ColumnDef	= 6.5;		(* Width of column in which to  *)
	S_ColumnDef	= '6.5 ';	(* center the image *)

       	HeightDef	= 3;		(* Default image height. *)
	S_HeightDef	= '3 ';		(* Image width depends on height *)

	UpDef		= 0;		(* Amount to move image up relative *)
	S_UpDef		= '0 ';		(* to the defined area on page *)

	PsCodefile	= 'uns:macps.ps'; (* Prelude file *)

type
	byte		= 0..377B;

var
	Mac_filename	: packed array[1..80] of char;
	Ps_filename	: packed array[1..80] of char;
	
	Mac_file	: file of byte;
	Mac_length	: integer;

	Ps_file		: file of char;
	Ps_length	: integer;

	Ps_Code		: text;

	current_line	: integer;	(* Counter *)

	change		: integer;	(* Used as a boolean for *)
	yes_no		: table;	(* Yes/No questions *)

	(* Parameters for postscript code *)
	columnwidth	: real;		(* Width of Scribe column *)
	height		: real;		(* Height of area on page *)
	up 		: real;		(* Vertical displacement *)
	invert		: boolean;	(* Should pixels be inverted? *)

	line_width	: integer;	(* Width of bitmap in bytes *)
	scanlines	: integer;	(* Height of bitmap in bits *)

procedure init;
(* Define all parameters, set up command table *)
begin (* init *)
	scanlines := ScanlinesDef;
	height := Heightdef;
	columnwidth := Columndef;
	line_width := Line_W_Def;
	up := Updef;
	invert := false;

	yes_no := tbmak(2);
	tbadd(yes_no,0,'No',0);
	tbadd(yes_no,1,'Yes',0);
end; (* init *)

procedure get_files;
(* Get file names from user *)
begin (* get_files *)
	cmini('Mac filename: ');
	cmhlp('Name of Mac file to convert ');
	cmifi(Mac_file);
	Mac_length := cmatom(Mac_filename);
	cmcfm;

	cmini('Output filename: ');
	cmhlp('Name of output file ');
	gjgen(400000000000B);
	gjext('PS');
	cmfil(Ps_file);
	Ps_length := cmatom(Ps_filename);
	cmcfm;

	reset(Mac_file,Mac_filename,'/B:08');
	rewrite(Ps_file,Ps_filename);
end; (* get_files *)

procedure get_page_params;
(* Change parameters having to do with the Scribe document page *)
begin (* get_page_params *)
    cmini('Image height: ');
    cmhlp('Height desired for image (in inches) ');
    cmdef(S_HeightDef);
    Height := cmflt;
    cmcfm;

    cmini('Scribe column width: ');
    cmhlp('Width of text columns in document');
    cmdef(S_ColumnDef);
    ColumnWidth := cmflt;
    cmcfm;

    cmini('Upward translation: ');
    cmhlp('Distance to move image up, in inches');
    cmdef(S_UpDef);
    Up := cmflt;
    cmcfm;
end; (* get_page_params *)

procedure get_doc_params;
(* Get info having to do with the MacPaint document *)
begin (* get_doc_params *)
    repeat
       cmini('Vertical scan lines: ');
       cmhlp('Number of scan lines to extract');
       cmdef(S_ScanlinesDef);
       scanlines := cmnum;
       cmcfm;
       if (scanlines < 1) or (scanlines > Mac_V_Scan) then
	  writeln(tty,'Scan lines must be between 1 and ',Mac_V_Scan:1);
    until (scanlines >= 1) and (scanlines <= Mac_V_Scan);

    repeat
       cmini('Horizontal Line Width: ');
       cmhlp('Number of bytes to extract from scan line');
       cmdef(S_Line_W_Def);
       Line_Width := cmnum;
       cmcfm;
       if (Line_Width < 1) or (Line_Width > Mac_H_Bytes) then
	  writeln(tty,'Number of bytes must be between 1 and ',Mac_H_Bytes:1);
    until (Line_Width >= 1) and (Line_Width <= Mac_H_Bytes);

    cmini('Inverted image? ');
    cmhlp('Exchange black and white pixels (Yes or No)');
    cmdef('No ');
    Invert := cmkey(yes_no) = 1;
    cmcfm;
end; (* get_doc_params *)


procedure discard_macpaint_header;
(* Read away the first .5K of the document, since we don't use it *)
var
	i : integer;
	b : byte;
begin (* discard_macpaint_header *)
    for i := 1 to 512 do
	read(Mac_file,b);    
end; (* discard_macpaint_header *)

procedure copy_ps_code;
(* Put the PostScript prelude in the output file *)
var
    	ch : char;
begin (* copy_ps_code *)
    reset(Ps_Code,PsCodeFile);
    while not eof(Ps_Code) do begin
	while not eoln(Ps_Code) do
	    begin
		read(Ps_Code,ch);
		write(Ps_File,ch);
	    end;
	readln(Ps_Code);
	writeln(Ps_File);
    end;
    close(Ps_Code);
end; (* copy_ps_code *)


procedure scan_a_line;
(* Read in one scan line of data and encode it in hex.
 * Only the first line_width bytes are encoded.
 *)
var
	in_pos		: integer;	(* Byte position in scan line *)
	count		: integer;	(* Count byte from file *)
	mcount		: integer;	(* Count byte for encoding *)
	data_byte	: byte;
	repeat_byte     : byte;
	n 		: integer;	(* counter *)

begin (* scan_a_line *)
    in_pos := 0;
    while (in_pos < Mac_H_Bytes) do
	begin
	    read(Mac_file,count);
	    if count > 127 then
		count := count - 256;

	    mcount := abs(count);	(* see how many bytes we may write *)

	    if (mcount + in_pos >= line_width) then (* must truncate *)
		mcount := line_width - 1 - in_pos;

	    if count < 0 then 		(* restore the sign *)
		mcount := -mcount;

	    if (in_pos < line_width) then
		write(Ps_file,((mcount + 256) mod 256):2:h);

	    if (count >= 0) then (* string of count + 1 data bytes *)
		for n := count downto 0 do
		    begin
			read(Mac_file,data_byte);
		    	if (in_pos < line_width) then
			    write(Ps_file,data_byte:2:h);
      	   	        in_pos := in_pos + 1;
		    end
	    else (* Count + 1 compressed bytes *)
		begin
		    read(Mac_file,repeat_byte);
		    if (in_pos < line_width) then
		        write(Ps_file,repeat_byte:2:h);
		    in_pos := in_pos - count + 1; (* count < 0, so subtract *)
		end;
	
	end; (* while in_pos < Mac_H_Bytes *)

	if (in_pos > Mac_H_Bytes) then (* error -- probably a bad file *)
	   begin
	      writeln(tty,' [FAILED]');
	      writeln(tty,'Input file is not a Mac bitmap file');
	      close(Mac_File);
	      jsys(haltf);
	   end;
	writeln(Ps_file);
end;

begin (* main program *)
    init;
    writeln(tty,'MacPs -- MacPaint to Postscript converter');
    get_files;

    cmini('Change MacPaint image parameters? ');
    cmhlp('Yes or No ');
    cmdef('No ');
    change := cmkey(yes_no);
    cmcfm;
    if (change = 1) then
	get_doc_params;

    cmini('Change Scribe page parameters? ');
    cmhlp('Yes or No ');
    cmdef('No ');
    change := cmkey(yes_no);
    cmcfm;
    if (change = 1) then
	get_page_params;

    discard_macpaint_header;
    copy_ps_code;

    (* if invert is false, postscript code needs a 1 *)
    write(Ps_file,ord(Invert = false):1,' ',line_width:3,' ',scanlines:3,' ');
    writeln(Ps_file,columnwidth:8:6,' ',height:8:6,' ',up:8:6);
       
    write(tty,'Processing file ',Mac_Filename:Mac_Length,'... ');
    for current_line := 1 to scanlines do
	scan_a_line;
    writeln(tty,'[OK]');
end.

