When a VIPS function is asked to output to a "p"
image descriptor,
all the fields in the descriptor are set (the output image size and type
are set, for example), but no image data is actually generated. Instead,
the function attaches callbacks to the image descriptor which VIPS can use
later to generate any piece of the output image that might be needed.
When a VIPS function is asked to output to a "w"
or a "t"
descriptor (a real disc file or a real memory buffer), it evaluates
immediately, and its evaluation in turn forces the evaluation of any earlier
"p"
images.
In the example in figure 3.5, whether or not any pixels are really
processed when im_Lab2disp()
is called depends upon the mode in
which out
was opened. If out
is also a partial image, then
no pixels will be calculated -- instead, a pipeline of VIPS operations
will be constructed behind the scenes and attached to out
.
Conversely, if out
is a real image (that is, either "w"
or "t"
), then the final VIPS operation in the function
(im_XYZ2disp()
) will output the entire image to out
, causing
the earlier parts of im_Lab2disp()
(and indeed possibly some earlier
pieces of program, if in
was also a "p"
image) to run.
When a VIPS pipeline does finally evaluate, all of the functions in the pipeline execute together, sucking image data through the system in small pieces. As a consequence, no intermediate images are generated, large amounts of RAM are not needed, and no slow disc I/O needs to be performed.
Since VIPS partial I/O is demand-driven rather than data-driven, this works
even if some of the operations perform coordinate transformations. We could,
for example, include a call to im_affine()
, which performs
arbitrary rotation and scaling, and everything would still work correctly.