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)