home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d3xx
/
d394
/
printimage.lha
/
PrintImage
/
PrintImage.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-28
|
19KB
|
991 lines
/* $Revision Header * Header built automatically - do not edit! *************
*
* (C) Copyright 1990 by MXM
*
* Name .....: PrintImage.c
* Created ..: Saturday 15-Sep-90 14:16
* Revision .: 1
*
* Date Author Comment
* ========= ======== ====================
* 15-Sep-90 Olsen Created this file!
*
* $Revision Header ********************************************************/
/* Remove this definition if you don't need it (see below). */
/*#define CITIZEN_SWIFT_24 1*/
/* Prototypes for this module. */
VOID CloseAll(BYTE ReturnCode);
VOID OpenAll(VOID);
VOID FreeImage(VOID);
BYTE LoadImage(char *Name);
ULONG FindChunk(ULONG ChunkName,FILE *FilePointer);
LONG LoadHeader(char *FileName,BitMapHeader *BMHeader);
BYTE LoadCMAP(char *FileName,BYTE Colours[32][3],LONG MaxCol,BitMapHeader *BMHeader);
BYTE LoadRaster(char *FileName,PLANEPTR *BitPlanes,BitMapHeader *BMHeader);
VOID main(VOID);
/* Global and shared library identifiers. */
extern struct ExecBase *SysBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct ReqLib *ReqBase;
/* Window and process data. */
struct Window *Window;
struct Process *ThisProcess;
/* Printer IO. */
struct MsgPort *PrintPort;
struct IODRPReq *PrintRequest;
struct IOStdReq *PrintStdReq;
/* File requester and associated data. */
struct FileRequester LoadFileReq;
char FileName[FCHARS],DirectoryName[DSIZE],Buffer[FCHARS + DSIZE + 2];
/* Image data. */
struct BitMap ImageBitMap;
struct RastPort ImageRastPort;
struct ColorMap *ImageColourMap;
BitMapHeader ImageBitMapHeader;
LONG ImageModes;
BYTE HasImage;
/* Window data. */
struct IntuiMessage *Massage;
ULONG Class;
USHORT Code;
BYTE GadgetID,i;
/* The four gadgets. */
char *GadgetTexts[] =
{
"Load new image",
"Print current image",
"Stop printing",
"Exit program"
};
/* Define the number of gadgets. */
#define NUMGADS (sizeof(GadgetTexts) / sizeof(char *))
/* Present a fitting number of gadget blocks. */
struct GadgetBlock GadgetBlocks[NUMGADS];
/* A window definition. */
struct NewWindow NewWindow =
{
0,0,
0,0,
0,1,
CLOSEWINDOW | GADGETUP,
WINDOWDEPTH | WINDOWDRAG | WINDOWCLOSE | RMBTRAP | ACTIVATE,
(struct Gadget *)NULL,
(struct Image *)NULL,
(STRPTR)"PrintImage",
(struct Screen *)NULL,
(struct BitMap *)NULL,
~0,~0,
~0,~0,
WBENCHSCREEN
};
/* A Zz... mouse pointer. */
USHORT ElecArtsWaitPointer[(22 + 2) * 2] =
{
0x0000,0x0000,
0x6700,0xC000,
0xCFA0,0xC700,
0xBFF0,0x0FA0,
0x70F8,0x3FF0,
0x7DFC,0x3FF8,
0xFBFC,0x7FF8,
0x70FC,0x3FF8,
0x7FFE,0x3FFC,
0x7F0E,0x3FFC,
0x3FDF,0x1FFE,
0x7FBE,0x3FFC,
0x3F0E,0x1FFC,
0x1FFC,0x07F8,
0x07F8,0x01E0,
0x01E0,0x0080,
0x07C0,0x0340,
0x0FE0,0x07C0,
0x0740,0x0200,
0x0000,0x0000,
0x0070,0x0020,
0x0078,0x0038,
0x0038,0x0010,
0x0000,0x0000
};
/* A macro to attach the mouse pointer to a window. */
#define SetWait(Window) SetPointer(Window,ElecArtsWaitPointer,22,16,0,0)
/* CloseAll():
*
* Closes all resources and returns to the shell.
*/
VOID
CloseAll(BYTE ReturnCode)
{
ThisProcess -> pr_WindowPtr = NULL;
PurgeFiles(&LoadFileReq);
FreeImage();
if(Window)
CloseWindow(Window);
if(PrintRequest)
{
if(PrintRequest -> io_Device)
{
/* The following code puts the Citicen Swift 24
* printer back into Epson emulation mode.
*/
#ifdef CITIZEN_SWIFT_24
PrintStdReq -> io_Command = PRD_RAWWRITE;
PrintStdReq -> io_Data = (APTR)"\33~5\0";
PrintStdReq -> io_Length = 4;
DoIO(PrintStdReq);
#endif /* CITIZEN_SWIFT_24 */
CloseDevice(PrintRequest);
}
DeleteExtIO(PrintRequest);
}
if(PrintPort)
DeletePort(PrintPort);
if(ReqBase)
CloseLibrary(ReqBase);
exit(ReturnCode);
}
/* OpenAll():
*
* Open all resources to start the program.
*/
VOID
OpenAll()
{
SHORT MaxWidth = 0,TempWidth;
BYTE i;
ThisProcess = (struct Process *)SysBase -> ThisTask;
if(!(ReqBase = (struct ReqLib *)OpenLibrary("req.library",0)))
CloseAll(RETURN_FAIL + 1);
IntuitionBase = ReqBase -> IntuiLib;
GfxBase = ReqBase -> GfxLib;
if(!(PrintPort = (struct MsgPort *)CreatePort(NULL,0)))
CloseAll(RETURN_FAIL + 2);
if(!(PrintRequest = (struct IODRPReq *)CreateExtIO(PrintPort,sizeof(struct IODRPReq))))
CloseAll(RETURN_FAIL + 3);
PrintStdReq = (struct IOStdReq *)PrintRequest;
if(OpenDevice("printer.device",0,PrintRequest,NULL))
CloseAll(RETURN_FAIL + 4);
/* The following lines will put the Citizen Swift 24
* printer into NEC P6+ emulation mode. Since the
* Workbench EpsonQ printer driver only permits
* to print with a maximum resolution of 360×180 dpi
* this provides a convenient way to work with the
* Nec_Pinwriter driver without having to reselect
* the emulation manually.
*/
#ifdef CITIZEN_SWIFT_24
PrintStdReq -> io_Command = PRD_RAWWRITE;
PrintStdReq -> io_Data = (APTR)"\33~5\2";
PrintStdReq -> io_Length = 4;
if(DoIO(PrintStdReq))
CloseAll(RETURN_FAIL + 4);
#endif /* CITIZEN_SWIFT_24 */
/* The following piece of code adapts the
* window to the number and the dimensions of
* the gadgets.
*/
for(i = 0 ; i < NUMGADS ; i++)
{
if((TempWidth = 8 * strlen(GadgetTexts[i]) + 4) > MaxWidth)
MaxWidth = TempWidth;
}
NewWindow . Width = MaxWidth + 8;
for(i = 0 ; i < NUMGADS ; i++)
{
LinkGadget(&GadgetBlocks[i],GadgetTexts[i],&NewWindow,((NewWindow . Width - (8 * strlen(GadgetTexts[i]) + 4)) >> 1) + 2,13 + (5 + 8) * i);
GadgetBlocks[i] . Gadget . GadgetID = i;
}
NewWindow . Height = 11 + ((5 + 8) * NUMGADS + 1);
Center(&NewWindow,GadgetBlocks[0] . Gadget . LeftEdge + (GadgetBlocks[0] . Gadget . Width >> 1),GadgetBlocks[0] . Gadget . TopEdge + (GadgetBlocks[0] . Gadget . Height >> 1));
if(!(Window = (struct Window *)OpenWindow(&NewWindow)))
CloseAll(RETURN_FAIL + 5);
for(i = 1 ; i < NUMGADS - 1 ; i++)
OffGadget(&GadgetBlocks[i] . Gadget,Window,NULL);
LoadFileReq . PathName = Buffer;
LoadFileReq . Title = GadgetTexts[0];
LoadFileReq . dirnamescolor = 3;
LoadFileReq . devicenamescolor = 3;
LoadFileReq . Window = Window;
LoadFileReq . Dir = DirectoryName;
LoadFileReq . File = FileName;
LoadFileReq . Flags = FRQCACHINGM | FRQINFOGADGETM | FRQNOHALFCACHEM | FRQLOADINGM;
LoadFileReq . blockcolor = 1;
ThisProcess -> pr_WindowPtr = (APTR)Window;
}
/* FreeImage():
*
* Free the data associated with the image in memory.
*/
VOID
FreeImage()
{
if(ImageColourMap)
FreeColorMap(ImageColourMap);
if(ImageBitMap . Planes[0])
FreeMem(ImageBitMap . Planes[0],ImageBitMap . Depth * ImageBitMap . BytesPerRow * ImageBitMap . Rows);
HasImage = FALSE;
}
/* PrintImage():
*
* Print the image in memory according to the current
* Preferences settings.
*/
VOID
PrintImage()
{
ULONG SignalSet;
SHORT i;
/* Standard system hardcopy. */
PrintRequest -> io_Command = PRD_DUMPRPORT;
PrintRequest -> io_RastPort = &ImageRastPort;
PrintRequest -> io_ColorMap = ImageColourMap;
PrintRequest -> io_Modes = ImageModes;
PrintRequest -> io_SrcWidth = ImageBitMapHeader . w;
PrintRequest -> io_SrcHeight = ImageBitMapHeader . h;
PrintRequest -> io_SrcX = 0;
PrintRequest -> io_SrcY = 0;
PrintRequest -> io_DestCols = ImageBitMapHeader . w;
PrintRequest -> io_DestRows = ImageBitMapHeader . h;
PrintRequest -> io_Special = SPECIAL_ASPECT | SPECIAL_TRUSTME;
/* Block all gadgets save one. */
for(i = 0 ; i < NUMGADS ; i++)
{
if(i != 2)
OffGadget(&GadgetBlocks[i] . Gadget,Window,NULL);
else
OnGadget(&GadgetBlocks[i] . Gadget,Window,NULL);
}
/* Sleep... */
SetWait(Window);
/* ...and fire off the printer dump. */
BeginIO(PrintRequest);
FOREVER
{
/* Wait for 'stop' or printer to finish. */
SignalSet = Wait((1 << PrintPort -> mp_SigBit) | (1 << Window -> UserPort -> mp_SigBit));
if(SignalSet & (1 << PrintPort -> mp_SigBit))
{
while(GetMsg(PrintPort));
break;
}
if(SignalSet & (1 << Window -> UserPort -> mp_SigBit))
{
while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
{
Class = Massage -> Class;
Code = Massage -> Code;
GadgetID = ((struct Gadget *)Massage -> IAddress) -> GadgetID;
ReplyMsg((struct Message *)Massage);
if(Class == GADGETUP && GadgetID == 2)
{
AbortIO(PrintRequest);
WaitIO(PrintRequest);
goto Quit;
}
}
}
}
Quit: ClearPointer(Window);
for(i = 0 ; i < NUMGADS ; i++)
{
if(i != 2)
OnGadget(&GadgetBlocks[i] . Gadget,Window,NULL);
else
OffGadget(&GadgetBlocks[i] . Gadget,Window,NULL);
}
}
/* LoadImage():
*
* Loads an IFF-ILBM file and prepares it for the graphic
* dump.
*/
BYTE
LoadImage(char *Name)
{
BYTE Colours[32][3];
ULONG PageSize;
BYTE i,MaxCol;
/* Load the view modes. */
if((ImageModes = LoadHeader(Name,&ImageBitMapHeader)) != -1)
{
/* Load the colour table. */
if(MaxCol = LoadCMAP(Name,Colours,32,&ImageBitMapHeader))
{
/* Initialize the bitmap. */
InitBitMap(&ImageBitMap,ImageBitMapHeader . nPlanes,ImageBitMapHeader . w,ImageBitMapHeader . h);
/* Don't forget the rastport. */
InitRastPort(&ImageRastPort);
/* Put the bitmap into the rastport. */
ImageRastPort . BitMap = &ImageBitMap;
/* Calculate the size of a single bitplane. */
PageSize = ImageBitMap . BytesPerRow * ImageBitMap . Rows;
/* Allocate space for the bitmap. */
if(ImageBitMap . Planes[0] = AllocMem(PageSize * ImageBitMap . Depth,MEMF_CHIP | MEMF_CLEAR))
{
/* Set the bitplane pointers accordingly. */
for(i = 1 ; i < ImageBitMapHeader . nPlanes ; i++)
ImageBitMap . Planes[i] = (PLANEPTR)((ULONG)ImageBitMap . Planes[0] + PageSize * i);
/* Allocate a colour map. */
if(ImageColourMap = (struct ColorMap *)GetColorMap(MaxCol))
{
/* Set the image colours. */
for(i = 0 ; i < MaxCol ; i++)
SetRGB4CM(ImageColourMap,i,Colours[i][0],Colours[i][1],Colours[i][2]);
/* Finally, load the bitmap itself. */
if(LoadRaster(Name,ImageBitMap . Planes,&ImageBitMapHeader))
{
HasImage = TRUE;
return(TRUE);
}
}
}
}
}
FreeImage();
return(FALSE);
}
/* FindChunk():
*
* Find a chunk in a file and return its length.
*/
ULONG
FindChunk(ULONG ChunkName,FILE *FilePointer)
{
ULONG OldPosition,FormType;
IFF_Chunk Chunk;
/* Remember the initial file position. */
OldPosition = ftell(FilePointer);
/* Reset the form type. */
FormType = 0;
for(;;)
{
/* Try to read the chunk. */
if(fread(&Chunk,sizeof(Chunk),1,FilePointer) != 1)
{
/* If it went wrong, reset the
* file position.
*/
fseek(FilePointer,OldPosition,0);
return(0);
}
/* If this is supposed to be a FORM chunk,
* try to figure out the form type.
*/
if(OldPosition == 0 && FormType == 0 && Chunk . IFF_Type == 'FORM')
{
fread(&FormType,sizeof(LONG),1,FilePointer);
/* Is it the type we want? */
if(FormType == ChunkName)
return(Chunk . IFF_Length);
continue;
}
/* Is this what we want? */
if(Chunk . IFF_Type == ChunkName)
return(Chunk . IFF_Length);
/* Else, skip the length information. */
fseek(FilePointer,Chunk . IFF_Length,1);
}
}
/* LoadHeader():
*
* Try to load a BitMapHeader from a file and return
* the proper ViewModes.
*/
LONG
LoadHeader(char *FileName,BitMapHeader *BMHeader)
{
LONG ViewModes = -1;
FILE *ImageFile;
/* No such file? */
if(ImageFile = fopen(FileName,"rb"))
{
/* No BMHD-Chunk? */
if(FindChunk('BMHD',ImageFile))
{
/* Read the header. */
if(fread(BMHeader,sizeof(BitMapHeader),1,ImageFile))
{
/* Strange values, probably not a picture but a
* "mistake", or even a CMAP.
*/
if(BMHeader -> nPlanes && BMHeader -> nPlanes <= 8)
{
ViewModes = NULL;
/* If we don't find a CAMG chunk in the file
* we will have to guess the right
* ViewModes. This line takes care of the
* interlaced display mode.
*/
if(BMHeader -> pageHeight > GfxBase -> NormalDisplayRows)
ViewModes |= LACE;
/* Could it be HIRES? */
if(BMHeader -> pageWidth >= 640)
ViewModes |= HIRES;
/* It is still much more likely to encounter a
* HAM picture than an EHB picture. If we are
* wrong with this assumption, the CAMG chunk
* will tell us (hope so).
*/
if(BMHeader -> nPlanes == 6)
ViewModes |= HAM;
/* Hello out there, got any CAMG chunk? */
if(FindChunk('CAMG',ImageFile))
{
/* Read it then. */
if(fread(&ViewModes,sizeof(LONG),1,ImageFile) == 1)
{
/* Mask out all unwanted bits (thanks, Carolyn!). */
ViewModes &= (~(SPRITES | VP_HIDE | GENLOCK_AUDIO | GENLOCK_VIDEO) | 0xFFFF);
}
else
ViewModes = -1;
}
}
}
}
fclose(ImageFile);
}
/* Finish it. */
return(ViewModes);
}
/* LoadCMAP():
*
* Load a colour table from a file and return the number
* of colours.
*/
BYTE
LoadCMAP(char *FileName,BYTE Colours[32][3],LONG MaxCol,BitMapHeader *BMHeader)
{
BYTE NumCols = 0;
FILE *ColFile;
BYTE i;
/* Are you there? */
if(ColFile = fopen(FileName,"rb"))
{
/* Black 'n white or colour TV? */
if(FindChunk('CMAP',ColFile))
{
/* Correct it before the reader believes it! */
if(MaxCol < 2)
MaxCol = 1 << BMHeader -> nPlanes;
/* A bit too large, innit? */
if(MaxCol > 32)
MaxCol = 32;
/* Read those colours. */
if(fread(Colours,32 * 3,1,ColFile) == 1)
{
for(i = 0 ; i < MaxCol ; i++)
{
Colours[i][0] >>= 4;
Colours[i][1] >>= 4;
Colours[i][2] >>= 4;
}
NumCols = MaxCol;
}
}
/* Finish it. */
fclose(ColFile);
}
return(NumCols);
}
/* LoadRaster():
*
* Load the bitmap from a file and decompress it into the
* supplied planes.
*/
BYTE
LoadRaster(char *FileName,PLANEPTR *BitPlanes,BitMapHeader *BMHeader)
{
UBYTE Value,SoFar,Compr,Depth;
LONG Height,Width;
PLANEPTR Planes[9]; /* 9 for possible bitmask. */
FILE *PicFile;
BYTE ChkVal;
LONG i,j,k;
LONG AuxLength;
BYTE *AuxBuff2;
BYTE *AuxBuff; /* Decompress in memory buffer. */
/* Clear the planes. */
for(i = 0 ; i < 9 ; i++)
Planes[i] = NULL;
/* Set up the working copies. */
Width = byte(BMHeader -> w);
Height = BMHeader -> h;
Depth = BMHeader -> nPlanes;
Compr = BMHeader -> compression;
/* Is there something wrong in paradise? */
if(Compr > 1 || !BitPlanes)
return(FALSE);
/* Can we read it, please? */
if(!(PicFile = fopen(FileName,"rb")))
return(FALSE);
/* No BODY? What is this? */
if(!(AuxLength = FindChunk('BODY',PicFile)))
{
fclose(PicFile);
return(FALSE);
}
/* Copy the bitmap pointers since their
* contents will get changed.
*/
for(i = 0 ; i < Depth ; i++)
Planes[i] = BitPlanes[i];
/* Very well, nobody told me that DPaint and Aegis Images
* are allowed to save their own home-brewn BODY chunks
* if the transparent colour is nonzero or the
* stencil/behind function is used. In this case the
* interleaved plane data is immediately followed by
* a bitmask which is to clear all unwanted pixels
* after the image is drawn. To support this feature
* we increment the depth of the image to give the
* reader access to a blank pointer the bitmask will
* be sent to.
*/
if(BMHeader -> masking == 1)
Depth++;
/* If we can allocate the memory buffer, we will
* decompress the image in memory rather than
* while reading it from disk.
*/
if(AuxBuff = (BYTE *)AllocMem(AuxLength,MEMF_PUBLIC))
{
/* Read the data. */
fread(AuxBuff,AuxLength,1,PicFile);
/* Remember the buffer address. */
AuxBuff2 = AuxBuff;
/* No compression? */
if(Compr == 0)
{
for(k = 0 ; k < Height ; k++)
{
for(j = 0 ; j < Depth ; j++)
{
if(Planes[j])
{
CopyMem(AuxBuff,Planes[j],Width);
Planes[j] += Width;
}
AuxBuff += Width;
}
}
}
/* ByteRun compression? */
if(Compr == 1)
{
for(k = 0 ; k < Height ; k++)
{
for(j = 0 ; j < Depth ; j++)
{
for(SoFar = 0 ; SoFar < Width ; )
{
ChkVal = *AuxBuff;
AuxBuff++;
if(ChkVal > 0)
{
if(Planes[j])
{
CopyMem(AuxBuff,Planes[j],ChkVal + 1);
Planes[j] += ChkVal + 1;
}
AuxBuff += ChkVal + 1;
SoFar += ChkVal + 1;
}
else
{
if(ChkVal != -128)
{
Value = *AuxBuff;
AuxBuff++;
for(i = 0 ; i <= -ChkVal ; i++)
{
if(Planes[j])
*Planes[j]++ = Value;
SoFar++;
}
}
}
}
}
}
}
/* Free the auxilary buffer. */
FreeMem(AuxBuff2,AuxLength);
goto Quit;
}
/* No compression, take the data as is. */
if(Compr == 0)
{
for(k = 0 ; k < Height ; k++)
{
for(j = 0 ; j < Depth ; j++)
{
if(Planes[j])
{
fread(Planes[j],Width,1,PicFile);
Planes[j] += Width;
}
else
fseek(PicFile,Width,1);
}
}
}
/* ByteRun1 compression. */
if(Compr == 1)
{
for(k = 0 ; k < Height ; k++)
{
for(j = 0 ; j < Depth ; j++)
{
for(SoFar = 0 ; SoFar < Width ; )
{
ChkVal = fgetc(PicFile);
/* Read the next bytes. */
if(ChkVal > 0)
{
if(Planes[j])
{
fread(Planes[j],ChkVal + 1,1,PicFile);
Planes[j] += ChkVal + 1;
}
else
fseek(PicFile,ChkVal + 1,1);
SoFar += ChkVal + 1;
}
else
{
/* Set the memory to this
* value.
*/
if(ChkVal != -128)
{
Value = fgetc(PicFile);
for(i = 0 ; i <= -ChkVal ; i++)
{
if(Planes[j])
*Planes[j]++ = Value;
SoFar++;
}
}
}
}
}
}
}
/* Finish it up. */
Quit: fclose(PicFile);
return(TRUE);
}
/* Stub routines. */
VOID _cli_parse() {}
VOID _wb_parse() {}
/* main():
*
* The real main program.
*/
VOID
main()
{
BYTE i;
/* Open all resources. */
OpenAll();
/* Go into neverending loop. */
FOREVER
{
WaitPort(Window -> UserPort);
/* Pick up all the messages. */
while(Massage = (struct IntuiMessage *)GetMsg(Window -> UserPort))
{
Class = Massage -> Class;
Code = Massage -> Code;
GadgetID = ((struct Gadget *)Massage -> IAddress) -> GadgetID;
ReplyMsg((struct Message *)Massage);
/* Close the window? */
if(Class == CLOSEWINDOW)
CloseAll(RETURN_OK);
/* Hit a gadget. */
if(Class == GADGETUP)
{
switch(GadgetID)
{
/* Load a new image? */
case 0: if(HasImage)
FreeImage();
if(FileRequester(&LoadFileReq))
{
SetWait(Window);
if(LoadImage(Buffer))
{
for(i = 1 ; i < NUMGADS - 1 ; i++)
{
if(i != 2)
OnGadget(&GadgetBlocks[i] . Gadget,Window,NULL);
else
OffGadget(&GadgetBlocks[i] . Gadget,Window,NULL);
}
}
else
SimpleRequest("Couldn't load file \"%s\"!",Buffer);
ClearPointer(Window);
}
break;
/* Print the image? */
case 1: if(HasImage)
PrintImage();
break;
/* Stop printing (ignore)? */
case 2: break;
/* Exit the program? */
case 3: CloseAll(RETURN_OK);
}
}
}
}
}