/* $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); } } } } }