diff --git a/src/filter.c b/src/filter.c --- a/src/filter.c +++ b/src/filter.c @@ -49,7 +49,7 @@ #define PIPSLITE_FILTER_VERSION "* epson-escpr is a part of " PACKAGE_STRING -#define PIPSLITE_FILTER_USAGE "Usage: $ epson-escpr model width_pixel height_pixel Ink PageSize MediaType Duplex InputSlot Brightness Contrast Saturation" +#define PIPSLITE_FILTER_USAGE "Usage: $ epson-escpr model width_pixel height_pixel HWResolution[0] Ink PageSize MediaType Duplex InputSlot Brightness Contrast Saturation" FILE* outfp = NULL; @@ -194,7 +194,7 @@ static int getMediaSizeID(char *media_name){ /////////////////////////////////////////////////////////////////////////////////////////////////////////// -/* Useage: epson-escpr model width_pixel height_pixel Ink PageSize MediaType */ +/* Useage: epson-escpr model width_pixel height_pixel HWResolution[0] Ink PageSize MediaType */ int main (int argc, char *argv[]) { @@ -398,12 +398,7 @@ main (int argc, char *argv[]) /* debug */ DEBUG_JOB_STRUCT (printJob); - x_mag = (double)print_area_x / width_pixel; - y_mag = (double)print_area_y / height_pixel; band_line = 1; - bytes_per_line = width_pixel * byte_par_pixel; - debug_msg("bytes_per_line = %d\n", bytes_per_line); - image_raw = mem_new0 (char, bytes_per_line); int page_count = 0; @@ -416,6 +411,23 @@ main (int argc, char *argv[]) y_count = 0; band_line_count = 0; + // TODO: Do we REALLY care about interrupts here? + unsigned char num_buf[4]; +#define LE_READ(buf) (buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24)) + read(STDIN_FILENO, num_buf, 4); + width_pixel = LE_READ(num_buf); + read(STDIN_FILENO, num_buf, 4); + height_pixel = LE_READ(num_buf); +#undef LE_READ + x_mag = (double)print_area_x / width_pixel; + y_mag = (double)print_area_y / height_pixel; + bytes_per_line = width_pixel * byte_par_pixel; + debug_msg("bytes_per_line = %d\n", bytes_per_line); + image_raw = mem_new0 (char, bytes_per_line); + + // This is the last use of page_num. The only other use at the + // end for epsEndPage() is commented out for some reason I don't + // dare to imagine. if(page_num == 99){ err = epsStartPage(NULL, 2); }else{ @@ -693,6 +705,8 @@ main (int argc, char *argv[]) if(err) err_fatal ("Error occurred in \"PEND_FUNC\"."); /* exit */ } + + mem_free(image_raw); } DEDBUG_END; @@ -708,7 +722,6 @@ quit:; err_fatal ("Error occurred in \"END_FUNC\"."); /* exit */ /* free alloced memory */ - mem_free(image_raw); mem_free(band); mem_free(paper); debug_msg("PRINT SUCCESS\n"); diff --git a/src/wrapper.c b/src/wrapper.c --- a/src/wrapper.c +++ b/src/wrapper.c @@ -59,8 +59,6 @@ int cancel_flg; static FILE *debug_f = NULL; #endif -#define safeFree(x) { if (x !=NULL) free(x); } - #define HAVE_DEBUG 0 static void debug_msg(const char *fmt, ...){ #if (HAVE_DEBUG) @@ -174,205 +172,111 @@ main (int argc, char *argv[]) return 1; } - pfp = NULL; - - int total_read = 0; - int total_read_cache = 0; - char *page_raw; //2ページ分のバッファ - char *page_raw_cache;//2ページ分のキャッシュ - - static BOOL first_fwrite = TRUE; - static BOOL cache_exist = FALSE; - - int pageNum = 0; - while (1) - { - int ret; - ret = cupsRasterReadHeader (ras, &header); - - if (ret == 0 || cancel_flg) //データをすべて読み終わった - { - - if(cache_exist){//cacheがあればcacheを送信 - int pageNum_cache = 2; - if(first_fwrite){//最初のfwriteだけ、ページ数を送信 - fwrite (&pageNum_cache, 1, 1, pfp); - first_fwrite = FALSE; - } - - switch (pageNum){ - case 1: - page_raw_cache[0] = 2; - page_raw_cache[total_read_cache/2 + 1] = 1; - break; - case 2: - page_raw_cache[0] = 99; - page_raw_cache[total_read_cache/2 + 1] = 99; - break; - default: - break; - } - - fwrite (page_raw_cache, total_read_cache + pageNum_cache, 1, pfp); - cache_exist = FALSE; - total_read_cache = 0; - } - - //バッファを送信 - switch (pageNum){ - case 1: - page_raw[0] = 0; - break; - case 2: - page_raw[0] = 1; - page_raw[total_read/2 + 1] = 0; - break; - default: - break; - } - - if (pfp == NULL) // do not write anything if pipe is not open - break; - - if(first_fwrite){//最初のfwriteだけ、ページ数を送信 - fwrite (&pageNum, 1, 1, pfp); - first_fwrite = FALSE; - } - - fwrite (page_raw, total_read + pageNum, 1, pfp); - - - break; - - }else{ - if(pageNum == 2){ //全部読み終わってないとき、2ページ分たまったら - total_read_cache = total_read; - - if(cache_exist){//cacheがあればcacheを送信 - int pageNum_cache = 2; - if(first_fwrite){//最初のfwriteだけ、ページ数を送信 - fwrite (&pageNum_cache, 1, 1, pfp); - first_fwrite = FALSE; - } - - switch (pageNum){ - case 1: - page_raw_cache[0] = 99; - page_raw_cache[total_read_cache/2 + 1] = 99; - break; - case 2: - page_raw_cache[0] = 2; - page_raw_cache[total_read_cache/2 + 1] = 99; - break; - default: - break; - } - - fwrite (page_raw_cache, total_read_cache + pageNum_cache, 1, pfp); - cache_exist = FALSE; - } - - //バッファをキャッシュへコピー - memcpy(page_raw_cache, page_raw, total_read_cache + pageNum + 1); - cache_exist = TRUE; - - total_read = 0; - pageNum = 0; - - } - } - - int image_bytes; - char *image_raw; - - if (pfp == NULL) - { - char tmpbuf[256]; - - sprintf (tmpbuf, "%s/%s \"%s\" %d %d %d %s %s %s %s %s %s %s %s", - CUPS_FILTER_PATH, - CUPS_FILTER_NAME, - fopt.model, - header.cupsWidth, - header.cupsHeight, - header.HWResolution[0], - fopt.ink, - fopt.media, - fopt.quality, - fopt.duplex, - fopt.inputslot, - fopt.brightness, - fopt.contrast, - fopt.saturation); - - debug_msg("tmpbuf = [%s]\n", tmpbuf); - - pfp = popen (tmpbuf, "w"); - - if (pfp == NULL) - { - debug_msg("popen error"); - perror ("popen"); - return 1; - } - - // +1 .. left page num (2 / 1 / 0) , *2 .. 2page分のバッファ - image_bytes = (WIDTH_BYTES(header.cupsBytesPerLine * 8 ) * header.cupsHeight + 1) * 2; - page_raw = (char *)calloc (sizeof (char), image_bytes); - page_raw_cache = (char *)calloc (sizeof (char), image_bytes); - - } - - image_bytes = WIDTH_BYTES(header.cupsBytesPerLine * 8 ) * CUPS_READ_LINE; - image_raw = (char *)calloc (sizeof (char), image_bytes); - - - int left_lines = header.cupsHeight; - while(!cancel_flg) - { - int cups_read_lines; - if(left_lines >= CUPS_READ_LINE){ - cups_read_lines = CUPS_READ_LINE; - }else{ - cups_read_lines = left_lines; - } - - int readpixels; - readpixels = cupsRasterReadPixels (ras, (unsigned char*)image_raw, header.cupsBytesPerLine * cups_read_lines); - - if (readpixels == 0) - { - // 1ページ分読み込み完了 - break; - } - - memcpy((page_raw + pageNum +1) + total_read, image_raw, readpixels); - total_read += readpixels; - - left_lines -= CUPS_READ_LINE; - - }//while (pixel data) - - safeFree (image_raw); - - pageNum++; - - }//while (cups header) - - safeFree (page_raw); - safeFree (page_raw_cache); - - cupsRasterClose (ras); - - if (pfp == NULL) - { + // The original just wrote to an uninitialized pointer if this failed. + // Reading a header at the start like this is ugly, but unfortunately I + // can't send HWResolution[0] to the child process every page because it + // puts the value into a global variable and does god knows what with it + // during initialization. Bleh. + if (cupsRasterReadHeader(ras, &header) == 0 || cancel_flg) + return 1; + + char tmpbuf[256]; // I'd REALLY like to get rid of this. + sprintf(tmpbuf, "%s/%s \"%s\" %d %d %d %s %s %s %s %s %s %s %s", + CUPS_FILTER_PATH, + CUPS_FILTER_NAME, + fopt.model, + // First two are no longer used. The third unfortunately is. + header.cupsWidth, + header.cupsHeight, + header.HWResolution[0], + fopt.ink, + fopt.media, + fopt.quality, + fopt.duplex, + fopt.inputslot, + fopt.brightness, + fopt.contrast, + fopt.saturation); + debug_msg("tmpbuf = [%s]\n", tmpbuf); + + pfp = popen(tmpbuf, "w"); + if (pfp == NULL) { debug_msg("popen error"); perror ("popen"); return 1; - }else{ - pclose (pfp); } + // Allegedly, this is the number of pages. However, this program only + // ever sends 1 (when there is only one page) or 2 (otherwise). As far + // as I can tell, sending 2 when there is one page changes nothing, so + // we abuse that for a noticeable simplification. + fputc(2, pfp); + + // The wrapper sends pages of raw pixel data over the wire to the child + // process. Each page is prefixed with a `page_num' byte that does... + // something. According to the docs it's the number of remaining pages, + // but the driver is shamelessly lying to the printer and only tells it + // two, one or zero pages are remaining, so who really knows. To be able + // to set page_num for the final two pages, we need to always keep the + // two most recent pages in memory, urgh. + // + // We extend this protocol by sending two 4-byte little endian integers + // after the page_num. They're cupsWidth and cupsHeight respectively. + unsigned char *pages[2]; + unsigned page_sizes[2]; + int page_counter = 0; + + // At the start of the loop body we always have a header read in and a + // page waiting to be processed. If we could delay the first read until + // the child process has spawned, this could be a standard loop. + while (1) { + if (page_counter == 2) { + pages[0][0] = 2; // confirmed not among final two pages + fwrite(pages[0], page_sizes[0], 1, pfp); + free(pages[0]); + pages[0] = pages[1]; + pages[0][0] = 1; // second to last page afawk right now + page_sizes[0] = page_sizes[1]; + page_counter--; + } + + unsigned line_size = header.cupsBytesPerLine; + unsigned new_size = 1 + 4 + 4 + line_size * header.cupsHeight; + pages[page_counter] = malloc(new_size); + page_sizes[page_counter] = new_size; + pages[page_counter][0] = 0; // last page afawk right now +#define LE_WRITE(p, i, x) do { p[i]=x; p[i+1]=(x>>8); p[i+2]=(x>>16); p[i+3]=(x>>24); } while(0) + LE_WRITE(pages[page_counter], 1, header.cupsWidth); + LE_WRITE(pages[page_counter], 1 + 4, header.cupsHeight); +#undef LE_WRITE + + unsigned char *raw_line = malloc(line_size); + int total_read = 0; + + for (int left_lines = header.cupsHeight; left_lines > 0; --left_lines) { + if (cancel_flg) + break; + int bytes = cupsRasterReadPixels(ras, raw_line, line_size); + if (bytes == 0) + break; + memcpy(pages[page_counter] + 1 + 4 + 4 + total_read, raw_line, bytes); + total_read += bytes; + } + free(raw_line); + page_counter++; + + if (cupsRasterReadHeader(ras, &header) == 0 || cancel_flg) + break; + } + + for (int i = 0; i < page_counter; ++i) { + fwrite(pages[i], page_sizes[i], 1, pfp); + free(pages[i]); + } + + pclose(pfp); + cupsRasterClose(ras); + return 0; }