summaryrefslogtreecommitdiff
path: root/doc/manual-html/gimpprint_25.html
diff options
context:
space:
mode:
Diffstat (limited to 'doc/manual-html/gimpprint_25.html')
-rw-r--r--doc/manual-html/gimpprint_25.html611
1 files changed, 611 insertions, 0 deletions
diff --git a/doc/manual-html/gimpprint_25.html b/doc/manual-html/gimpprint_25.html
new file mode 100644
index 0000000..bbccb97
--- /dev/null
+++ b/doc/manual-html/gimpprint_25.html
@@ -0,0 +1,611 @@
+<HTML>
+<HEAD>
+<!-- This HTML file has been created by texi2html 1.51
+ from .././gimpprint.texi on 11 June 2004 -->
+
+<TITLE>GIMP-Print - Dithering</TITLE>
+</HEAD>
+<BODY>
+Go to the <A HREF="gimpprint_1.html">first</A>, <A HREF="gimpprint_24.html">previous</A>, <A HREF="gimpprint_26.html">next</A>, <A HREF="gimpprint_47.html">last</A> section, <A HREF="gimpprint_toc.html">table of contents</A>.
+<P><HR><P>
+
+
+<H1><A NAME="SEC40" HREF="gimpprint_toc.html#TOC40">A Dithering</A></H1>
+<P>
+<A NAME="IDX182"></A>
+
+</P>
+<P>
+The dithering code in <TT>`print-dither.c'</TT> attempts to reproduce
+various shades of gray (or all colors) from only a few different inks
+(black, cyan, magenta, yellow, and sometimes light cyan and light
+magenta). The dots can't vary in darkness or size (except for certain
+special printers), and so we need to lay down a certain fraction of dots
+to represent each distinct level.
+
+</P>
+<P>
+This sounds straightforward; in practice, it isn't. Completely random
+distribution of dots (simple probabilistic dithering) would create
+grainy clumps and light spots. The smoothest pattern results from an
+equidistant spacing of dots. Approximating this requires sophisticated
+algorithms. We have two dithering algorithms, an ordered dither
+algorithm that uses a grid (matrix) to decide whether to print, and a
+modified Floyd-Steinberg error diffusion algorithm that uses a grid in a
+slightly different way.
+
+</P>
+
+<P>
+We currently have three dithering functions:
+
+</P>
+
+<OL>
+<LI>
+
+<CODE>dither_fastblack</CODE> produces pure black or white from a pre-dithered
+input. This is used for two purposes: for printing pure black and white
+very quickly (e. g. text), and for printing pre-screened monochrome
+output that was rasterized externally.
+
+<LI>
+
+<CODE>dither_black</CODE> produces black from grayscale input. The new
+dither_black can produce either a single or multiple levels of black,
+for printers supporting variable dot size.
+
+<LI>
+
+<CODE>dither_cmyk</CODE> produces 3, 4, 5, 6, or 7 color output (CMY, CMYK,
+CcMmYK, CcMmYy, CcMmYyK, or any variants). The new routine can handle
+single or multiple levels of each color.
+</OL>
+
+<P>
+There is a choice of dithering algorithms. Four of them are based on a
+basic error diffusion, with a few tweaks of my own. The other one is
+`ordered'. However, they all share the basic operation in common.
+First, the algorithm picks what kind of dot (if there are multiple dot
+sizes and/or tones that may be picked) is the candidate to be printed.
+This decision is made based on the darkness at the point being dithered.
+Then, it decides whether the dot will be printed at all. What this is
+based on depends upon which algorithm family we use. This is all
+described in more detail below.
+
+</P>
+
+<P>
+Ordered dithering works by comparing the value at a given point with the
+value of a tiled matrix. If the value at the point is greater than the
+value in the matrix, the dot is printed. The matrix should consist of a
+set of evenly spaced points between 0 and the upper limit. The choice
+of matrix is very important for print quality. A good dither matrix
+will emphasize high frequency components, which distributes dots evenly
+with a minimum of clumping. The matrices used here are all simple
+matrices that are expanded recursively to create larger matrices with
+the same kind of even point distribution. This is described below.
+
+</P>
+<P>
+Note that it is important to use different matrices for the two
+sub-operations, because otherwise the choice about whether to print and
+the choice of dot size will be correlated. The usual result is that the
+print is either too dark or too light, but there can be other problems.
+
+</P>
+<P>
+Ordered dithering works quite well on single dot size, four color
+printers. It has not been well tested on four color, variable dot size
+printers. It should be avoided on six color printers.
+
+</P>
+
+<P>
+Error diffusion works by taking the output error at a given pixel and
+"diffusing" it into surrounding pixels. Output error is the
+difference between the amount of ink output and the input level at each
+pixel. For simple printers, with one or four ink colors and only one
+dot size, the amount of ink output is either 65536 (i. e. full output)
+or 0 (no output). The difference between this and the input level is
+the error. Normal error diffusion adds part of this error to the
+adjoining pixels in the next column and the next row (the algorithm
+simply scans each row in turn, never backing up). The error adds up
+until it reaches a threshold (half of the full output level, or 32768),
+at which point a dot is output, the output is subtracted from the
+current value, and the (now negative) error is diffused similarly.
+
+</P>
+<P>
+Error diffusion works quite well in general, but it tends to generate
+artifacts which usually appear as worm-like lines or areas of anomalous
+density. I have devised some ways, as described below, of ameliorating
+these artifacts.
+
+</P>
+<P>
+There are two sub-classes of error diffusion that we use here, `random'
+and `hybrid'. One of the techniques that we use to ameliorate the
+artifacts is to use a fuzzy threshold rather than the hard threshold of
+half of the output level. Random error diffusion uses a pseudo-random
+number to perturb the threshold, while hybrid error diffusion uses a
+matrix. Hybrid error diffusion worked very poorly in 3.1.3, and I
+couldn't figure out why until I found a bug. It now works very well.
+
+</P>
+<P>
+There is one additional variant (on both sub-classes), called `adaptive
+hybrid' and `adaptive random'. The adaptive variant takes advantage of
+the fact that the patterns that ordered dithering create are less
+visible at very low densities, while the artifacts created by error
+diffusion are more objectionable at low densities. At low densities,
+therefore, it uses ordered dithering; at higher densities it uses error
+diffusion.
+
+</P>
+
+<P>
+Handling multiple output levels makes life a bit more complicated. In
+principle, it shouldn't be much harder: simply figure out what the ratio
+between the available output levels is and have multiple thresholds. In
+practice, getting these right involves a lot of trial and error. The
+other thing that's important is to maximize the number of dots that have
+some ink. This will reduce the amount of speckling. More on this
+later.
+
+</P>
+<P>
+The next question: how do we handle black when printing in color? Black
+ink is much darker than colored inks. It's possible to produce black by
+adding some mixture of cyan, magenta, and yellow--in principle. In
+practice, the black really isn't very black, and different inks and
+different papers will produce different color casts. However, by using
+CMY to produce gray, we can output a lot more dots! This makes for a much
+smoother image. What's more, one cyan, one magenta, and one yellow dot
+produce less darkness than one black dot, so we're outputting that many
+more dots. Better yet, with 6 or 7 color printers, we have to output even
+more light ink dots. So Epson Stylus Photo printers can produce really
+smooth grays--if we do everything right. The right idea is to use
+CMY at lower black levels, and gradually mix in black as the overall
+amount of ink increases, so the black dots don't really become visible
+within the ink mass.
+
+</P>
+<P>
+Variable dot sizes are handled by dividing the range between 0 and
+65536 into segments. Each segment can either represent a range in
+which all of one kind of ink (color and/or dot size) is used, with
+varying amounts of ink, or a transition region between inks, in which
+equal numbers of dots are printed but the amount of each ink will be
+adjusted throughout the range. Each range is represented by four
+numbers:
+
+</P>
+
+<OL>
+<LI>
+
+bottom of the range
+<LI>
+
+top of the range
+<LI>
+
+value of the lighter ink
+<LI>
+
+value of the darker ink
+</OL>
+
+<P>
+In addition, the bit patterns and which type of ink are also
+represented, but they don't affect the actual algorithm.
+
+</P>
+
+<P>
+As mentioned above, the basic algorithm is the same whether we use
+ordered dither or error diffusion. We perform the following steps on
+each color of each pixel:
+
+</P>
+
+<OL>
+<LI>
+
+Compute the value of the particular color we're printing. This isn't
+usually the pure CMY value; it's adjusted to improve saturation and to
+limit the use of black in light toned regions (to avoid speckling).
+
+<LI>
+
+Find the range containing this value.
+
+<LI>
+
+Compute where this value lies within the range. We scale the endpoints
+between 0 and 65536 for this purpose. So for example, if the bottom of
+the range is 10,000 and the top of the range is 20,000, and the value is
+12,500, we're 1/4 of the way between the bottom and the top of the
+range, so our scale point is 16384.
+
+<LI>
+
+Compute the "virtual value". The virtual value is the distance between
+the value of the lighter and the value of the darker ink. So if the
+value of the light ink is 32768 and the dark ink is 65536, we compute a
+virtual value scaled appropriately between these two values, which is
+40960 in this case.
+
+<LI>
+
+Using either error diffusion or ordered dither, the standard threshold
+is 1/2 of the value (20480 in this case). Using ordered dither, we want
+to compute a value between 0 and 40960 that we will compare the input
+value against to decide whether to print. Using pure error diffusion,
+we would compare the accumulated error against 20480 to decide whether
+to print. In practice, we use the same matrix method to decide whether
+to print. The correct amount of ink will be printed this way, but we
+minimize the squiggly lines characteristic of error diffusion by
+dithering the threshold in this fashion. A future enhancement will
+allow us to control the amount of dithering applied to the threshold.
+</OL>
+
+<P>
+The matrices were generated by Thomas Tonino
+@email{&#60;ttonino@bio.vu.nl&#62;} with an algorithm of his devising. The
+algorithm is designed to maximize the spacing between dots at any given
+density by searching the matrix for holes and placing a dot in the
+largest available hole. It requires careful selection of initial points
+to achieve good results, and is very time consuming. For best results,
+a different matrix must be used for modes with 2:1 aspect ratio
+(e.g. 1440x720) than for 1:1 (e. g. 720x720). It is essential with any
+of these matrices that every point be used. Skipping points generates
+low-frequency noise.
+
+</P>
+<P>
+It's essential to use different matrices for deciding whether to print
+and for deciding what color (dark or light) to print. This should be
+obvious; the decision about whether to print at all should be as
+independent as possible from the decision about what color to print,
+because any bias will result in excess light or dark ink being
+printed, shifting the tonal balance. We actually use the same
+matrices, but we shift them vertically and horizontally. Assuming
+that the matrices are not self-correlated, this will yield good
+results.
+
+</P>
+<P>
+The ranges are computed from a list of ink values (between 0 and 1 for
+each possible combination of dot size and ink tone, where the value
+represents the darkness of the ink) and the desired maximum density of
+the ink. This is done in dither_set_ranges, and needs more
+documentation.
+
+</P>
+
+<P>
+I stated earlier that I've tweaked the basic error diffusion algorithm.
+Here's what I've done to improve it:
+
+</P>
+
+<OL>
+<LI>
+
+We use a variable threshold to decide when to print, as discussed above.
+This does two things for us: it reduces the slightly squiggly diagonal
+lines that are the mark of error diffusion; and it allows us to lay down
+some ink even in very light areas near the edge of the image. The
+squiggly lines that error diffusion algorithms tend to generate are
+caused by the gradual accumulation of error. This error is partially
+added horizontally and partially vertically. The horizontal
+accumulation results in a dot eventually being printed. The vertical
+accumulation results in a dot getting laid down in roughly the same
+horizontal position in the next row. The diagonal squigglies result
+from the error being added to pixels one forward and one below the
+current pixel; these lines slope from the top right to the bottom left
+of the image.
+
+Error diffusion also results in pale areas being completely white near
+the top left of the image (the origin of the printing coordinates).
+This is because enough error has to accumulate for anything at all to
+get printed. In very pale areas it takes quite a long time to build up
+anything printable at all; this results in the bare spots.
+
+Randomizing the threshold somewhat breaks up the diagonals to some
+degree by randomizing the exact location that the accumulated output
+crosses the threshold. It reduces the false white areas by allowing
+some dots to be printed even when the accumulated output level is very
+low. It doesn't result in excess ink because the full output level is
+still subtracted and diffused.
+
+Excessive randomization leads to blobs at high densities. Therefore, as
+the density increases, the degree of randomization decreases.
+
+<LI>
+
+Alternating scan direction between rows (first row is scanned left to
+right, second is scanned right to left, and so on). This also helps
+break up white areas, and it also seems to break up squigglies a bit.
+Furthermore, it eliminates directional biases in the horizontal
+direction. This isn't necessary for ordered dither, but it doesn't hurt
+either.
+
+<LI>
+
+Diffusing the error into more pixels. Instead of diffusing the entire
+error into @math{(X+1, Y)} and @math{(X, Y+1)}, we diffuse it into
+@math{(X+1, Y)}, @math{(X+K, Y+1)}, @math{(X, Y+1)}, @math{(X-K, Y+1)}
+where @math{K} depends upon the output level (it never exceeds about 10
+dots, and is greater at higher output levels). This really reduces
+squigglies and graininess. The amount of this spread can be controlled;
+for line art, it should be less than for photographs (of course, line
+art doesn't usually contain much light color, but the <STRONG>error</STRONG>
+value can be small in places!) In addition to requiring more
+computation, a wide ink spread results in patterning at high dot
+densities (note that the dot density can be high even in fairly pale
+regions if multiple dot sizes are in use).
+
+<LI>
+
+Don't lay down any colored ink if we're laying down black ink. There's
+no point; the colored ink won't show. We still pretend that we did for
+purposes of error diffusion (otherwise excessive error will build up,
+and will take a long time to clear, resulting in heavy bleeding of ink
+into surrounding areas, which is very ugly indeed), but we don't bother
+wasting the ink. How well this will do with variable dot size remains
+to be seen.
+
+<LI>
+
+Oversampling. This is how to print 1440x720 with Epson Stylus printers.
+Printing full density at 1440x720 will result in excess ink being laid
+down. The trick is to print only every other dot. We still compute the
+error as though we printed every dot. It turns out that randomizing
+which dots are printed results in very speckled output. This can be
+taken too far; oversampling at 1440x1440 or 1440x2880 virtual resolution
+results in other problems. However, at present 1440x1440 (which is more
+accurately called "1440x720 enhanced", as the Epson printers cannot
+print 1440 rows per inch) does quite well, although it's slow.
+</OL>
+
+<P>
+What about multiple output levels? For 6 and 7 color printers, simply
+using different threshold levels has a problem: the pale inks have trouble
+being seen when a lot of darker ink is being printed. So rather than
+just using the output level of the particular color to decide which ink
+to print, we look at the total density (sum of all output levels).
+If the density's high enough, we prefer to use the dark ink. Speckling
+is less visible when there's a lot of ink, anyway. I haven't yet figured
+out what to do for multiple levels of one color.
+
+</P>
+<P>
+You'll note that I haven't quoted a single source on color or printing
+theory. I simply did all of this empirically.
+
+</P>
+<P>
+There are various other tricks to reduce speckling. One that I've seen
+is to reduce the amount of ink printed in regions where one color
+(particularly cyan, which is perceived as the darkest) is very pale.
+This does reduce speckling all right, but it also results in strange
+tonal curves and weird (to my eye) colors.
+
+</P>
+
+<P>
+Before any dither routine is used, <CODE>init_dither()</CODE> must be called.
+This takes three arguments: the input width (number of pixels in the
+input), the output width (number of pixels in the output), and a
+<CODE>vars_t</CODE> structure containing the parameters for the print job.
+
+</P>
+<P>
+<CODE>init_dither()</CODE> returns a pointer to an opaque object representing
+the dither. This object is passed as the first argument to all of the
+dither-related routines.
+
+</P>
+<P>
+After a page is fully dithered, <CODE>free_dither()</CODE> must be called to
+free the dither object and perform any cleanup. In the future, this may
+do more (such as flush output). This arrangement permits using these
+routines with programs that create multiple output pages, such as
+GhostScript.
+
+</P>
+<P>
+The dithering routines themselves have a number of control knobs that
+control internal aspects of the dithering process. These knobs are
+accessible via a number of functions that can be called after
+<CODE>init_dither()</CODE>.
+
+</P>
+
+<UL>
+<LI>
+
+<CODE>dither_set_density()</CODE> takes a double between 0 and 1 representing
+the desired ink density for printing solid colors. This is used in a
+number of places in the dithering routine to make decisions.
+
+<LI>
+
+<CODE>dither_set_black_density()</CODE> takes a double between 0 and 1
+representing the desired ink density for printing black ink in color
+printing. This is used to balance black against color ink. By default,
+this is equal to the density set by <CODE>dither_set_density()</CODE>. By
+setting it higher, more black ink will be printed. For example, if the
+base density is .4 and the black density is .8, twice as much black ink
+will be printed as would otherwise be called for.
+
+This is not used when printing in monochrome. When printing monochrome,
+the base density (<CODE>dither_set_density</CODE>) should be adjusted
+appropriately.
+
+<LI>
+
+<CODE>dither_set_ink_budget()</CODE> takes an unsigned number representing the
+most ink that may be deposited at a given point. This number is
+arbitrary; the limit is computed by summing the size of each ink dot,
+which is supplied as a parameter in <CODE>dither_set_<VAR>X</VAR>_ranges</CODE>.
+By default, there is no limit.
+
+<LI>
+
+<CODE>dither_set_black_lower()</CODE> takes a double that should be between 0
+and 1 that represents the lowest density level at which black ink will
+start to mix in with colored ink to generate grays. The lower this is,
+the less density is required to use black ink. Setting this too low
+will result in speckling from black dots, particularly on 6 and 7 color
+printers. Setting this too high will make it hard to get satisfactory
+black or may result in sharp transition between blended colors and
+black. Default: 0.0468.
+
+It is important to note that since the density scale is never linear
+(and since this value is adjusted via other things happening during the
+dithering process) that this does not mean that 95% gray will use any
+black ink. At this setting, there will be no black ink used until about
+50% gray.
+
+This only applies to color mode.
+
+This value should be set lower for printers capable of variable dot
+size, since more dots can be laid down close to each other.
+
+<LI>
+
+<CODE>dither_set_black_upper()</CODE> takes a double that should be between 0
+and 1 that represents the highest density level at which colored inks
+will be mixed to create gray. Setting this too low will result in
+speckly dark grays because there is not enough ink to fill all the
+holes, or sharp transition between blended colors and black if it is too
+close to the value of dither_set_black_upper(). Setting this too high
+will result in poor black and dark tone quality. Default: 0.5. This
+results in 10% and darker grays being printed with essentially all
+black.
+
+This only applies to color mode.
+
+<LI>
+
+<CODE>dither_set_black_levels()</CODE> takes three doubles that represent the
+amount of cyan, magenta, and yellow respectively that are blended to
+create gray. The defaults are 1.0 for each, which is probably too low
+for most printers. These values are adjusted to create a good gray
+balance. Setting these too low will result in pale light and midtone
+grays, with a sharp transition to darker tones as black mixes in.
+Setting them too high will result in overly dark grays and use of too
+much ink, possibly creating bleed-through.
+
+This only applies to color mode.
+
+<LI>
+
+<CODE>dither_set_randomizers()</CODE> takes four integer values representing
+the degree of randomness used for cyan, magenta, yellow, and black.
+This is used to allow some printing to take place in pale areas. Zero
+is the most random; greater than 8 or so gives very little randomness at
+all. Defaults are 0 for cyan, magenta, and yellow, and 4 for black.
+Setting the value for black too low will result in black speckling in
+pale areas. Setting values too high will result in pale areas getting
+no ink at all.
+
+This currently only applies to single dot size in color and black. It
+should be extended to operate in variable dot size mode, although
+actually applying it correctly will be tricky.
+
+<LI>
+
+<CODE>dither_set_ink_darkness()</CODE> takes three doubles representing the
+contribution to perceived darkness of cyan, magenta, and yellow. This
+is used to help decide when to switch between light and dark inks in 6
+and 7 color printers (with light cyan, light magenta, and possibly light
+yellow). Setting these too low will result in too much light ink being
+laid down, creating flat spots in the darkness curves and bleed-through.
+Setting them too high will result in dark ink being used in pale areas,
+creating speckle. The defaults are .4 for cyan, .3 for magenta, and .2
+for yellow. Dark cyan will show against yellow much more than dark
+magenta will show against cyan, since the cyan appears much darker than
+the yellow.
+
+<LI>
+
+<CODE>dither_set_light_inks()</CODE> takes three doubles between 0 and 1
+representing the ratio in darkness between the light and dark versions
+of the inks. Setting these too low will result in too much dark ink
+being used in pale areas, creating speckling, while setting them too
+high will result in very smooth texture but too much use of light ink,
+resulting in flat spots in the density curves and ink bleed-through.
+There are no defaults. Any light ink specified as zero indicates that
+there is no light ink for that color.
+
+This only applies to 6 and 7 color printers in single dot size color
+mode, and only to those inks which have light versions (usually cyan and
+magenta).
+
+<LI>
+
+<CODE>dither_set_ink_spread()</CODE> takes a small integer representing the
+amount of ink spread in the dither. Larger numbers mean less spread.
+Larger values are appropriate for line art and solid tones; they will
+yield sharper transitions but more dither artifacts. Smaller values are
+more appropriate for photos. They will reduce resolution and sharpness
+but reduce dither artifacts up to a point. A value of 16 or higher
+implies minimum ink spread at any resolution no matter what the
+overdensity. A value of 14 is typical for photos on single dot size, 6
+color printers. For 4 color printers, subtract 1 (more spread; the dots
+are farther apart). For variable dot size printers, add 1 (more small
+dots are printed; less spread is desirable).
+
+<LI>
+
+<CODE>dither_set_adaptive_divisor()</CODE> takes a float representing the
+transition point between error diffusion and ordered dither if adaptive
+dithering is used. The float is a fraction of the printing density.
+For example, if you wish the transition to be at 1/4 of the maximum
+density (which works well on simple 4-color printers), you would pass
+.25 here. With six colors and/or with multiple dot sizes, the values
+should be set lower.
+
+<LI>
+
+<CODE>dither_set_transition()</CODE> takes a float representing the exponent
+of the transition curve between light and dark inks/dot sizes. A value
+less than 1 (typical when using error diffusion) mixes in less dark
+ink/small dots at lower ends of the range, to reduce speckling. When
+using ordered dithering, this must be set to 1.
+
+<LI>
+
+<CODE>dither_set_<VAR>X</VAR>_ranges_simple</CODE> (<VAR>X</VAR>=<SAMP>`c'</SAMP>, <SAMP>`m'</SAMP>,
+<SAMP>`y'</SAMP>, or <SAMP>`k'</SAMP>) describes the ink choices available for each
+color. This is useful in typical cases where a four color printer with
+variable dot sizes is in use. It is passed an array of doubles between
+(0, 1] representing the relative darkness of each dot size. The dot
+sizes are assigned bit patterns (and ink quantities, see
+<CODE>dither_set_ink_budget()</CODE> above) from 1 to the number of levels.
+This also requires a density, which is the desired density for this
+color. This density need not equal the density specified in
+<CODE>dither_set_density()</CODE>. Setting it lower will tend to print more
+dark ink (because the curves are calculated for this color assuming a
+lower density than is actually supplied).
+
+<LI>
+
+<CODE>dither_set_<VAR>X</VAR>_ranges</CODE> (<VAR>X</VAR>=<SAMP>`c'</SAMP>, <SAMP>`m'</SAMP>, <SAMP>`y'</SAMP>,
+or <SAMP>`k'</SAMP>) describes in a more general way the ink choices available
+for each color. For each possible ink choice, a bit pattern, dot size,
+value (i. e. relative darkness), and whether the ink is the dark or
+light variant ink is specified.
+</UL>
+
+<P>
+---Robert Krawitz @email{&#60;rlk@alum.mit.edu&#62;} May 8, 2000
+<P><HR><P>
+Go to the <A HREF="gimpprint_1.html">first</A>, <A HREF="gimpprint_24.html">previous</A>, <A HREF="gimpprint_26.html">next</A>, <A HREF="gimpprint_47.html">last</A> section, <A HREF="gimpprint_toc.html">table of contents</A>.
+</BODY>
+</HTML>