src/ptouch.c

changeset 9
ebce4a7615e9
parent 3
4aec27d9d4da
child 14
088286f9e1e4
     1.1 --- a/src/ptouch.c	Mon Aug 03 16:14:35 2009 +0100
     1.2 +++ b/src/ptouch.c	Mon Aug 03 17:23:54 2009 +0100
     1.3 @@ -13,9 +13,10 @@
     1.4  
     1.5  #include <stdio.h>
     1.6  #include <stdlib.h>
     1.7 +#include <stdbool.h>
     1.8  #include <string.h>
     1.9 +#include <gd.h>
    1.10  #include "hexdump.h"
    1.11 -#include "pt_image.h"
    1.12  #include "ptouch.h"
    1.13  
    1.14  #define ESC 0x1b
    1.15 @@ -68,7 +69,7 @@
    1.16  	// Check for timeout
    1.17  	if (timeout == 0) {
    1.18  		// Timeout
    1.19 -		return -1;
    1.20 +		return PT_ERR_TIMEOUT;
    1.21  	}
    1.22  
    1.23  #ifdef DEBUG
    1.24 @@ -77,8 +78,6 @@
    1.25  #endif
    1.26  
    1.27  	// Decode the status buffer, store the results in the device object
    1.28 -	dev->headMark     = buf[0];
    1.29 -	dev->size         = buf[1];
    1.30  	dev->errorInfo[0] = buf[8];
    1.31  	dev->errorInfo[1] = buf[9];
    1.32  	dev->mediaWidth   = buf[10];
    1.33 @@ -90,29 +89,150 @@
    1.34  	dev->phaseLo      = buf[21];
    1.35  	dev->notification = buf[22];
    1.36  
    1.37 +	// Set pixel width (label width in pixels)
    1.38 +	if (dev->mediaWidth >= 24) {
    1.39 +		// Label tape is 24mm or wider. Print head is 128 dots at 180dpi,
    1.40 +		// which is 18.06mm. Thus, we can only print on the centre 18mm
    1.41 +		// of a tape that is wider than 18mm.
    1.42 +		dev->pixelWidth = 128;
    1.43 +	} else {
    1.44 +		// Print head is 180dpi. Pixel size is mediaWidth * dpi. If we
    1.45 +		// multiply by ten, then divide by 254, we can avoid using
    1.46 +		// floating point to convert from inches to mm. The -2 is a
    1.47 +		// safety margin -- one pixel on either side of the label.
    1.48 +		// This is far closer than Brother suggest, but hey-ho.
    1.49 +		dev->pixelWidth = ((dev->mediaWidth * 180 * 10) / 254) - 2;
    1.50 +	}
    1.51 +
    1.52  	// Operation succeeded
    1.53 -	return 0;
    1.54 +	return PT_ERR_SUCCESS;
    1.55  }
    1.56  
    1.57 -// TODO: print options struct parameter (e.g. fullcut, halfcut, print res,
    1.58 +// TODO: print options struct parameter (e.g. fullcut, halfcut, print res, ...)
    1.59 +//
    1.60  //
    1.61 -int pt_Print(pt_Device *dev, pt_Image *image)
    1.62 +
    1.63 +// labels: 1 or more labels
    1.64 +// count: number of labels, 0<count<MAXINT
    1.65 +int pt_Print(pt_Device *dev, gdImagePtr *labels, int count)
    1.66  {
    1.67 -	// TODO: trap dev == NULL
    1.68 -	// TODO: trap image == NULL
    1.69 -	// TODO: trap image.height > printhead.height
    1.70 -	// TODO: trap image.height <= 0
    1.71 -	// TODO: trap image.width <= 0
    1.72 +	int err;
    1.73 +	gdImagePtr *curLabel = labels;
    1.74 +
    1.75 +	// trap dev == NULL
    1.76 +	if (dev == NULL) {
    1.77 +		return PT_ERR_BAD_PARAMETER;
    1.78 +	}
    1.79 +
    1.80 +	// trap labels == NULL
    1.81 +	if (labels == NULL) {
    1.82 +		return PT_ERR_BAD_PARAMETER;
    1.83 +	}
    1.84 +
    1.85 +	// trap count == 0
    1.86 +	if (count == 0) {
    1.87 +		return PT_ERR_BAD_PARAMETER;
    1.88 +	}
    1.89 +
    1.90 +	// Request current status from the printer
    1.91 +	if ((err = pt_GetStatus(dev)) != PT_ERR_SUCCESS) {
    1.92 +		return err;
    1.93 +	}
    1.94 +
    1.95 +	// Make sure the printer has tape, and is ready
    1.96 +	if ((dev->errorInfo[0] != 0x00) || (dev->errorInfo[1] != 0x00)) {
    1.97 +		return PT_ERR_PRINTER_NOT_READY;
    1.98 +	}
    1.99 +
   1.100 +	// Send the print initialisation commands
   1.101  	//
   1.102 -	// allocate print buffer
   1.103 -	//
   1.104 -	// pack pixels -- 8 pixels => 1 byte
   1.105 -	//
   1.106 -	// compress print data (packbits)
   1.107 -	//
   1.108 -	// send print buffer to printer
   1.109 -	//
   1.110 -	// free print buffer
   1.111 +	// ESC i M -- Set Mode
   1.112 +	fprintf(dev->fp, "%ciM%c", ESC,
   1.113 +			(dev->autocut ? 0x40 : 0x00) | (dev->mirror ? 0x80 : 0x00));
   1.114 +
   1.115 +	// ESC i K -- Set Expanded Mode
   1.116 +	fprintf(dev->fp, "%ciK%c", ESC, 0x00);
   1.117 +
   1.118 +	// ESC i R {n1} -- Set Raster Graphics Transfer Mode
   1.119 +	//   {n1} = 0x01 ==> Raster Graphics mode
   1.120 +	fprintf(dev->fp, "%ciR%c", ESC, 0x01);
   1.121 +
   1.122 +	// M {n1} -- Set Compression Mode
   1.123 +	//   {n1} = 0x00 ==> no compression
   1.124 +	//   {n1} = 0x01 ==> reserved
   1.125 +	//   {n1} = 0x02 ==> TIFF/Packbits
   1.126 +	fprintf(dev->fp, "M%c", 0x00);
   1.127 +
   1.128 +	// Loop over the images that were passed in
   1.129 +	for (int imnum=0; imnum < count; imnum++) {
   1.130 +		// Make sure image is the right size for this label tape
   1.131 +		if (gdImageSY(*curLabel) != dev->pixelWidth) {
   1.132 +			return PT_ERR_LABEL_TOO_WIDE;
   1.133 +		}
   1.134 +
   1.135 +		//
   1.136 +		// TODO: trap image height / width == 0?
   1.137 +		// will libgd allow an image with a zero dimension?
   1.138 +		//
   1.139 +
   1.140 +		// Iterate left-to-right over the source image
   1.141 +		for (int xpos = 0; xpos < gdImageSX(*curLabel); xpos++) {
   1.142 +			char bitbuf[128/8];		// 128-dot printhead, 8 bits per byte
   1.143 +			int rowclear = true;	// TRUE if entire row is clear, else FALSE
   1.144 +
   1.145 +			// Fill bit buffer with zeroes
   1.146 +			memset(bitbuf, 0x00, sizeof(bitbuf));
   1.147 +
   1.148 +			// Calculate left-side margin for this label size
   1.149 +			// Again, 128-dot printhead.
   1.150 +			int margin = (128 + dev->pixelWidth) / 2;
   1.151 +
   1.152 +			// Copy data from the image to the bit-buffer
   1.153 +			for (int ypos = 0; ypos < gdImageSY(*curLabel); ypos++) {
   1.154 +				// Get pixel from gd, is it white (palette entry 0)?
   1.155 +				if (gdImageGetPixel(*curLabel, xpos, ypos) != 0) {
   1.156 +					// No. Set the bit.
   1.157 +					int bit = 1 << (7 - ((margin+ypos) % 8));
   1.158 +					bitbuf[(margin+ypos) / 8] |= bit;
   1.159 +
   1.160 +					// Clear the "row is clear" flag
   1.161 +					rowclear = false;
   1.162 +				}
   1.163 +			}
   1.164 +
   1.165 +			// We now have the image data in bitbuf, and a flag to say whether
   1.166 +			// there are any black pixels in the buffer. We can pack full-rows
   1.167 +			// by sending a "Z" character, i.e. "this row is entirely blank".
   1.168 +			// If not, we have to send a (128/8)=16 byte chunk of image data.
   1.169 +			if (rowclear) {
   1.170 +				// Row is clear -- send a "clear row" command
   1.171 +				fprintf(dev->fp, "Z");
   1.172 +			} else {
   1.173 +				// Row is not clear -- send the pixel data
   1.174 +				//
   1.175 +				// TODO: the printer supports Packbits compression. Implement!
   1.176 +				fprintf(dev->fp, "G");
   1.177 +				for (int i=0; i<sizeof(bitbuf); i++) {
   1.178 +					fputc(bitbuf[i], dev->fp);
   1.179 +				}
   1.180 +			}
   1.181 +		}
   1.182 +
   1.183 +		// Is this the last label?
   1.184 +		if (imnum == (count-1)) {
   1.185 +			// Yes, send an End Job command
   1.186 +			fprintf(dev->fp, "%c", 0x1A);
   1.187 +		} else {
   1.188 +			// No, more labels to print. Send a formfeed.
   1.189 +			fprintf(dev->fp, "%c", 0x0C);
   1.190 +		}
   1.191 +
   1.192 +		// Move onto the next label
   1.193 +		curLabel++;
   1.194 +	}
   1.195 +
   1.196 +	// Operation successful.
   1.197 +	return PT_ERR_SUCCESS;
   1.198  }
   1.199  
   1.200  void pt_Close(pt_Device *dev)