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