Having written a few printer drivers I can confirm that generally the documentation is confusing because of the way printers work. The document that you refer to doesn't actually seem to bad to me.
I think you're right to be printing in raster mode and that overall this is going to give the best results.
From the Star documentation I reckon you'll need to send :
1. \x1b*rR Initialize raster mode
2. \x1b*rA Enter raster mode
3. \x1b*rC Clear raster data
4. \x1b*rml
4. b\x##\x##\xAA\xAA\xAA....<DATA>..........
5. \x1b\x0C\x00 Raster Form feed(??) - should spit out the data.
6. \x1b*rB Clear raster data
Obv. in the above \x1b is the C encoding of ESC (i.e. character 27 0x1b).
From all of the documentation that I've been reading the following is how the images should be formatted in raster mode. When in line mode it is completely different as the vertical & horizontal are swapped. From THERMAL PRINTER PROGRAMMER'S MANUAL (TSP552,TSP552II,TSP2000)
This equates to the following bytes stream.
On the 4th command line it is effectively 'b' followed by two bytes definining the size. This size is computed as the number of pixels contained in the stream % 256 and / 256. So for 320x1 that'd 0x40,0x01
So, taking the above and plugging it into a simple test program you should test with this:
char rasterImage [] = {
0x1b, '*', 'r', 'R', // Initialize raster mode
0x1b, '*', 'r', 'A', // Enter raster mode
0x1b, '*', 'r', 'C', // Clear raster data
// n1 n2 d1 d2..
0x1b, 'b', 0x2, 0, 0x00, 0x00, // data
0x1b, 'b', 0x2, 0, 0x1F, 0xF8,
0x1b, 'b', 0x2, 0, 0x3F, 0xFC,
0x1b, 'b', 0x2, 0, 0x77, 0xEE,
0x1b, 'b', 0x2, 0, 0xF8, 0x1F,
0x1b, 'b', 0x2, 0, 0xF8, 0x1F,
0x1b, 'b', 0x2, 0, 0xF8, 0x1F,
0x1b, 'b', 0x2, 0, 0x0F, 0xF0,
0x1b, 'b', 0x2, 0, 0x1F, 0xF8,
0x1b, 'b', 0x2, 0, 0x1F, 0xF8,
0x1b, 'b', 0x2, 0, 0x3E, 0x7C,
0x1b, 'b', 0x2, 0, 0x38, 0x1C,
0x1b, 'b', 0x2, 0, 0x79, 0x9E,
0x1b, 'b', 0x2, 0, 0x73, 0xCE,
0x1b, 'b', 0x2, 0, 0x73, 0xCE,
0x1b, 'b', 0x2, 0, 0xF9, 0x9F,
0x1b, 'b', 0x2, 0, 0xF8, 0x1F,
0x1b, 'b', 0x2, 0, 0xFE, 0x7F,
0x1b, 'b', 0x2, 0, 0xFF, 0xFF,
0x1b, 'b', 0x2, 0, 0xFF, 0xFF,
0x1b, 'b', 0x2, 0, 0x00, 0x00,
0x1b, 'b', 0x2, 0, 0x00, 0x00,
0x1b, 'b', 0x2, 0, 0x00, 0x00,
0x1b, 'b', 0x2, 0, 0x00, 0x00};
[self.currentDataBeingSent appendBytes:rasterImage length:sizeof(rasterImage)];
Simply squirt that out to the printer and you should get a picture as above. This is where you can easily tweak and play about with the exact commands to get something that's working. Often this is the only way I've ever managed to figure out what should be done.
rev.3
Ref. comments.
If you have a byte per pixel then you will need to merge these into a series of bits; the following should do the job based on your pastebin code. I've also changed the char*
to be unsigned as it is signed can cause problems when bit manipulating.
NSUInteger bitmapBytePerRow = width/8;
NSUInteger bytesPerRow = 3 + bitmapBytePerRow;
[self.currentDataBeingSent = [NSMutableData dataWithLength:bytesPerRow * height];
[self.currentDataBeingSent appendBytes:initializeRaster length:sizeof(initializeRaster)];
[self.currentDataBeingSent appendBytes:enterRaster length:sizeof(enterRaster)];
NSUInteger byteOffset = 0;
for (NSUInteger y = 0; y < height; y++)
{
unsigned char *rasterCommandForRow = (unsigned char *)calloc(bytesPerRow, sizeof(char));
unsigned char *current_raster = rasterCommandForRow;
*current_raster++ = '\x6B';
*current_raster++ = (width*height) % 256;
*current_raster++ = (width*height) / 256;
unsigned char mask = '\x80' ;
unsigned char out = 0 ;
for (NSUInteger x = 0; x < width; x++)
{
if (*(data + (byteOffset * sizeof(char))))
out |= mask ;
byteOffset++;
mask >>= 1 ;
if( 0 == mask )
{
mask = '\x80' ;
*current_raster++ = out ;
if( out )
lastDot = nextOut ;
out = 0 ;
}
}
// handle partially finished byte .
if( ( '\x80' != mask ) && ( 0 != out ) )
*current_raster++ = out ;
[self.currentDataBeingSent appendBytes:rasterCommandForRow length:bytesPerRow];
}
rev.3a
Looking at the Mac CUPS support from Star it's got the source code for the driver which contains a lot of clues about how this should be done. Sometimes code is so much easier to read than documentation.
starcupsdrv-3.1.1_mac_20100423.zip\starcupsdrv-3.1.1_mac\SourceCode\
contains starcupsdrv-src-3.1.1.tar.gz\
sub folder starcupsdrv\src\
View rastertostar.c, the important bit is the calculation of the n1 / n2 values. These aren't at all X & Y but based on the pixel count, lastBlackPixel is the count of pixels from the source.
putchar('b');
putchar((char) ((lastBlackPixel > 0)?(lastBlackPixel % 256):1));
putchar((char) (lastBlackPixel / 256));
I've modified the code above to include the fixes, hopefully that'll be closer. If not post a scan of what comes out of the printer, it will be useful to diagnose what's happening.
For reference The code between 580:650 from jsStarUSB.cpp seems to me to be along the lines of what you need to produce a buffer (stored in nextOut
) that contains the raster data in the format to be sent directly to the printer.