ian@ob1.uws.EDU.AU (Ian Walsh) (02/13/91)
The following programs will allow PPM files to be viewed on a BBC Model B (or any machine with BBC BASIC 2 - probably!). I didn't know whether to uuencode them or not, so I haven't. Sorry about the size of this file! (I was going to wait till the binary group started). A full-colour PPM file will have to be 'quantised' to 8 colours, using ppmquant. The colour map provided in the ppmquant man entry will be used (I called mine ttl.map). eg. ppmquant -map ttl.map -fs image.ppm | ppmtobbc > p.image ^^^^^^^^^ ^^^^^^^ input file output file The resulting file (p.image from above) should be transfered to your BBC. Then use the BBC BASIC program (at end of this article) to view and save the image on your Beeb. It's probably a good idea to put the ppmquant stuff into a shell script. I use one to convert GIF files: giftoppm $1.gif | ppmquant -map ttl.map -fs | ppmtobbc > p.$1 Using the PBMPLUS package you can convert GIF/PCX/IFF/TIFF/BMP files to the PPM format. If there's any interest I could post BBC versions of some of these files for downloading (maybe when comp.binaries.acorn gets going). Andrew Leahy Univeristy Of Western Sydney - Nepean email: a.leahy@nepean.uws.edu.au C Source for ppmtobbc: ====================== Compile & run this program on the same machine which has the PBMPLUS package. I haven't used any of the PBM library routines, I should really! I've only compiled it on one machine (Apollo DN3000), but there shouldn't be any machine-specific code. Some checks are made on the input file: it must be a P6 file (ie. PPM RAWBITS), the max value must be 255 (usually is anyway). The image dimensions are read, if they are greater than 160x256 a warning will be displayed, but it will still be converted. I've only just started programming in C, so if you've got any comments or questions about my code please email me! /* Convert PPM files to compressed R..R,G..G,B..B format, for displaying on a BBC micro in Mode 2 (160x256x8) by Andrew Leahy 12/2/91 email: a.leahy@nepean.uws.edu.au Usage: ppmtobbc [file] Input: stdin or file Output: stdout eg. ppmtobbc image.ppm > p.image */ #include <stdio.h> #define BAD 0 #define OK 1 #define LO_MASK 0x80 FILE *fp_in, *fp_out; int width, height; main( int argc, char *argv[] ) { char dummy; if (argc == 1) fp_in = stdin; else if ((fp_in = fopen( argv[1], "r" )) == NULL) { fprintf( stderr, "Couldn't open %s\n", argv[1] ); exit(0); } if (!PPM_ok()) exit(0); /* if PPM file unacceptable die */ fp_out = stdout; /* all o/p to stdout */ dummy = fgetc( fp_in ); /* read past linefeed character */ write_dim(); /* o/p image size */ write_map(); /* compress & reorder the image */ fclose (fp_in ); /* close-up shop */ fclose( fp_out ); } int PPM_ok()/* is the PPM file reasonable? */ { #define PTYPE "P6" #define MAX_WIDTH 160 #define MAX_HEIGHT 512 #define MAX_COL 255 char ptype[2]; int max_col, return_val = BAD; fscanf( fp_in, "%s", ptype ); /* get PPM info from file */ fscanf( fp_in, "%d %d", &width, &height ); fscanf( fp_in, "%d", &max_col ); fprintf( stderr, "PPM info: %s, %dx%d, %d.\n", ptype, width, height, max_col ); if (!strcmp( ptype, PTYPE )) if (max_col == MAX_COL) return_val = OK; else fprintf( stderr, "ppmtobbc: PPM max colour value must be 255\n" ); else fprintf( stderr, "ppmtobbc: PPM file type not P6 (PPM RAWBITS)\n" ); if (width > MAX_WIDTH || height > MAX_HEIGHT) fprintf( stderr, "ppmtobbc: image may be too large!\n" ); return return_val; } int write_dim() /* write out the image type and size */ { fprintf( fp_out, "%s", "M2" ); /* for a Mode 2 screen */ fputc( width /256, fp_out ); fputc( width %256, fp_out); /* width */ fputc( height /256, fp_out ); fputc( height %256, fp_out); /* height */ } int write_map() { #define RED 0 #define GREEN 1 #define BLUE 2 char row [80] [3]; /* should use malloc here to setup array */ int y, x, byte, shift, colour; for( y=0; y < height; y++ ) { /* Initialise array */ for( byte=0; byte < width / 8; byte++ ) row [byte] [RED] = row [byte] [GREEN] = row [byte] [BLUE] = 0; /* Read PPM row into array, masking lower 7 bits */ for( x=0; x < width; x++ ) { byte = x / 8; shift = x % 8; row [byte] [RED] += (fgetc( fp_in ) & 0x80) >> shift; row [byte] [GREEN] += (fgetc( fp_in ) & 0x80) >> shift; row [byte] [BLUE] += (fgetc( fp_in ) & 0x80) >> shift; } /* Write out each row in turn */ for( colour=0; colour < 3; colour++ ) for( byte=0; byte < width / 8; byte++ ) fputc( row [byte] [colour], fp_out ); } } BBC BASIC 2 program: ==================== Use this program to view the resulting file on your Beeb. The image will be centred on a MODE 2 screen. If you want to save the image to disc un-comment line 130 (replace the SAVE with SVPIC if you wish). I give all my PPM M2 files the prefix 'P', so when an image is saved it is given the 'S' prefix. eg. P.PORSCHE becomes S.PORSCHE. The machine code is an attempt to speed up the loading, all it basically does is VDU23,128,BGET#Y%;0;0;0;128 in a loop. Again, any problems/questions/improvements please email me! 10 REM PPM M2 file viewer, by Andrew Leahy 6/2/91 20 REM email: a.leahy@nepean.uws.edu.au 30 ONERRORCLOSE#0:VDU4:REPORT:PRINT" at ";ERL:END 40 INPUT"Enter RGB File to view : P."C$ 50 Y%=OPENIN("P."+C$):IF Y%=0 PROCerr("No Such File!") 60 IF FNid<>"M2" PROCerr("Not a recognised file type!") 70 W%=(BGET#Y%*256+BGET#Y%)DIV8:H%=BGET#Y%*256+BGET#Y%-1:REM Get size 80 ?&70=W%:code=&900:PROCass 90 MODE2:VDU5,29,640-32*W%;510-H%*2;:REM Centre image 100 FORI%=H%*4 TO0STEP-4:?&71=1 110 FORJ%=0TO2:MOVE0,I%:CALLcode:NEXT, 120 VDU4:CLOSE#0 130 REMOSCLI("SAVE S."+C$+" 3000 8000") 140 END 150 DEF PROCass 160 P%=code:oswrch=&FFEE:osbget=&FFD7 170 FOR pass=0TO2STEP2:[OPT pass 180 LDA #18:JSR oswrch:LDA #1:JSR oswrch:LDA &71:JSR oswrch \ GCOL1,?&71 190 ASL A:STA &71 \ ?&71= 2*?&71 200 LDX &70 \ Get width 210 .put_byte LDA#23:JSR oswrch \ VDU23,128,BGET#Y%;0;0;0; 220 LDA #128:JSR oswrch:JSR osbget:JSR oswrch 230 LDA #0:]:FOR I%=0TO6:[OPT pass:JSR oswrch:]:NEXT 240 [OPT pass:LDA #128:JSR oswrch \ VDU128 250 DEX:BNE put_byte:RTS:] 260 NEXT:ENDPROC 270 DEF FNid:=CHR$BGET#Y%+CHR$BGET#Y% 280 DEF PROCerr(A$):PRINT'A$:CLOSE#0:END