page%swap@Sun.COM (Bob Page) (05/09/89)
Submitted-by: kennedy%wwpacs@dupont.com (Tony Kennedy) Posting-number: Volume 89, Issue 120 Archive-name: iff/iff2sixel.1 Here's a program I wrote to convert IFF pictures to DEC Sixels. You can now display IFF files on VT240s, VT241s, VT340s and the like. [binary not available; use your favorite compiler. ..bob] # This is a shell archive. # Remove anything above and including the cut line. # Then run the rest of the file through 'sh'. # Unpacked files will be owned by you and have default permissions. #----cut here-----cut here-----cut here-----cut here----# #!/bin/sh # shar: SHell ARchive # Run the following text through 'sh' to create: # ReadMe # iff2sixel.c # This is archive 1 of a 1-part kit. # This archive created: Mon May 8 21:54:31 1989 echo "extracting ReadMe" sed 's/^X//' << \SHAR_EOF > ReadMe XHi there, X XHere's the program. It's got a few limitations. It NEEDS a 16 color Xfile for a 340 (you can use fewer that 16 but not more), or 4 colors Xfor a 240. I ran it with HAM converted to hires interlace with XPixmate and they look great. The best results are the 16 color hires Xinterlaced picts. X XLet me know if you find this program useful and if there are any bugs. XAlso please let me know what environment/compiler/linker you used (for Xfuture versions) X X Enjoy... X ...Tony SHAR_EOF echo "extracting iff2sixel.c" sed 's/^X//' << \SHAR_EOF > iff2sixel.c X/*****************************************************************************/ X/* X Program : IFF2SIXEL.C X X Author : Tony Kennedy X Internet address: kennedam%wwps@dupont.com@relay.cs.net X X Purpose : This program takes a AMIGA IFF ILBM file and converts X it to a SIXEL file to be displayed on DIGITAL EQUIPMENT X CORP. VT240, VT241, VT340 terminals. X X This version will handle only 16 colors for a VT340 and X 4 colors for a VT240. It does no color compression, so X all input files must be 16 colors or less for a 340, X 4 colors or less for a 240. X X If the display is a VT240/241 then the resolution X is set to 640X200. If it's a 340 then the res is 640X400. X X I tried to make it a generic as possible so you can X compile it under what ever environment you please. X If you do it under VMS you will need to define IFF2SIXEL X as a foreign command i.e. $ iff2sixel :== $mydir:iff2sixel X otherwise you can't use command line args. X X Usage : iff2sixel <input_file> <output_file> <VT240 | VT340> X X Comments : This program is Freely Distributable. You may X use it for any non-commercial uses. X (If anybody hacks at this please send me a copy.) X X Acknowledgements : Thanks to... X X Carter Brock for the SHOW_IFF program I used X to figure out how to read an IFF file. X X Mark Thompson and Steve Berry for the IFF2SUN X program I used to figure out how to interpret X the bitplanes. X X Barry Young for his help with SIXEL formats. X X Daniel Jay Barrett for his switching bytes X hacks. X X Limitations : This won't do HAM or Halfbrite. When I figure them out X I'll put that in too. X Won't do any color compression. X X X Versions: Revisions : X X 1.0 3/1/89 Original program. X X*/ X/*****************************************************************************/ X X#include <stdio.h> X#include <math.h> X X#define Sixel_base 63 X#define DCS 144 X#define ST 156 X#define QUOTE 34 X X#define LoRes 1 X#define LoLace 2 X#define HiRes 3 X#define HiLace 4 X X#define VT240_LoRes 1 X#define VT240_LoLace 2 X#define VT240_HiRes 3 X#define VT240_HiLace 4 X#define VT340_LoRes 5 X#define VT340_LoLace 6 X#define VT340_HiRes 7 X#define VT340_HiLace 8 X X typedef unsigned char ID_type[4]; X struct ChunkType X { X ID_type Ident ; X long ChunkSize ; X } ; X struct ChunkType chunk ; X X typedef struct X { X unsigned char red, green, blue; X } ColorRegType; X X unsigned char BitPlaneArray[400][6][128]; /* vert posit, plane, width posit*/ X unsigned char PixelArray[400][640]; /* vert posit, horiz posit */ X int SixelLine[16][640][80]; /* color,horizontal posit, row.*/ X int vert, horz, s_vert, v_bit; X X/******************************************************************** X X This function decompresses the IFF file. I got the algorithm X from Mark and Steve who got it from Leo (The Great Caped One). X X********************************************************************/ X X int decompress_planes(nplanes,width,height,inp_file) X X unsigned short nplanes,width,height; X FILE *inp_file; X X { X long h,p,count,BytesPerRow; X char len; X unsigned char byte; X X for (h=0;h<height;h++) X { X for (p=0;p<nplanes;p++) X { X count = 0; X BytesPerRow=width/8; X while(BytesPerRow>0) X { X if ((len = getc(inp_file)) >= 0) X { X BytesPerRow -= ++len; X fread(&BitPlaneArray[h][p][count],len,1,inp_file); X count += len; X } X else X if (len < 0) X { X len = -len + 1; X BytesPerRow -= len; X byte = getc(inp_file); X while (--len >= 0) X BitPlaneArray[h][p][count++] = byte; X } X } X if (BytesPerRow) printf("Compression is corrupt.\n"); X } X } X } X X/******************************************************************** X X Since the VAX reads shorts and longs backwards we've got to X flip them around... X X********************************************************************/ X X#ifdef VAX X Xshort flip_byte_short(s) X X short s; X { X short hib,lob; X X lob = (s & 255); X hib = ((s >> 8) & 255); X return ((lob << 8) + hib); X } X Xlong flip_bytes_long(l) X X long l; X { X short low,hiw; X X low = (l & 65535); X hiw = ((l >> 16) & 65535); X return ( ((flip_byte_short(low) << 16) + flip_byte_short(hiw))); X } X#endif X X/******************************************************************** X X Convert a string to upper case. X X********************************************************************/ X Xchar *upcase(str) X X char *str; X X { X int len, i; X X i=0; X len=strlen(str); X while(i != len) X { X str[i]=toupper(str[i]); X i++; X } X return str; X } X X/******************************************************************** X X Double the width of the Pixel Array. X X********************************************************************/ X X short double_width(width,height) X X short width,height; X X { X short h,w; X for (h=0;h<height;h++) X { X for (w=width-1;w>=0;w--) X { X PixelArray[h][w * 2] = PixelArray[h][w]; X PixelArray[h][(w * 2)+1] = PixelArray[h][w]; X } X } X return (width * 2); X } X X/******************************************************************** X X Double the height of the Pixel array. X X********************************************************************/ X X short double_height(width,height) X X short width,height; X X { X short h,w; X for (w=0;w<width;w++) X for (h=height-1;h>=0;h--) X { X PixelArray[h * 2][w]=PixelArray[h][w]; X PixelArray[(h * 2)+1][w]=PixelArray[h][w]; X } X return (height * 2); X } X X/******************************************************************** X X Halve the height of the Pixel Array. This is gonna make the X picture look pretty ugly if you ask me. Only gets done if a X picture for a VT240 from an interlace IFF file is being X generated. X X********************************************************************/ X Xshort halve_height(width,height) X X short width,height; X X { X short h,w; X for (h=0;h<height;h++) X for (w=0;w<=width;w++) X PixelArray[h][w]=PixelArray[(h * 2)][w]; X X return (height/2); X } Xmain (argc,argv) X X int argc; X char **argv[]; X X { X long num_colors; X int stat; X long posit,h,w,p,i,j,k,l,m,pixel; X long w_pos,cnt_100,cnt_10,cnt_1,rep_cnt; X char ch, outline[700]; X unsigned char color; X char *term; X char term_type[5]; X char *input_file; X char *output_file; X FILE *outf,*inf; X char start_sixel = DCS; X char end_sixel = ST; X char quote = QUOTE; X int convert_mode = 0; X int resolution; X X struct BitMapHeaderType X { X unsigned short width, height; X short org_x, org_y; X unsigned char NumPlanes, Mask, Compression, pad; X unsigned short TransColor; X unsigned char X_Asp, Y_Asp; X unsigned short PageWid, PageHeight; X } ; X struct BitMapHeaderType bmhd; X X ColorRegType CMap[16]; X X/********************************************************************* X X First, get all the needed info from the user... X X Input file, Output file, Type of terminal to create a file for. X X*********************************************************************/ X switch (argc) X { X case 1 : X printf("Input File Name : "); X scanf ("%s",&input_file); X printf("Output File Name : "); X scanf("%s",&output_file); X printf("\nThis will generate SIXELS for a VT240 @ 640x240.\n"); X printf("or a VT340 @ 640x480.\n"); X printf("Enter VT240 or VT340 : "); X scanf("%s",&term_type); X inf = fopen(&input_file,"r"); X outf = fopen(&output_file,"w"); X term = &term_type; X break; X X case 2 : X X printf("Output File Name : "); X scanf("%s",&output_file); X printf("\nThis will generate SIXELS for a VT240 @ 640x240.\n"); X printf("or a VT340 @ 640x480.\n"); X printf("Enter VT240 or VT340 : "); X scanf("%s",&term_type); X inf = fopen(argv[1],"r"); X outf = fopen(&output_file,"w"); X term = &term_type; X break; X X case 3 : X X printf("\nThis will generate SIXELS for a VT240 @ 640x240.\n"); X printf("or a VT340 @ 640x480.\n"); X printf("Enter VT240 or VT340 : "); X scanf("%s",&term_type); X inf = fopen(argv[1],"r"); X outf = fopen(argv[2],"w"); X term = &term_type; X break; X X case 4 : X X inf = fopen(argv[1],"r"); X outf = fopen(argv[2],"w"); X term = argv[3]; X X } X X if (outf == NULL) { X printf("Output can't be opened.\n"); X exit(0); } X X if (inf == NULL) { X printf("Input file can't be opened.\n"); X exit(0); } X X X/********************************************************************* X X Ok. Now read in the IFF file... X X*********************************************************************/ X X X stat=fread(chunk.Ident,4,1,inf); X if (stat == -1) X { X printf("Error reading file.\n"); X stat=close(inf) ; stat=close(outf); X exit(0); X } X X X while (strncmp(chunk.Ident,"FORM",4) !=0) X stat=fread(chunk.Ident,4,1,inf); X X if (strncmp(chunk.Ident,"FORM",4) != 0) X { X printf("Error, not a FORM file.\n"); X stat=close(inf); stat=close(outf); X exit(0); X } X X stat=fread(&chunk.ChunkSize,4,1,inf); X X stat=fread(chunk.Ident,4,1,inf); X X while (strncmp(chunk.Ident,"ILBM",4) !=0) X stat=fread(chunk.Ident,4,1,inf); X X if (strncmp(chunk.Ident, "ILBM",4) !=0) X X { X printf("Error Not an ILBM file.\n"); X stat=close(inf); stat=close(outf); X exit(0); X } X stat=fread(chunk.Ident,4,1,inf); X X while (strncmp(chunk.Ident,"BMHD",4) !=0) X stat=fread(chunk.Ident,4,1,inf); X X if (strncmp(chunk.Ident, "BMHD",4) !=0) X { X printf("Error can't find Bit Map Header.\n"); X stat=close(inf); stat=close(outf); X exit(0); X } X X stat=fread(&chunk.ChunkSize,4,1,inf); X stat=fread(chunk.Ident,2,1,inf); X bmhd.width = *((short *)chunk.Ident); X stat=fread(chunk.Ident,2,1,inf); X bmhd.height = *((short *)chunk.Ident); X stat=fread(chunk.Ident,2,1,inf); X bmhd.org_x = *((short *)chunk.Ident); X stat=fread(chunk.Ident,2,1,inf); X bmhd.org_y = *((short *)chunk.Ident); X stat=fread(chunk.Ident,1,1,inf); X bmhd.NumPlanes = *((char *)chunk.Ident); X stat=fread(chunk.Ident,1,1,inf); X bmhd.Mask = *((char *)chunk.Ident); X stat=fread(chunk.Ident,1,1,inf); X bmhd.Compression = *((char *)chunk.Ident); X stat=fread(chunk.Ident,1,1,inf); X stat=fread(chunk.Ident,2,1,inf); X bmhd.TransColor = *((short *)chunk.Ident); X stat=fread(chunk.Ident,1,1,inf); X bmhd.X_Asp = *((char *)chunk.Ident); X stat=fread(chunk.Ident,1,1,inf); X bmhd.Y_Asp = *((char *)chunk.Ident); X stat=fread(chunk.Ident,2,1,inf); X bmhd.PageWid = *((short *)chunk.Ident); X stat=fread(chunk.Ident,2,1,inf); X bmhd.PageHeight = *((short *)chunk.Ident); X X if (stat == -1) X { X printf("Error failed to get Bit Map information.\n"); X stat=close(inf); stat=close(outf); X exit(0); X } X X X stat=fread(chunk.Ident,4,1,inf); X X while (strncmp(chunk.Ident,"CMAP",4) !=0) X stat=fread(chunk.Ident,4,1,inf); X X if (strncmp(chunk.Ident,"CMAP",4) !=0) X { X printf("Error can't find Color Map.\n"); X stat=close(inf); stat=close(outf); X exit(0); X } X stat=fread(&num_colors,4,1,inf); X X#ifdef VAX X X bmhd.width=flip_byte_short(bmhd.width); X bmhd.height=flip_byte_short(bmhd.height); X bmhd.org_x=flip_byte_short(bmhd.org_x); X bmhd.org_y=flip_byte_short(bmhd.org_y); X bmhd.TransColor=flip_byte_short(bmhd.TransColor); X bmhd.PageWid=flip_byte_short(bmhd.PageWid); X bmhd.PageHeight=flip_byte_short(bmhd.PageHeight); X num_colors=flip_bytes_long(num_colors); X X#endif X X/******************************************************************** X X define conversion mode X X********************************************************************/ X X if ((bmhd.width==320)&&(bmhd.height==200)) resolution = LoRes; X if ((bmhd.width==320)&&(bmhd.height==400)) resolution = LoLace; X if ((bmhd.width==640)&&(bmhd.height==200)) resolution = HiRes; X if ((bmhd.width==640)&&(bmhd.height==400)) resolution = HiLace; X X X if ((strcmp(upcase(term),"VT240",5) == 0) && X (resolution==LoRes)) convert_mode=VT240_LoRes; X X if ((strcmp(upcase(term),"VT240",5) == 0) && X (resolution==LoLace)) convert_mode=VT240_LoLace; X X if ((strcmp(upcase(term),"VT240",5) == 0) && X (resolution==HiRes)) convert_mode=VT240_HiRes; X X if ((strcmp(upcase(term),"VT240",5) == 0) && X (resolution==HiLace)) convert_mode=VT240_HiLace; X X if ((strcmp(upcase(term),"VT340",5) == 0) && X (resolution==LoRes)) convert_mode=VT340_LoRes; X X if ((strcmp(upcase(term),"VT340",5) == 0) && X (resolution==LoLace)) convert_mode=VT340_LoLace; X X if ((strcmp(upcase(term),"VT340",5) == 0) && X (resolution==HiRes)) convert_mode=VT340_HiRes; X X if ((strcmp(upcase(term),"VT340",5) == 0) && X (resolution==HiLace)) convert_mode=VT340_HiLace; X X if (!convert_mode) { X printf("IFF picture is an irregular size.\n"); X close(inf); X close(outf); X exit(0); X } X X X num_colors=num_colors/3; X stat=fread(CMap,(num_colors * 3),1,inf); X X if ( (num_colors > 16) || X ((num_colors > 4) && (strcmp(upcase(term),"VT240",5) == 0)) X ) X X { X printf("File has too many colors for this conversion.\n"); X close(inf); X close(outf); X exit(0); X } X X/******************************************************************** X X Skip everything till we find the BODY. X X********************************************************************/ X X stat=fread(chunk.Ident,4,1,inf); X while (strncmp(chunk.Ident,"BODY",4) !=0) X stat=fread(chunk.Ident,4,1,inf); X X X stat=fread(chunk.Ident,4,1,inf); /* body length */ X X X/******************************************************************** X X Now read the bit planes in. X X********************************************************************/ X X if (bmhd.Compression == 1) X decompress_planes(bmhd.NumPlanes,bmhd.width,bmhd.height,inf); X else X X for (h = 0;h<bmhd.height;h++) X for (p = 0;p<bmhd.NumPlanes;p++) X { X for (w = 0;w<bmhd.width/8;w++) X { X if (feof(inf)) continue; X read(inf,BitPlaneArray[h][p][w],1); X } X } X close(inf); X X/******************************************************************** X X Translate bit planes to pixel color values. X X********************************************************************/ X X for (h = 0;h<bmhd.height;h++) X { X w_pos = 0; X for (w=0;w<bmhd.width/8;w++) X { X pixel = 0; X for (i=7;i>=0;i--) X { X X for (p=0;p<bmhd.NumPlanes;p++) X pixel = ((((1 << i) & BitPlaneArray[h][p][w])>>i)<<p)|pixel; X X PixelArray[h][w_pos++] = (char)(pixel & 0x1f); X pixel = 0; X } X } X } X X/******************************************************************** X X Convert to screen size. X X********************************************************************/ X X switch(convert_mode) X X { X case VT240_LoRes : X bmhd.width = double_width(bmhd.width,bmhd.height); X break; X X case VT240_LoLace : X bmhd.height = halve_height(bmhd.width,bmhd.height); X bmhd.width = double_width(bmhd.width,bmhd.height); X break; X X case VT240_HiRes : X break; X X case VT240_HiLace : X bmhd.height = halve_height(bmhd.width,bmhd.height); X break; X X case VT340_LoRes : X bmhd.width = double_width(bmhd.width,bmhd.height); X bmhd.height = double_height(bmhd.width,bmhd.height); X break; X X case VT340_LoLace : X bmhd.width = double_width(bmhd.width,bmhd.height); X break; X X case VT340_HiRes : X bmhd.height = double_height(bmhd.width,bmhd.height); X break; X X case VT340_HiLace : X break; X X } X X/******************************************************************** X X Convert Pixels to Sixels. X X********************************************************************/ X X vert=bmhd.height; X horz=bmhd.width; X v_bit = 0; X X for (i=0;i<vert;i++) X { X s_vert = i/6; X v_bit= i%6; X for (j=0;j<horz;j++) X { X color = PixelArray[i][j]; X SixelLine[color][j][s_vert] |= (int)pow(2,v_bit); X } X } X X X/******************************************************************** X X Compress Sixels and write to file. X X********************************************************************/ X X X vert = bmhd.height/6; X X/* Write Sixel start code. */ X X fprintf(outf,"%c;1;;q%c1;1;;\n",start_sixel,quote); X X/* Write color map. */ X X for (color=0;color<num_colors;color++) X { X CMap[color].red = (CMap[color].red * 100)/255; X CMap[color].green = (CMap[color].green * 100)/255; X CMap[color].blue = (CMap[color].blue * 100)/255; X fprintf(outf,"#%d;2;%d;%d;%d\n",color, X CMap[color].red,CMap[color].green,CMap[color].blue); X X } X fprintf(outf,"\n"); X X X/* Compress and write Sixels. */ X X for (s_vert=0;s_vert <= vert;s_vert++) X { X for (color=0;color<num_colors;color++) X { X X for (j=0;j<horz;j++) X SixelLine[color][j][s_vert] += Sixel_base; X i = 0; X k = 0; X while( i < horz ) X { X ch = SixelLine[color][i][s_vert]; X l=i; X X while ((l < horz) && (ch == SixelLine[color][l][s_vert])) X l++; X rep_cnt = l - i; X if (rep_cnt >= 5) X { X cnt_100 = rep_cnt/100; X cnt_10 = (rep_cnt-(cnt_100 * 100))/10; X cnt_1 = (rep_cnt-((cnt_100 * 100)+(cnt_10 * 10))); X outline[k] = 33; /* Exclamation mark */ X outline[k+1] = cnt_100 + 48; X outline[k+2] = cnt_10 + 48; X outline[k+3] = cnt_1 + 48; X outline[k+4] = SixelLine[color][l-1][s_vert]; X k += 5; X i=l; X } X else X { X for (m=0;m<=(l-1)-i;m++) X outline[k+m]=SixelLine[color][l-1][s_vert]; X k += (l-i); X i=l; X } X } X outline[k]=0; X fprintf(outf,"#%d %s$\n",color,&outline); X X } X fprintf(outf," - \n"); X } X fprintf(outf,"%c\n",ST); X close(outf); X } SHAR_EOF echo "End of archive 1 (of 1)" # if you want to concatenate archives, remove anything after this line exit