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