1st version with printing support. Now uses Libgd for image generation functionality.

Mon, 03 Aug 2009 17:23:54 +0100

author
Philip Pemberton <philpem@philpem.me.uk>
date
Mon, 03 Aug 2009 17:23:54 +0100
changeset 9
ebce4a7615e9
parent 8
a2989aa17d21
child 10
604c205d9163

1st version with printing support. Now uses Libgd for image generation functionality.

Makefile file | annotate | diff | revisions
src/ptouch.c file | annotate | diff | revisions
src/ptouch.h file | annotate | diff | revisions
     1.1 --- a/Makefile	Mon Aug 03 16:14:35 2009 +0100
     1.2 +++ b/Makefile	Mon Aug 03 17:23:54 2009 +0100
     1.3 @@ -113,7 +113,7 @@
     1.4  # libraries to link in -- these will be specified as "-l" parameters, the -l
     1.5  # is prepended automatically
     1.6  #LIB			=	jpeg tiff png z
     1.7 -LIB			=
     1.8 +LIB			=	gd
     1.9  # library paths -- where to search for the above libraries
    1.10  LIBPATH		=
    1.11  # include paths -- where to search for #include files (in addition to the
     2.1 --- a/src/ptouch.c	Mon Aug 03 16:14:35 2009 +0100
     2.2 +++ b/src/ptouch.c	Mon Aug 03 17:23:54 2009 +0100
     2.3 @@ -13,9 +13,10 @@
     2.4  
     2.5  #include <stdio.h>
     2.6  #include <stdlib.h>
     2.7 +#include <stdbool.h>
     2.8  #include <string.h>
     2.9 +#include <gd.h>
    2.10  #include "hexdump.h"
    2.11 -#include "pt_image.h"
    2.12  #include "ptouch.h"
    2.13  
    2.14  #define ESC 0x1b
    2.15 @@ -68,7 +69,7 @@
    2.16  	// Check for timeout
    2.17  	if (timeout == 0) {
    2.18  		// Timeout
    2.19 -		return -1;
    2.20 +		return PT_ERR_TIMEOUT;
    2.21  	}
    2.22  
    2.23  #ifdef DEBUG
    2.24 @@ -77,8 +78,6 @@
    2.25  #endif
    2.26  
    2.27  	// Decode the status buffer, store the results in the device object
    2.28 -	dev->headMark     = buf[0];
    2.29 -	dev->size         = buf[1];
    2.30  	dev->errorInfo[0] = buf[8];
    2.31  	dev->errorInfo[1] = buf[9];
    2.32  	dev->mediaWidth   = buf[10];
    2.33 @@ -90,29 +89,150 @@
    2.34  	dev->phaseLo      = buf[21];
    2.35  	dev->notification = buf[22];
    2.36  
    2.37 +	// Set pixel width (label width in pixels)
    2.38 +	if (dev->mediaWidth >= 24) {
    2.39 +		// Label tape is 24mm or wider. Print head is 128 dots at 180dpi,
    2.40 +		// which is 18.06mm. Thus, we can only print on the centre 18mm
    2.41 +		// of a tape that is wider than 18mm.
    2.42 +		dev->pixelWidth = 128;
    2.43 +	} else {
    2.44 +		// Print head is 180dpi. Pixel size is mediaWidth * dpi. If we
    2.45 +		// multiply by ten, then divide by 254, we can avoid using
    2.46 +		// floating point to convert from inches to mm. The -2 is a
    2.47 +		// safety margin -- one pixel on either side of the label.
    2.48 +		// This is far closer than Brother suggest, but hey-ho.
    2.49 +		dev->pixelWidth = ((dev->mediaWidth * 180 * 10) / 254) - 2;
    2.50 +	}
    2.51 +
    2.52  	// Operation succeeded
    2.53 -	return 0;
    2.54 +	return PT_ERR_SUCCESS;
    2.55  }
    2.56  
    2.57 -// TODO: print options struct parameter (e.g. fullcut, halfcut, print res,
    2.58 +// TODO: print options struct parameter (e.g. fullcut, halfcut, print res, ...)
    2.59 +//
    2.60  //
    2.61 -int pt_Print(pt_Device *dev, pt_Image *image)
    2.62 +
    2.63 +// labels: 1 or more labels
    2.64 +// count: number of labels, 0<count<MAXINT
    2.65 +int pt_Print(pt_Device *dev, gdImagePtr *labels, int count)
    2.66  {
    2.67 -	// TODO: trap dev == NULL
    2.68 -	// TODO: trap image == NULL
    2.69 -	// TODO: trap image.height > printhead.height
    2.70 -	// TODO: trap image.height <= 0
    2.71 -	// TODO: trap image.width <= 0
    2.72 +	int err;
    2.73 +	gdImagePtr *curLabel = labels;
    2.74 +
    2.75 +	// trap dev == NULL
    2.76 +	if (dev == NULL) {
    2.77 +		return PT_ERR_BAD_PARAMETER;
    2.78 +	}
    2.79 +
    2.80 +	// trap labels == NULL
    2.81 +	if (labels == NULL) {
    2.82 +		return PT_ERR_BAD_PARAMETER;
    2.83 +	}
    2.84 +
    2.85 +	// trap count == 0
    2.86 +	if (count == 0) {
    2.87 +		return PT_ERR_BAD_PARAMETER;
    2.88 +	}
    2.89 +
    2.90 +	// Request current status from the printer
    2.91 +	if ((err = pt_GetStatus(dev)) != PT_ERR_SUCCESS) {
    2.92 +		return err;
    2.93 +	}
    2.94 +
    2.95 +	// Make sure the printer has tape, and is ready
    2.96 +	if ((dev->errorInfo[0] != 0x00) || (dev->errorInfo[1] != 0x00)) {
    2.97 +		return PT_ERR_PRINTER_NOT_READY;
    2.98 +	}
    2.99 +
   2.100 +	// Send the print initialisation commands
   2.101  	//
   2.102 -	// allocate print buffer
   2.103 -	//
   2.104 -	// pack pixels -- 8 pixels => 1 byte
   2.105 -	//
   2.106 -	// compress print data (packbits)
   2.107 -	//
   2.108 -	// send print buffer to printer
   2.109 -	//
   2.110 -	// free print buffer
   2.111 +	// ESC i M -- Set Mode
   2.112 +	fprintf(dev->fp, "%ciM%c", ESC,
   2.113 +			(dev->autocut ? 0x40 : 0x00) | (dev->mirror ? 0x80 : 0x00));
   2.114 +
   2.115 +	// ESC i K -- Set Expanded Mode
   2.116 +	fprintf(dev->fp, "%ciK%c", ESC, 0x00);
   2.117 +
   2.118 +	// ESC i R {n1} -- Set Raster Graphics Transfer Mode
   2.119 +	//   {n1} = 0x01 ==> Raster Graphics mode
   2.120 +	fprintf(dev->fp, "%ciR%c", ESC, 0x01);
   2.121 +
   2.122 +	// M {n1} -- Set Compression Mode
   2.123 +	//   {n1} = 0x00 ==> no compression
   2.124 +	//   {n1} = 0x01 ==> reserved
   2.125 +	//   {n1} = 0x02 ==> TIFF/Packbits
   2.126 +	fprintf(dev->fp, "M%c", 0x00);
   2.127 +
   2.128 +	// Loop over the images that were passed in
   2.129 +	for (int imnum=0; imnum < count; imnum++) {
   2.130 +		// Make sure image is the right size for this label tape
   2.131 +		if (gdImageSY(*curLabel) != dev->pixelWidth) {
   2.132 +			return PT_ERR_LABEL_TOO_WIDE;
   2.133 +		}
   2.134 +
   2.135 +		//
   2.136 +		// TODO: trap image height / width == 0?
   2.137 +		// will libgd allow an image with a zero dimension?
   2.138 +		//
   2.139 +
   2.140 +		// Iterate left-to-right over the source image
   2.141 +		for (int xpos = 0; xpos < gdImageSX(*curLabel); xpos++) {
   2.142 +			char bitbuf[128/8];		// 128-dot printhead, 8 bits per byte
   2.143 +			int rowclear = true;	// TRUE if entire row is clear, else FALSE
   2.144 +
   2.145 +			// Fill bit buffer with zeroes
   2.146 +			memset(bitbuf, 0x00, sizeof(bitbuf));
   2.147 +
   2.148 +			// Calculate left-side margin for this label size
   2.149 +			// Again, 128-dot printhead.
   2.150 +			int margin = (128 + dev->pixelWidth) / 2;
   2.151 +
   2.152 +			// Copy data from the image to the bit-buffer
   2.153 +			for (int ypos = 0; ypos < gdImageSY(*curLabel); ypos++) {
   2.154 +				// Get pixel from gd, is it white (palette entry 0)?
   2.155 +				if (gdImageGetPixel(*curLabel, xpos, ypos) != 0) {
   2.156 +					// No. Set the bit.
   2.157 +					int bit = 1 << (7 - ((margin+ypos) % 8));
   2.158 +					bitbuf[(margin+ypos) / 8] |= bit;
   2.159 +
   2.160 +					// Clear the "row is clear" flag
   2.161 +					rowclear = false;
   2.162 +				}
   2.163 +			}
   2.164 +
   2.165 +			// We now have the image data in bitbuf, and a flag to say whether
   2.166 +			// there are any black pixels in the buffer. We can pack full-rows
   2.167 +			// by sending a "Z" character, i.e. "this row is entirely blank".
   2.168 +			// If not, we have to send a (128/8)=16 byte chunk of image data.
   2.169 +			if (rowclear) {
   2.170 +				// Row is clear -- send a "clear row" command
   2.171 +				fprintf(dev->fp, "Z");
   2.172 +			} else {
   2.173 +				// Row is not clear -- send the pixel data
   2.174 +				//
   2.175 +				// TODO: the printer supports Packbits compression. Implement!
   2.176 +				fprintf(dev->fp, "G");
   2.177 +				for (int i=0; i<sizeof(bitbuf); i++) {
   2.178 +					fputc(bitbuf[i], dev->fp);
   2.179 +				}
   2.180 +			}
   2.181 +		}
   2.182 +
   2.183 +		// Is this the last label?
   2.184 +		if (imnum == (count-1)) {
   2.185 +			// Yes, send an End Job command
   2.186 +			fprintf(dev->fp, "%c", 0x1A);
   2.187 +		} else {
   2.188 +			// No, more labels to print. Send a formfeed.
   2.189 +			fprintf(dev->fp, "%c", 0x0C);
   2.190 +		}
   2.191 +
   2.192 +		// Move onto the next label
   2.193 +		curLabel++;
   2.194 +	}
   2.195 +
   2.196 +	// Operation successful.
   2.197 +	return PT_ERR_SUCCESS;
   2.198  }
   2.199  
   2.200  void pt_Close(pt_Device *dev)
     3.1 --- a/src/ptouch.h	Mon Aug 03 16:14:35 2009 +0100
     3.2 +++ b/src/ptouch.h	Mon Aug 03 17:23:54 2009 +0100
     3.3 @@ -11,17 +11,102 @@
     3.4  #ifndef PTOUCH_H
     3.5  #define PTOUCH_H
     3.6  
     3.7 +#include <gd.h>
     3.8 +
     3.9 +/**
    3.10 + * @brief	Device information structure
    3.11 + *
    3.12 + * This is used to store the state of the printer as of the last call to
    3.13 + * pt_GetStatus(), the current job settings, and other details required
    3.14 + * by the printer driver.
    3.15 + */
    3.16  typedef struct {
    3.17 +	/// Reference to the printer device
    3.18  	FILE	*fp;
    3.19 -	int		headMark, size, errorInfo[2];
    3.20 +	/// Error information
    3.21 +	int		errorInfo[2];
    3.22 +	/// Label width, type and length
    3.23  	int		mediaWidth, mediaType, mediaLength;
    3.24 +	/// Label width in pixels
    3.25 +	int		pixelWidth;
    3.26 +	/// Status type, phase type, and phase number
    3.27  	int		statusType, phaseType, phaseHi, phaseLo;
    3.28 +	/// Notification number
    3.29  	int		notification;
    3.30 +
    3.31 +	/// Print parameter: autocutter enable
    3.32 +	int		autocut;
    3.33 +	/// Print parameter: mirror printing enable
    3.34 +	int		mirror;
    3.35 +	/// Print parameter: half-cut enable
    3.36 +	/// Print parameter: chainprint enable
    3.37 +	/// Print parameter: label end cut
    3.38  } pt_Device;
    3.39  
    3.40 -// printer functions
    3.41 +/*
    3.42 + * Function return codes
    3.43 + */
    3.44 +enum {
    3.45 +/// Operation completed successfully
    3.46 +	PT_ERR_SUCCESS				= 0,
    3.47 +
    3.48 +/// Data transfer timed out
    3.49 +	PT_ERR_TIMEOUT				= -1,
    3.50 +
    3.51 +/// Invalid parameter
    3.52 +	PT_ERR_BAD_PARAMETER		= -2,
    3.53 +
    3.54 +/// Label image is too large for this label tape
    3.55 +	PT_ERR_LABEL_TOO_WIDE		= -3,
    3.56 +
    3.57 +/// Printer is not ready
    3.58 +	PT_ERR_PRINTER_NOT_READY	= -4
    3.59 +};
    3.60 +
    3.61 +
    3.62 +/**
    3.63 + * @brief	Initialise the printer
    3.64 + * 
    3.65 + * Initialises the printer and returns a pointer to a pt_Device struct
    3.66 + * describing it.
    3.67 + *
    3.68 + * @param	path	Path to the printer device file (e.g. /dev/usb/lp0)
    3.69 + * @return	On success, a pt_Device struct referring to the printer.
    3.70 + * 			On failure, NULL.
    3.71 + */
    3.72  pt_Device *pt_Initialise(char *path);
    3.73 -int pt_GetStatus(pt_Device *dev);
    3.74 +
    3.75 +/**
    3.76 + * @brief	Close a printer device
    3.77 + *
    3.78 + * Closes the connection to the printer, and destroys the pt_Device struct.
    3.79 + *
    3.80 + * @param	dev		A pt_Device struct created by pt_Initialise.
    3.81 + */
    3.82  void pt_Close(pt_Device *dev);
    3.83  
    3.84 +/**
    3.85 + * @brief	Get the current status of the printer
    3.86 + *
    3.87 + * Queries the printer for its current status, then returns the result.
    3.88 + *
    3.89 + * @param	dev		A pt_Device struct created by pt_Initialise.
    3.90 + * @return	Any valid PT_ERR_* constant. The pt_Device struct passed in
    3.91 + * 	is also updated with the current status of the printer.
    3.92 + */
    3.93 +int pt_GetStatus(pt_Device *dev);
    3.94 +
    3.95 +/**
    3.96 + * @brief	Print one or more labels
    3.97 + *
    3.98 + * Takes a pointer to an array of Libgd images, and prints each of them.
    3.99 + *
   3.100 + * @param	dev		A pt_Device struct created by pt_Initialise.
   3.101 + * @param	labels	A pointer to an array of gdImagePtr objects containing
   3.102 + *	the labels to be printed.
   3.103 + * @param	count	The number of labels to be printed.
   3.104 + * @return	Any valid PT_ERR_* constant.
   3.105 + */
   3.106 +int pt_Print(pt_Device *dev, gdImagePtr *labels, int count);
   3.107 +
   3.108  #endif // PTOUCH_H