From: Charles Briscoe-S. <cp...@de...> - 2000-05-13 02:34:32
|
On Mon, May 08, 2000 at 08:39:33PM -0400, Robert L Krawitz wrote: > BTW, since you're a Debian developer and there are a number of people > here interested in how to package this up for Debian, how would you > like to become a developer on this project? If you'd like to, just > get yourself an account on sourceforge.net and drop me a note. We > need someone to create .deb's (as well as rpm's). If Eric isn't able to do this, I'm willing to give it a go sometime. I think it would be best to co-ordinate with Ben Gertzfield <ch...@de...> since he maintains the Debian gimp packages. Since /usr/lib/gimp/1.1/plug-ins/print already exists in gimp1.1, either gimp-print should be included in that package in place of the print plugin currently in gimp1.1, or a separate package would have to divert (or possibly replace, but that's rather ugly so I'd rather not) the gimp1.1 print plugin. (There's little point packaging it for gimp 1.0 even if it compiles with it; gimp 1.0 users want stability...) BTW, I noticed that gimp-print puts its printrc in ~/.gimp rather than ~/.gimp-1.1. Why's that? (In preparation for gimp v1.2, perhaps?) > That [CVS 4th May] should be pretty good, although the 3.1.4 release might be > slightly better (or it might not). I've updated from CVS, but I haven't really tested it yet. > See above about the tiny dots. It might also be (barely) noticeably > different in things with very sharp transitions or very fine lines. I tried a picture of a cactus. The 1440x720DPI softweave gives better-defined results than 720DPI softweave in the case of a light cactus needle against a dark background. For a dark needle on a light background, there was nothing to choose between the two. Something that I thought might be useful would be interpolation. The dither routine could be supplied with the row before the current position and the row after, and could interpolate the colour of its current location from the surrounding pixels. This might be desirable when scaling up an image a lot, so that the low resolution of the original image does not cause ugly pixellation in the printed output. This would have to be an option, of course, since it would only be appropriate for some kinds of images, like photos. > 1"x1.6": > 360DPI: 3sec 7sec > Dark, grainy, too magenta, but fast. > > Try a density of 1.0 here. > > 720DPI microweave: 6sec 34sec > Much, much too dark. The printer dumped so much ink on this one > that the photo paper actually went slightly soggy, something I > never expected to see (although it didn't actually soak through to > the back). > > Again, try a density of 1.0 here, and don't bother using this mode. The 360DPI mode is little light with density 1.0 and 720DPI microweave is a little dark, but it's quite close. The microweave modes are still really bitty. The driver doesn't seem to be using variable sized dots when in microweave mode. Still, as you say, there's no reason to use these modes on the 870. > 720DPI softweave: 6sec 24sec > Good. Bidirectional printing, so it was pretty fast, and I'm > surprised this didn't affect the print quality. When I print a > more complex full A4-width image in this mode, the printer pauses > at the end of each pass, presumably waiting for more data. It looks > like the parallel protocol is the bottleneck in this mode. I tried > setting the parport to ECP and EPP mode, and giving Linux the DMA > channel for this one, but wasn't able to speed it up any. > > I have the same problem (kernel 2.2.10). What kernel are you running? 2.2.14. Is USB likely to be faster? I don't remember what USB's transfer rate is supposed to be. The machine has a USB port, and, IIRC, Linux 2.2.15 does USB. > That's an attempt to correct for the starting vertical position thing > you noted below. I don't have that quite right. This patch seems to fix it; the comment says how I think it does so: ============================================================================== --- print-escp2.c.orig Thu May 11 01:02:20 2000 +++ print-escp2.c Thu May 11 01:03:01 2000 @@ -1002,8 +1002,14 @@ * would happen in softweave mode. The divide by 10 is to convert * lines into points (Epson printers all have 720 ydpi); */ + /* + * (-5) instead of (+5) to effectively reduce the nozzle count by + * one; in softweave mode, we start printing with the bottom-most + * nozzle which is (nozzles - 1) * nozzle_separation distant from + * the top nozzle. + */ int extra_points = (escp2_nozzles(model) * - escp2_nozzle_separation(model) + 5) / 10; + escp2_nozzle_separation(model) - 5) / 10; top += extra_points; } ============================================================================== > I guess the weave normally starts printing with the bottom nozzle. > Assume we're advancing the paper by x each pass, the nozzle separation > is s, and assume that x > s. We can instead start printing with the top > nozzle and advance the paper by (x - s) until the weave has expanded to > use all nozzles, then start advancing by x as before. > > The difficulty is that in some of the high resolution modes that > assumption is incorrect (in some cases, it advances by as little as > one row sometimes -- the actual advance varies). If you want to play > with this, check out the test program 'escp2-weavetest'. This (in > combination with run-weavetest) is a regression test for the weave > code, that checks a whole bunch of invariants very carefully. It's > really hard to get it all right, but if you want to take a crack at > it, please do (it would be a really worthwhile contribution). Right > now it does something that works correctly, at the cost of losing the > top and bottom of the sheet. I've spent a day or two so far teasing apart the weave code, and I'm *pretty* sure I know more about how it works than when I started... It's hairy stuff, though. It's going to take a while longer before I understand it. Here's some of what I understand so far, mostly my understanding of your terminology. Please correct me if I'm wrong: The page is rendered to a collection of dots by the dithering code at some resolution, e.g. 720x720DPI. A "row" consists of all the dots output by the dither for printing at a single vertical position. A row may be printed in two or more "subpasses" which print dots at the same vertical position but different horizontal positions. I suppose this is needed if the printer's "raster image" command doesn't allow a high enough horizontal resolution, or if the print head can't print dots as close together as we'd like (I know the old dot matrix printers used to ignore any dot immediately following another dot on the same pin). I'll call a subpass (or a row if it's printed in only one subpass) a "line": a line consists of all the dots printed by a single nozzle during one pass. A "pass" is a group of lines printed in one sweep of the print head. In a pass, each jet on the printhead can be assigned one line, so these lines must be spaced the same way as the printhead's jets. If jets at the top of the pass lie outside the image, they are assigned blank "phantom rows". Unused jets at the bottom of the pass don't need phantom rows, because of the way the printer's "raster image" commands work. initialize_weave() creates a data structure which keeps track of the weaving pattern for a single page, and destroy_weave() cleans it up afterwards. As each row on the page is dithered (in order, top-to-bottom) the row is passed to escp2_write_weave(). This calculates the weave parameters for that row, chops the row up into lines as necessary, and stashes the lines in the softweave data structure. When all the lines for a given pass are available, escp2_write_weave() advances the paper appropriately and prints the pass. initialize_weave() takes parameters: jets: number of nozzles in printhead. sep: separation between nozzles in rows (1/720"). osample: number of passes necessary to print a single row (due to the row's resolution being higher than the printer's horizontal resolution). v_subpasses: number of passes in which to print each "osample" pass in order to bring different jets into play. v_subsample: number of dithered rows for each printed row. I'm not sure what this does. Does it merge rows? Overprint them? Feed the paper in smaller increments than 1/720"? colormode: one of: monochrome, four-colour or six-colour printing. width: number of bits per pixel. linewidth: number of pixels per row. lineheight: number of rows on the page. separationrows: used for calculating paper advance for the 1520/3000. I'm not sure what this does, and I doubt I need to know at the moment. Parameters calculated by initialize_weave(): OVERSAMPLE is the number of lines to be printed on each row. VMOD is the number of lines to be printed in the space between each pair of jets. In other words, it's the number of passes the printhead makes while spanning any given point on the paper. NJETS is the number of jets within whose span we print one line on every row as the printhead moves that distance. That is, a line is printed on a given row once for each time NJETS nozzles move past it. So, in the space of NJETS nozzles, we have to do a complete weave pattern, hitting each row once. The first NJETS nozzles print each row for the first time. The next NJETS nozzles overprint each of those rows to perform the second subpass, the third NJETS nozzles print the third subpass, etc. Thus, we only need consider the first NJETS nozzles when working out our weaving pattern; the rest of the jets simply trail behind at regular intervals. WEAVEFACTOR is the interleave factor, NJETS/SEPARATION rounded up. Each pass, WEAVEFACTOR lines get printed below the previously lowest-printed line. (This is a guess; I don't understand it yet.) I'll try to write down more as I understand it. > It's not possible to reverse feed. At least, it isn't documented, and > I've never seen a Windows print file that suggested that it is. I don't know where I got the idea that it was. I'll have to generate some print files from the Epson driver and see what they get up to. If the initial print position is (as it appears to be) hard up against the top of the page, there would be little reason to back up anyway, except for the sake of simplicity. > The problem is that the Gimp hits plugins with a SIGKILL (kill -9) > whenever you hit cancel, so there's no opportunity to clean up (Sven, > are you listening?) I've tried fixing this; here's the patch. It works by spawning a "monitor" process whose purpose is to spawn lpr and then watch its parent process (the plugin). If the parent sends SIGUSR1 to the monitor process, the print job was successful, so the monitor quits. If the plugin dies before sending SIGUSR1, the monitor kills off lpr, thus cancelling the print job. This also has the nice effect that if the plugin crashes, the print job will be cancelled. ============================================================================== --- print.c.orig Wed May 10 18:13:16 2000 +++ print.c Wed May 10 18:14:32 2000 @@ -293,6 +293,18 @@ #endif /* + * 'usr1_handler()' - Make a note when we receive SIGUSR1. + */ + +static volatile int usr1_interrupt; + +static void +usr1_handler (int signal) +{ + usr1_interrupt = 1; +} + +/* * 'run()' - Run the plug-in... */ @@ -318,6 +330,10 @@ #ifndef GIMP_1_0 GimpExportReturnType export = EXPORT_CANCEL; /* return value of gimp_export_image() */ #endif + int ppid = getpid (), /* PID of plugin */ + opid, /* PID of output process */ + cpid, /* PID of control/monitor process */ + pipefd[2]; /* Fds of the pipe connecting all the above */ INIT_LOCALE ("gimp-print"); @@ -531,7 +547,62 @@ if (plist_current > 0) #ifndef __EMX__ - prn = popen (vars.output_to, "w"); + { + /* + * The following IPC code is only necessary because the GIMP kills + * plugins with SIGKILL if its "Cancel" button is pressed; this + * gives the plugin no chance whatsoever to clean up after itself. + */ + usr1_interrupt = 0; + signal (SIGUSR1, usr1_handler); + if (pipe (pipefd) != 0) { + prn = NULL; + } else { + cpid = fork (); + if (cpid < 0) { + prn = NULL; + } else if (cpid == 0) { + /* LPR monitor process. Printer output is piped to us. */ + opid = fork (); + if (opid < 0) { + /* Errors will cause the plugin to get a SIGPIPE. */ + exit (1); + } else if (opid == 0) { + dup2 (pipefd[0], 0); + close (pipefd[0]); + close (pipefd[1]); + execl("/bin/sh", "/bin/sh", "-c", vars.output_to, NULL); + exit (1); + } else { + /* + * If the print plugin gets SIGKILLed by gimp, we kill lpr + * in turn. If the plugin signals us with SIGUSR1 that it's + * finished printing normally, we close our end of the pipe, + * and go away. + */ + close (pipefd[0]); + while (usr1_interrupt == 0) { + if (kill (ppid, SIGNULL) < 0) { + /* The print plugin has been killed! */ + kill (opid, SIGTERM); + waitpid (opid, &dummy, 0); + close (pipefd[1]); + exit (0); + } + sleep (5); + } + /* We got SIGUSR1. */ + close (pipefd[1]); + exit (0); + } + } else { + close (pipefd[0]); + /* Parent process. We generate the printer output. */ + prn = fdopen (pipefd[1], "w"); + /* and fall through... */ + } + } + } #else /* OS/2 PRINT command doesn't support print from stdin, use temp file */ prn = (tmpfile = get_tmp_filename ()) ? fopen (tmpfile, "w") : NULL; @@ -566,7 +637,11 @@ if (plist_current > 0) #ifndef __EMX__ - pclose (prn); + { + fclose (prn); + kill (cpid, SIGUSR1); + waitpid (cpid, &dummy, 0); + } #else { /* PRINT temp file */ char *s; ============================================================================== [The yellow colouring of the pictures I printed] > Did that seem specific to the camera? I haven't really tried enough image sources to be able to tell. I'll try some scanned photos sometime. > And thanks for all the work you (all) have already done on gimp-print! > I mentioned above that a friend (a newspaper photographer) had asked > for some images printed. He has a Photo 700 (and no ink at present) and > uses Windows (NT I think). After seeing the prints gimp-print produced, > he said he wanted a new printer. Congratulations! > > The driver is very well tuned for the 700 (I previously had an EX). Ben uses Windows and the Windows driver with his 700. The prints we did for him were from the 870 with gimp-print. What I meant to say (apparently unsuccessfully) was that (Photo 870 + gimp-print) makes better prints than (Photo 700 + Windows driver), which seems to be a good result, since the 700 is relatively recent. I also know first-hand that (Photo 870 with gimp-print) is considerably better than (Colour 3000 with Windows driver), which is also a good result, but probably not a surprising one. I'll append the patch for clipping the image to the page size that I mentioned in my previous email. In landscape mode, 3.1.4 with this patch seems to print images upside down... But as far as I can tell, vanilla 3.1.2 did the same thing. Cheers, -- Charles Briscoe-Smith <URL:http://www.debian.org/%7Ecpbs/> PGP2: 1024/B35EE811 74 68 AB 2E 1C 60 22 94 B8 21 2D 01 DE 66 13 E2 "You think that's air you're breathing now?" -- Morpheus, "The Matrix" ============================================================================== diff -ur orig/print-escp2.c ./print-escp2.c --- orig/print-escp2.c Sat May 13 02:07:03 2000 +++ ./print-escp2.c Sat May 13 02:11:16 2000 @@ -893,6 +893,10 @@ colormode_t colormode = COLOR_CCMMYK; int separation_rows = escp2_separation_rows(model); int use_glossy_film = 0; + int first_row = 0, /* First row used in image */ + num_rows, /* Number of rows used in image */ + clip_row_start = 0, /* First pixel used on each row */ + clip_row_length; /* No. of pixels used on each row */ if (!strcmp(media_type, "Glossy Film")) use_glossy_film = 1; @@ -1122,11 +1126,46 @@ left = page_width - x - out_width; } - if (left < 0) - left = (page_width - out_width) / 2; + first_row = 0; + clip_row_start = 0; - if (top < 0) - top = (page_height - out_height) / 2; + if (landscape) { + num_rows = image_width; + clip_row_length = image_height; + } else { + num_rows = image_height; + clip_row_length = image_width; + } + + if (left < 0) { + left = -left; + clip_row_start = left * clip_row_length / out_width; + clip_row_length -= clip_row_start; + out_width -= left; + left = 0; + } + + if (top < 0) { + top = -top; + first_row = top * num_rows / out_height; + num_rows -= first_row; + out_height -= top; + top = 0; + } + + { + int extra = left + out_width - page_width; + if (extra > 0) { + clip_row_length -= extra * clip_row_length / out_width; + out_width -= extra; + } + + extra = top + out_height - page_height; + if (extra > 0) { + num_rows -= extra * num_rows / out_height; + out_height -= extra; + } + } /* * Let the user know what we're doing... @@ -1210,10 +1249,7 @@ v->density = 1.0; v->saturation *= printer->printvars.saturation; - if (landscape) - dither = init_dither(image_height, out_width, v); - else - dither = init_dither(image_width, out_width, v); + dither = init_dither(clip_row_length, out_width, v); dither_set_black_levels(dither, 1.5, 1.5, 1.5); dither_set_black_lower(dither, .4); if (use_glossy_film) @@ -1255,16 +1291,17 @@ } dither_set_density(dither, v->density); + in = malloc(clip_row_length * image_bpp); + out = malloc(clip_row_length * out_bpp * 2); + + errdiv = num_rows / out_height; + errmod = num_rows % out_height; + errval = 0; + errlast = -1; + if (landscape) { - in = malloc(image_height * image_bpp); - out = malloc(image_height * out_bpp * 2); - - errdiv = image_width / out_height; - errmod = image_width % out_height; - errval = 0; - errlast = -1; - errline = image_width - 1; + errline = first_row + num_rows - 1; for (x = 0; x < out_height; x ++) { @@ -1274,10 +1311,10 @@ if (errline != errlast) { errlast = errline; - Image_get_col(image, in, errline); + Image_get_clipped_col(image, in, errline, clip_row_start, clip_row_length); } - (*colorfunc)(in, out, image_height, image_bpp, cmap, v); + (*colorfunc)(in, out, clip_row_length, image_bpp, cmap, v); if (v->image_type == IMAGE_MONOCHROME) dither_fastblack(out, x, dither, black); @@ -1303,21 +1340,10 @@ errline --; } } - if (use_softweave) - escp2_flush(weave, model, out_width, left, ydpi, xdpi, prn); - else - escp2_free_microweave(); } else { - in = malloc(image_width * image_bpp); - out = malloc(image_width * out_bpp * 2); - - errdiv = image_height / out_height; - errmod = image_height % out_height; - errval = 0; - errlast = -1; - errline = 0; + errline = first_row; for (y = 0; y < out_height; y ++) { @@ -1327,10 +1353,10 @@ if (errline != errlast) { errlast = errline; - Image_get_row(image, in, errline); + Image_get_clipped_row(image, in, errline, clip_row_start, clip_row_length); } - (*colorfunc)(in, out, image_width, image_bpp, cmap, v); + (*colorfunc)(in, out, clip_row_length, image_bpp, cmap, v); if (v->image_type == IMAGE_MONOCHROME) dither_fastblack(out, y, dither, black); @@ -1355,11 +1381,11 @@ errline ++; } } - if (use_softweave) - escp2_flush(weave, model, out_width, left, ydpi, xdpi, prn); - else - escp2_free_microweave(); } + if (use_softweave) + escp2_flush(weave, model, out_width, left, ydpi, xdpi, prn); + else + escp2_free_microweave(); free_dither(dither); /* diff -ur orig/print.c ./print.c --- orig/print.c Sat May 13 02:07:03 2000 +++ ./print.c Sat May 13 02:06:41 2000 @@ -1205,6 +1205,22 @@ } void +Image_get_clipped_col(Image image, unsigned char *data, int column, + int start, int length) +{ + Gimp_Image_t *gimage = (Gimp_Image_t *) image; + gimp_pixel_rgn_get_col(&(gimage->rgn), data, column, start, length); +} + +void +Image_get_clipped_row(Image image, unsigned char *data, int row, + int start, int length) +{ + Gimp_Image_t *gimage = (Gimp_Image_t *) image; + gimp_pixel_rgn_get_row(&(gimage->rgn), data, start, row, length); +} + +void Image_progress_init(Image image) { image = image; diff -ur orig/print.h ./print.h --- orig/print.h Sat May 13 02:07:03 2000 +++ ./print.h Sat May 13 02:07:34 2000 @@ -152,6 +152,10 @@ extern const char *Image_get_pluginname(Image image); extern void Image_get_col(Image image, unsigned char *data, int column); extern void Image_get_row(Image image, unsigned char *data, int row); +extern void Image_get_clipped_col(Image image, unsigned char *data, + int column, int start, int length); +extern void Image_get_clipped_row(Image image, unsigned char *data, + int row, int start, int length); extern void Image_progress_init(Image image); extern void Image_note_progress(Image image, double current, double total); ============================================================================== |