/* Print gs bitcmyk output on Primera Signature (aka Fargo Signature) CD printer * For original model Signature only, not for Signature II and newer. * * sig1-c's output will print only with a color cartridge. * * Example usage: * cdlabelgen -c "Disc Title" --create-cdlabel -b -D --page-offset .327,1.286 -l 0 > foo.ps * gs -r300 -g1800x1800 -sDEVICE=bitcmyk -dNOPAUSE -dBATCH -dSAFER -q -sOutputFile=- foo.ps | sig1-c > /dev/lp0 * * sig1-c does not enforce printable area restrictions, so it will happily * spit ink all over the tray if you try printing beyond the actual disc * dimensions. * * The printable area is a circle about 4.567" in diameter (116mm, 1370/300"). * The left edge of the circle is .327" right of the origin. * The top of the circle is 5.853" above the origin (BOTTOM of the page). * The bottom of the circle is 1.286" above the origin. * * Ghostscript does not perform color correction. Also, its dithering algorithm * sucks. Accordingly, you should get acceptable results printing line-art and * text, but continuous-tone images such as photographs may not look so good. * * Copyright 2008 by Adam Goldman * Email: * * History: * 2008-12-29 Initial release. * * sig1-c is not produced or endorsed by Primera. */ /* zlib-style license: * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ #include #include /* * */ void init() { fputs("\033*\007s0\033*\007c",stdout); } void advance(unsigned int amount) { /* in 300ths of an inch */ static char foo[]="\033*\003xx"; foo[3]=(amount>>8)&255; foo[4]=amount&255; fwrite(foo,5,1,stdout); } void draw(unsigned int squirts, const unsigned char *raster, unsigned int margin, unsigned char head) { /* prints a 16-pixel-high stripe of yellow across the page. below it, prints a magenta stripe; below the magenta, prints cyan. each pixel is a 1/300" square. the top of the magenta stripe is 20/300" below the top of the yellow stripe, and the top of the cyan stripe is 40/300" below the top of the yellow stripe. also, the magenta is offset 18/300" to the left compared to the other colors. the raster data to the printer consists of 6 bytes for each squirt. the highest-order bit activates the topmost yellow nozzle, etc, and the lowest-order bit of the last byte activates the bottommost cyan nozzle. (the "top" of the cartridge is the end closest to the front panel of the printer.) after printing, advances the media by 16/300". when printing b&w, prints a single 48-pixel-high stripe and advances the media by 48/100". if the chosen head (color or b&w) does not correspond to the installed cartridge type, the printer will blink an error code instead of printing. */ static char header[]={ 0x1b, 0x2a, 0x04, /* 0 command Esc * ^D */ 0xaa, 0xaa, /* 3 total byte count including hdr */ 0x00, /* 5 ??? */ 0x01, /* 6 maybe resolution? */ 0x01, /* 7 maybe direction? */ 0xaa, /* 8 head - 0=color 1=b&w */ 0x06, /* 9 maybe bytes per squirt? */ 0x00, /* 10 ??? */ 0xaa, 0xaa, /* 11 squirt count (h. pixel count) */ 0xaa, 0xaa, /* 13 left margin */ 0x00, 0x00, 0x00, /* 14 ??? */ 0x10, /* 17 maybe media advance? */ 0x00, 0x00, 0x00, 0x00, /* ??? */ 0x00, 0x00, 0x00, /* ??? */ }; unsigned int raster_bytecount=squirts*6; unsigned int total_bytecount=raster_bytecount+26; header[3]=(total_bytecount>>8)&255; header[4]=total_bytecount&255; header[8]=head; header[11]=(squirts>>8)&255; header[12]=squirts&255; header[13]=(margin>>8)&255; header[14]=margin&255; fwrite(header,sizeof(header),1,stdout); fwrite(raster,raster_bytecount,1,stdout); } void eject() { fputs("\033*\007e",stdout); } /* * */ #define WIDTH (6*300) /* pixels; should be a multiple of 8 */ unsigned char rbuf[WIDTH*16]; /* raster data for one printhead swipe */ /* ring buffers to delay Y and M data for proper vertical alignment */ unsigned char buf_y[(WIDTH/8)*(40+16)]={0,}; unsigned char buf_m[(WIDTH/8)*(20+16)]={0,}; unsigned char buf_c[(WIDTH/8)*16]={0,}; unsigned char *in_y=buf_y+(WIDTH/8)*40, *in_m=buf_m+(WIDTH/8)*20, *in_c=buf_c; unsigned char *out_y=buf_y, *out_m=buf_m, *out_c=buf_c; unsigned int queued_lines=0; void wrap_in() { if(in_y>=buf_y+(WIDTH/8)*(40+16)) in_y-=(WIDTH/8)*(40+16); if(in_m>=buf_m+(WIDTH/8)*(20+16)) in_m-=(WIDTH/8)*(20+16); if(in_c>=buf_c+(WIDTH/8)*16) in_c-=(WIDTH/8)*16; } void wrap_out() { if(out_y>=buf_y+(WIDTH/8)*(40+16)) out_y-=(WIDTH/8)*(40+16); if(out_m>=buf_m+(WIDTH/8)*(20+16)) out_m-=(WIDTH/8)*(20+16); if(out_c>=buf_c+(WIDTH/8)*16) out_c-=(WIDTH/8)*16; } int squirt_blank(unsigned char *squirt) { if(squirt[0]==0 && squirt[1]==0 && squirt[2]==0 && squirt[3]==0 && squirt[4]==0 && squirt[5]==0) return 1; return 0; } void set_pixel(int line, int column, int color) { int bitnum=line+(color*16); rbuf[(column*6)+(bitnum/8)]|=0x80>>(bitnum%8); } void assemble_swipe() { int line,i,j; bzero(rbuf,sizeof(rbuf)); for(line=0;line<16;line++) { for(i=0;i4 && squirt_blank(r+(6*(squirts-1)))) { squirts--; } if(squirts==4 && squirt_blank(r) && squirt_blank(r+6) && squirt_blank(r+12) && squirt_blank(r+18)) { blank_lines+=16; return; } if(blank_lines>0) { advance(blank_lines); blank_lines=0; } draw(squirts,r,margin,0); } void extract_two_nibs(const unsigned char nibs) { *in_c<<=1; *in_m<<=1; *in_y<<=1; if(nibs&0x80) *in_c|=1; if(nibs&0x40) *in_m|=1; if(nibs&0x20) *in_y|=1; *in_c<<=1; *in_m<<=1; *in_y<<=1; if(nibs&0x08) *in_c|=1; if(nibs&0x04) *in_m|=1; if(nibs&0x02) *in_y|=1; } void queue_scanline(unsigned char *cmy) { int i; in_m+=2; /* insert 16 blank M pixels to move M alignment towards C/Y */ *in_m=0; for(i=0;i<(WIDTH/8)-2;i++) { *in_c=0; *in_y=0; extract_two_nibs(*cmy); cmy++; extract_two_nibs(*cmy); cmy++; extract_two_nibs(*cmy); cmy++; in_m++; *in_m=0; /* 2 nibbles early, for another 2-pixel shift*/ extract_two_nibs(*cmy); cmy++; in_c++; in_y++; } in_c+=2; in_y+=2; wrap_in(); queued_lines++; if(queued_lines==16) { print_swipe(); queued_lines=0; } } void flush_buffers() { int i; while(queued_lines<16) { for(i=0;i0) flush_buffers(); flush_buffers(); eject(); } /* * */ void cmyk_to_cmy(unsigned char *buf) { int i; for(i=0;i