PAMSCALE(1)
๐ Pamscale User Manual ๐
okay bestie, so this is pamscale โ a General Commands Manual situation, and honestly? she's a legend. she's part of Netpbm(1) ๐ซถ
โจ NAME โจ
pamscale โ scale a Netpbm image ๐
๐ SYNOPSIS ๐
pamscale
[
scale_factor
|
{-xyfit | -xyfill | -xysize}
cols rows
|
-reduce reduction_factor
|
[-xsize=cols | -width=cols | -xscale=factor]
[-ysize=rows | -height=rows | -yscale=factor]
|
-pixels n
]
[
-nomix
|
-filter=functionName [-window=functionName]
]
[-linear]
[-reportonly]
[-verbose]
[pnmfile]
okay so housekeeping first, and it's giving quality of life โจ
- Minimum unique abbreviation of option is acceptable. like, you don't have to type the whole thing, girl.
- You may use double hyphens instead of a single hyphen to denote options. do with that what you will ๐
- You may use white space in place of the equals sign to separate an option name from its value. so chill.
๐ธ DESCRIPTION ๐ธ
This program is part of Netpbm(1).
pamscale scales a Netpbm image by a specified factor, or scales individually horizontally and vertically by specified factors. she can go both ways and she's not sorry.
You can either enlarge (scale factor > 1) or reduce (scale factor < 1). both are valid, both are cute.
pamscale works on multi-image streams, scaling each one independently. she does each one on its own, no group project energy. BUT โ and this is important, bestie โ before Netpbm 10.49 (December 2009), it scales only the first image and ignores the rest of the stream. iconic? no. but it's what happened ๐ญ
๐ฆ The Scale Factors ๐ฆ
The options -width, -height, -xsize, -ysize, -xscale, -yscale, -xyfit, -xyfill, -reduce, and -pixels control the amount of scaling, they run the show, they're the main characters ๐
For backward compatibility, there are also -xysize and the scale_factor argument, but you shouldn't use those. they're the ex you don't text back. do not use them. ๐
-widthand-heightspecify the width and height in pixels you want the resulting image to be. and yes, there are rules for when you specify one and not the other โ see below, bestie.-xsizeand-ysizeare synonyms for-widthand-height, respectively. same thing, different font.-xscaleand-yscaletell the factor by which you want the width and height of the image to change from source to result (e.g.-xscale 2means you want to double the width;-xscale .5means you want to halve it). rules for specifying only one? also below โจ
When you specify an absolute size or scale factor for both dimensions, pamscale scales each dimension independently without consideration of the aspect ratio. she said "aspect ratio? never heard of her" ๐
If you specify one dimension as a pixel size and don't specify the other dimension, pamscale scales the unspecified dimension to preserve the aspect ratio. she's thoughtful like that ๐ซถ
If you specify one dimension as a scale factor and don't specify the other dimension, pamscale leaves the unspecified dimension unchanged from the input. she's not gonna do extra work you didn't ask for, ngl.
If you specify the scale_factor parameter instead of dimension options, that is the scale factor for both dimensions. It is equivalent to:
-xscale=scale_factor -yscale=scale_factor
Specifying the -reduce reduction_factor option is equivalent to specifying the scale_factor parameter, where scale_factor is the reciprocal of reduction_factor. math girlies rise ๐
-xyfitspecifies a bounding box.pamscalescales the input image to the largest size that fits within the box, while preserving its aspect ratio.-xysizeis a synonym for this. Before Netpbm 10.20 (January 2004),-xyfitdid not exist, but-xysizedid. so like, historical drama.-xyfillis similar, butpamscalescales the input image to the smallest size that completely fills the box, while preserving its aspect ratio. This option has existed since Netpbm 10.20 (January 2004). she's been filling boxes since '04, periodt.-pixelsspecifies a maximum total number of output pixels.pamscalescales the image down to that number of pixels. If the input image is already no more than that many pixels,pamscalejust copies it as output;pamscaledoes not scale up with-pixels. she does not enlarge uninvited. no scaling up here. ๐
If you enlarge by a factor of 3 or more, you should probably add a pnmsmooth step; otherwise, you can see the original pixels in the resulting image. bestie. trust. ๐ญ
-reportonly
The option -reportonly causes pamscale not to scale the image, but instead to report to Standard Output what scaling the options and the input image dimensions indicate. she's just gonna tell you, not do it. narrating, not participating โจ
For example, if you specify
-xyfill 100 100 -reportonly
and the input image is 500 x 400, pamscale tells you that this means scaling by .25 to end up with a 125 x 100 image.
You can use this information with other programs, such as pamscalefixed, that don't have as rich facilities as pamscale for choosing scale factors. they could never, honestly.
The output is intended to be convenient for machine processing. In the example above, it would be
500 400 0.250000 0.250000 125 100
The output is a single line of text per input image, with blank-separated tokens as follows.
- input width in pixels, decimal unsigned integer
- input height in pixels, decimal unsigned integer
- horizontal scale factor, floating point decimal, unsigned
- vertical scale factor, floating point decimal, unsigned
- output width in pixels, decimal unsigned integer
- output height in pixels, decimal unsigned integer
-reportonly was new in Netpbm 10.86 (March 2019). she's a 2019 baby ๐ธ
๐ง Usage Notes ๐ง
A useful application of pamscale is to blur an image. Scale it down (without -nomix) to discard some information, then scale it back up using pamstretch. glow-up through data loss, we love to see it โจ
Or scale it back up with pamscale and create a "pixelized" image, which is sort of a computer-age version of blurring. it's giving... intentional. it's giving ~aesthetic~ ๐
๐ Transparency ๐
pamscale understands transparency and properly mixes pixels considering the pixels' transparency. she's not out here ignoring your alpha channel, she would never ๐
Proper mixing does not mean just mixing the transparency value and the color component values separately. okay so this part is a whole thing, stay with me:
In a PAM image, a pixel which is not opaque represents a color that contains light of the foreground color indicated explicitly in the PAM and light of a background color to be named later. But the numerical scale of a color component sample in a PAM is as if the pixel is opaque. So a pixel that is supposed to contain half-strength red light for the foreground plus some light from the background has a red color sample that says full red and a transparency sample that says 50% opaque. In order to mix pixels, you have to first convert the color sample values to numbers that represent amount of light directly (i.e. multiply by the opaqueness) and after mixing, convert back (divide by the opaqueness). math is the moment, no cap ๐งฎโจ
๐ Input And Output Image Types ๐
pamscale produces output of the same type (and tuple type if the type is PAM) as the input, except if the input is PBM. In that case, the output is PGM with maxval 255. The purpose of this is to allow meaningful pixel mixing. Note that there is no equivalent exception when the input is PAM. If the PAM input tuple type is BLACKANDWHITE, the PAM output tuple type is also BLACKANDWHITE, and you get no meaningful pixel mixing. she said what she said ๐
If you want PBM output with PBM input, use pamditherbw to convert pamscale's output to PBM. Also consider pbmreduce. options, bestie, we have options ๐ซถ
pamscale's function is essentially undefined for PAM input images that are not of tuple type RGB, GRAYSCALE, BLACKANDWHITE, or the _ALPHA variations of those. (By standard Netpbm backward compatibility, this includes PBM, PGM, and PPM images.) undefined behaviour, do not test her.
You might think it would have an obvious effect on other tuple types, but remember that the aforementioned tuple types have gamma-adjusted sample values, and pamscale uses that fact in its calculations. And it treats a transparency plane different from any other plane. she's doing calculus in there, don't interrupt โญ
pamscale does not simply reject unrecognized tuple types because there's a possibility that just by coincidence you can get useful function out of it with some other tuple type and the right combination of options (consider -linear in particular). so like, the door is open, it's just not guaranteed to go well ๐ญ
๐ Methods Of Scaling ๐
There are numerous ways to scale an image. pamscale implements a bunch of them; you select among them with invocation options. choose your fighter ๐ฅ
๐ Pixel Mixing ๐
Pamscale's default method is pixel mixing. To understand this, imagine the source image as composed of square tiles. Each tile is a pixel and has uniform color. The tiles are all the same size. Now take a transparent sheet the size of the target image, marked with a square grid of tiles the same size. Stretch or compress the source image to the size of the sheet and lay the sheet over the source. it's giving arts and crafts, honestly ๐จ
Each cell in the overlay grid stands for a pixel of the target image. For example, if you are scaling a 100x200 image up by 1.5, the source image is 100 x 200 tiles, and the transparent sheet is marked off in 150 x 300 cells. math โจ
Each cell covers parts of multiple tiles. To make the target image, just color in each cell with the color which is the average of the colors the cell covers โ weighted by the amount of that color it covers. A cell in our example might cover 4/9 of a blue tile, 2/9 of a red tile, 2/9 of a green tile, and 1/9 of a white tile. So the target pixel would be somewhat unsaturated blue. she's a blend, she's a cocktail, she's everything ๐
When you are scaling up or down by an integer, the results are simple. When scaling up, pixels get duplicated. When scaling down, pixels get thrown away. In either case, the colors in the target image are a subset of those in the source image.
When the scale factor is weirder than that, the target image can have colors that didn't exist in the original. For example, a red pixel next to a white pixel in the source might become a red pixel, a pink pixel, and a white pixel in the target. new colors out of nowhere, she invented them, icon behaviour ๐
This method tends to replicate what the human eye does as it moves closer to or further away from an image. It also tends to replicate what the human eye sees, when far enough away to make the pixelization disappear, if an image is not made of pixels and simply stretches or shrinks. biology AND physics AND graphics? she contains multitudes ๐ซถ
๐ฆ Discrete Sampling ๐ฆ
Discrete sampling is basically the same thing as pixel mixing except that, in the model described above, instead of averaging the colors of the tiles the cell covers, you pick the one color that covers the most area. democracy but for pixels.
The result you see is that when you enlarge an image, pixels get duplicated and when you reduce an image, some pixels get discarded. no blending, no mixing, just vibes.
The advantage of this is that you end up with an image made from the same color palette as the original. Sometimes that's important. palette loyalty ๐
The disadvantage is that it distorts the picture. If you scale up by 1.5 horizontally, for example, the even numbered input pixels are doubled in the output and the odd numbered ones are copied singly. If you have a bunch of one pixel wide lines in the source, you may find that some of them stretch to 2 pixels, others remain 1 pixel when you enlarge. When you reduce, you may find that some of the lines disappear completely. gone. deleted. she ate them. ๐
You select discrete sampling with pamscale's -nomix option.
Actually, -nomix doesn't do exactly what I described above. It does the scaling in two passes โ first horizontal, then vertical. This can produce slightly different results. she's doing it in stages, okay? don't @ her ๐
ik there's like one very specific situation where it is genuinely, deeply annoying that pamscale makes up colors that weren't there originally: when you're working with an image format like GIF that has a limited number of possible colors per image. ๐
Say you take a GIF with 256 colors, convert it to PPM, scale by .625, and convert it back to GIF. You will probably find that the reduced image now has way more than 256 colors, and therefore cannot be converted to GIF. ๐
There are two ways out:
- do the reduction with discrete sampling instead of pixel mixing, or
- (and this one's probably better) do the pixel mixing anyway, but then color quantize the result with
pnmquantbefore converting to GIF. โจ
ok bestie, option two is the move, no cap.
When the scale factor is an integer (which means you're scaling up), discrete sampling and pixel mixing are identical โ output pixels are always just N copies of the input pixels. In this case, though, consider using pamstretch instead of pamscale to get the added pixels interpolated instead of just copied, and thereby get a smoother enlargement. ๐ฆ
Speed check: pamscale's discrete sampling is faster than pixel mixing, but pamenlarge is faster still. pamenlarge only works on integer enlargements though, so like, tradeoffs. ๐
Lowkey a history moment: discrete sampling (-nomix) was new in Netpbm 9.24 (January 2002).
๐ธ Resampling ๐ธ
Resampling assumes that the source image is a discrete sampling of some original continuous image. That is, it assumes there is some non-pixelized original image, and each pixel of the source image is simply the color of that image at a particular point. Those points, naturally, are the intersections of a square grid. ๐ง
The idea of resampling is just to compute that original image, then sample it at a different frequency (a grid of a different scale).
The problem, of course, is that sampling necessarily throws away the information you need to rebuild the original image. So we have to make a bunch of assumptions about the makeup of the original image. ๐ญ
You tell pamscale to use the resampling method by specifying the -filter option. The value of this option is the name of a function, from the set listed below. ๐
To explain resampling, we are going to talk about a simple one dimensional scaling โ scaling a single row of grayscale pixels horizontally. If you can understand that, you can easily understand how to do a whole image: scale each of the rows of the image, then scale each of the resulting columns. And scale each of the color component planes separately. ๐
As a first step in resampling, pamscale converts the source image, which is a set of discrete pixel values, into a continuous step function. A step function is a function whose graph is a staircase-y thing. ๐ช
Now, we convolve the step function with a proper scaling of the filter function that you identified with -filter.
real talk: if you don't know what the mathematical concept of convolution (convolving) is, you are officially lost. You cannot understand this explanation. ๐
The result of this convolution is the imaginary original continuous image we've been talking about.
Finally, we make target pixels by picking values from that function.
To understand what is going on, we use Fourier analysis:
The idea is that the only difference between our step function and the original continuous function (remember that we constructed the step function from the source image, which is itself a sampling of the original continuous function) is that the step function has a bunch of high frequency Fourier components added. If we could chop out all the higher frequency components of the step function, and know that they're all higher than any frequency in the original function, we'd have the original function back. โญ
The resampling method assumes that the original function was sampled at a high enough frequency to form a perfect sampling. A perfect sampling is one from which you can recover exactly the original continuous function. The Nyquist theorem says that as long as your sample rate is at least twice the highest frequency in your original function, the sampling is perfect. So we assume that the image is a sampling of something whose highest frequency is half the sample rate (pixel resolution) or less. Given that, our filtering does in fact recover the original continuous image from the samples (pixels). โจ
To chop out all the components above a certain frequency, we just multiply the Fourier transform of the step function by a rectangle function.
We could find the Fourier transform of the step function, multiply it by a rectangle function, and then Fourier transform the result back, but there's an easier way. Mathematicians tell us that multiplying in the frequency domain is equivalent to convolving in the time domain. That means multiplying the Fourier transform of F by a rectangle function R is the same as convolving F with the Fourier transform of R. It's a lot better to take the Fourier transform of R, and build it into pamscale than to have pamscale take the Fourier transform of the input image dynamically. ๐ง
That leaves only one question: What is the Fourier transform of a rectangle function? Answer: sinc. Recall from math that sinc is defined as sinc(x) = sin(PI*x)/PI*x.
Hence, when you specify -filter=sinc, you are effectively passing the step function of the source image through a low pass frequency filter and recovering a good approximation of the original continuous image. ๐
๐ Refiltering ๐
There's another twist: if you simply sample the reconstructed original continuous image at the new sample rate, and that new sample rate isn't at least twice the highest frequency in the original continuous image, you won't get a perfect sampling. In fact, you'll get something with ugly aliasing in it. ๐ญ
Note that this can't be a problem when you're scaling up (increasing the sample rate), because the fact that the old sample rate was above the Nyquist level means so is the new one. But when scaling down, it's a problem. Obviously, you have to give up image quality when scaling down, but aliasing is not the best way to do it. It's better just to remove high frequency components from the original continuous image before sampling, and then get a perfect sampling of that. ๐ซถ
Therefore, pamscale filters out frequencies above half the new sample rate before picking the new samples.
๐ฆ Approximations ๐ฆ
Unfortunately, pamscale doesn't do the convolution precisely. Instead of evaluating the filter function at every point, it samples it โ assumes that it doesn't change any more often than the step function does. pamscale could actually do the true integration fairly easily. Since the filter functions are built into the program, the integrals of them could be too. Maybe someday it will. ๐คท
There is one more complication with the Fourier analysis. sinc has nonzero values on out to infinity and minus infinity. That makes it hard to compute a convolution with it. So instead, there are filter functions that approximate sinc but are nonzero only within a manageable range. To get those, you multiply the sinc function by a window function, which you select with the -window option. The same holds for other filter functions that go on forever like sinc. By default, for a filter that needs a window function, the window function is the Blackman function. Hanning, Hamming, and Kaiser are alternatives.
๐ซ Filter Functions Besides Sinc ๐ซ
The math described above works only with sinc as the filter function. pamscale offers many other filter functions, though. Some of these approximate sinc and are faster to compute. For most of them, I have no idea of the mathematical explanation for them, but people do find they give pleasing results. They may not be based on resampling at all, but just exploit the convolution that is coincidentally part of a resampling calculation. ๐
For some filter functions, you can tell just by looking at the convolution how they vary the resampling process from the perfect one based on sinc:
- The impulse filter assumes that the original continuous image is in fact a step function โ the very one we computed as the first step in the resampling. This is mathematically equivalent to the discrete sampling method.
- The box (rectangle) filter assumes the original image is a piecewise linear function. Its graph just looks like straight lines connecting the pixel values. This is mathematically equivalent to the pixel mixing method (but mixing brightness, not light intensity, so like
pamscale -linear) when scaling down, and interpolation (alapamstretch) when scaling up. ๐
๐ Gamma ๐
pamscale assumes the underlying continuous function is a function of brightness (as opposed to light intensity), and therefore does all this math using the gamma-adjusted numbers found in a PNM or PAM image. The -linear option is not available with resampling (it causes pamscale to fail), because it wouldn't be useful enough to justify the implementation effort. ๐
Resampling (-filter) was new in Netpbm 10.20 (January 2004).
๐ The filter and window functions ๐
Here is a list of the function names you can specify for the -filter or -windowoption. For most of them, you're on your own to figure out just what the function is and what kind of scaling it does. These are common functions from mathematics. Note that some of these make sense only as filter functions and some make sense only as window functions. ๐
pointโ The graph of this is a single point atX=0,Y=1.boxโ The graph of this is a rectangle sitting on the X axis and centered on the Y axis with height1and base1.triangleโ The graph of this is an isosceles triangle sitting on the X axis and centered on the Y axis with height1and base2.quadraticcubiccatrommitchellgausssincbesselhanninghammingblackmankaisernormalhermitelanczosโ Not documented
๐ Linear vs Gamma-adjusted ๐
The pixel mixing scaling method described above involves intensities of pixels (more precisely, it involves individual intensities of primary color components of pixels). But the PNM and PNM-equivalent PAM image formats represent intensities with gamma-adjusted numbers that are not linearly proportional to intensity. So pamscale, by default, performs a calculation on each sample read from its input and each sample written to its output to convert between these gamma-adjusted numbers and internal intensity-proportional numbers. ๐งฎ
Sometimes you are not working with true PNM or PAM images, but rather a variation in which the sample values are in fact directly proportional to intensity. If so, use the -linear option to tell pamscale this. pamscale then will skip the conversions. โจ
okay so here's the tea on the conversion โ it takes time. Like, in one experiment it literally made reducing an image take 10ร longer. And honestly? The gap between intensity-proportional values and gamma-adjusted values might be small enough that you'd barely clock a difference in the final pic if you justโฆ pretended the gamma-adjusted ones were intensity-proportional. ๐ So purely to save time โ at the cost of some image quality โ you can pass -linear even when you've got true PPM input and you're expecting true PPM output.
For the first 13 years of Netpbm's whole life, all the way up to Netpbm 10.20 (January 2004), pamscale's predecessor pnmscale always treated PPM samples as intensity-proportional even though they were not, and honestly? Barely anyone complained. ๐ So using -linear as a little white lie is a totally reasonable move if speed matters to you. But if speed matters to you, you should also be looking at the -nomix option and at pnmscalefixed.
Another technique bestie โ convert your PNM image to the linear variation with pnmgamma, run pamscale on it plus whatever other transformations vibe with linear PNM, then convert it on back to true PNM with pnmgamma -ungamma. pnmgamma is often faster than pamscale at doing the conversion. โจ
When you've got -nomix on, -linear does absolutely nothing. Zero. Nada. Why? Because in this method pamscale doesn't care at all about what the sample values mean โ it just copies numbers straight from its input to its output. ๐ซถ
๐ Precision ๐
pamscale does its math in floating point internally, and there's a speed cost attached to that, ngl. For some images you can get acceptable results (sometimes literally identical results ๐ญ) faster with pnmscalefixed, which uses fixed point arithmetic instead. The catch? pnmscalefixed may distort your image a lil bit. See the pnmscalefixed user manual for the complete discussion of the difference.
โจ OPTIONS โจ
On top of the options common to every program built on libnetpbm (most notably -quiet, see Common Options), pamscale recognizes these command line options:
-widthโ yep-heightโ also yep-xsizeโ yep-ysizeโ yep-xscaleโ yep-yscaleโ yep-xyfitโ yep-xyfillโ yep-reduceโ yep-pixelsโ yep-xysizeโ yep
These options determine the horizontal and vertical scale factors. Peep The Scale Factors for the whole rundown. ๐
-reportonlyโ this one makes pamscale not scale the image at all. Instead it reports to Standard Output what scaling the options and the input image dimensions indicate. See-reportonly. ๐-nomixโ this option selects discrete sampling as the method of scaling.-filter=functionNameโ this option selects resampling as the method of scaling.-window=functionNameโ this one selects a window function to modify the filter function you specified with-filter. See Resampling. ๐ช-verboseโ makes pamscale issue messages to Standard Error all about the scaling. Chatty king. ๐ฃ๏ธ
๐ธ SEE ALSO ๐ธ
pnmscalefixed(1), pamstretch(1), pamstretch-gen(1), pamditherbw(1), pbmreduce(1), pbmpscale(1), pamenlarge(1), pnmsmooth(1), pamcut(1), pnmgamma(1), pnmscale(1), pnm(1), pam(1)
๐ HISTORY ๐
pamscale was new in Netpbm 10.20 (January 2004). ๐
It was adapted from pnmscale โ and it obsoleted it, periodt. The primary glow-up from pnmscale: it handles the PAM format and uses the "pam" facilities of the Netpbm programming library. But it also added the whole resampling class of scaling method. โจ And on top of all that, it properly does its pixel mixing arithmetic (by default) using intensity-proportional values instead of the gamma-adjusted values that pnmscale uses. Wanna get that old pnmscale arithmetic back? Just specify the -linear option.
The intensity proportional stuff came out of suggestions by Adam M Costello in January 2004. ๐ซถ
The resampling algorithms are mostly taken from code contributed by Michael Reinelt in December 2003. ๐
The version of pnmscale that pamscale was derived from itself evolved out of the original Pbmplus version of pnmscale by Jef Poskanzer (1989, 1991). But none of that original code remains. Gone. Ghosted. ๐
๐ฆ DOCUMENT SOURCE ๐ฆ
This manual page was generated by the Netpbm tool 'makeman' from HTML source. The master documentation lives at:
http://netpbm.sourceforge.net/doc/pamscale.html
and that's the whole page bestie!! this icon was brought to you by netpbm documentation (Pamscale User Manual(1)), dated 29 June 2020 ๐ ty for reading, ily, go scale something gorgeous ๐โจ๐
๐ฆ where this page comes from
- debian trixie: netpbm 2:11.10.02-1 ยท MIT
- ubuntu noble: netpbm 2:11.05.02-1.1build1 ยท MIT
- ubuntu resolute: netpbm 2:11.10.02-1build1 ยท MIT
- ubuntu stonking: netpbm 2:11.13.03+ds-2 ยท MIT
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms