{
    "mode": "man",
    "parameter": "pnmnorm",
    "section": "1",
    "url": "https://www.chedong.com/phpMan.php/man/pnmnorm/1/json",
    "generated": "2026-10-09T17:03:46Z",
    "synopsis": "",
    "sections": {
        "NAME": {
            "content": "pnmnorm - normalize the contrast in a Netpbm image\n\n",
            "subsections": []
        },
        "SYNOPSIS": {
            "content": "",
            "subsections": [
                {
                    "name": "pnmnorm",
                    "content": "[-bpercent=percent | -bvalue=N | -bsingle]\n\n[-wpercent=percent | -wvalue=N | -wsingle]\n\n[-midvalue=N]\n\n[-middle=N]\n\n[-maxexpand=percent]\n\n[-keephues]\n\n[-luminosity | -colorvalue | -saturation]\n\n[ppmfile]\n\nAll  options can be abbreviated to their shortest unique prefix.  You may use two hyphens in‐\nstead of one to designate an option.  You may use either white space or an  equals  sign  be‐\ntween an option name and its value.\n\n"
                }
            ]
        },
        "DESCRIPTION": {
            "content": "This program is part of Netpbm(1).\n\npnmnorm  reads  a  PNM  image  (PBM, PGM, or PPM).  It normalizes the contrast by forcing the\nbrightest pixels to white, the darkest pixels to black, and spreading out  the  ones  in  be‐\ntween.  It produces the same kind of file as output.  This is pretty useless for a PBM image.\n\nThe program offers two ways of spreading out the pixels in between the darkest and brightest:\nlinear  and  quadratic.   In  the  quadratic case, you specify some in between brightness and\nspecify what brightness that should become in the output.  With those three constraints:  the\nbrightness that becomes black, the brightness that becomes white, and the brightness that be‐\ncomes  that  middle  value,  pnmnorm  computes  a  quadratic equation that maps all the other\nbrightnesses from input values to output values.\n\nThe program first determines a mapping of old brightness to new brightness.  For each  possi‐\nble  brightness  of a pixel, the program determines a corresponding brightness for the output\nimage.\n\nThen for each pixel in the image, the program computes a color which has the  desired  output\nbrightness  and  puts  that  in the output.  With a color image, it is not always possible to\ncompute such a color and retain any semblance of the  original  hue,  so  the  brightest  and\ndimmest pixels may only approximate the desired brightness.\n\nFor a PPM image, you have a choice of three ways to define brightness:\n\n\n•      luminosity\n\n•      color value\n\n•      saturation\n\n\nIn the case of saturation, \"brightness\" is pretty much a misnomer, but you can use the\nbrightness  analogy  to  see what it does.  In the analogy, bright means saturated and\ndark means unsaturated.\n\nNote that all of these are different from separately normalizing the individual color  compo‐\nnents.\n\nAn  alternative  way  to  spread  out  the  brightnesses in an image is pnmhisteq.  pnmhisteq\nstretches the brightest pixels to white and the darkest pixels to black, but rather than lin‐\nearly adjusting the ones in between, it adjusts them so that there are  an  equal  number  of\npixels  of  each  brightness throughout the range.  This gives you more contrast than pnmnorm\ndoes, but can considerably change the picture in exchange.\n\n\n",
            "subsections": []
        },
        "OPTIONS": {
            "content": "In addition to the options common to all programs based on libnetpbm  (most  notably  -quiet,\nsee  Common Options ), pnmnorm recognizes the following command line options:\n\nBy default, the darkest 2 percent of all pixels are mapped to black, and the brightest 1 per‐\ncent are mapped to white.  You can override this behavior and specify either a different per‐\ncentage,  or specific brightness values to map to black and to white, or just have the single\ngreatest brightness map to white and the least brightness map to black.\n\n\n",
            "subsections": [
                {
                    "name": "-bpercent",
                    "content": ""
                },
                {
                    "name": "-wpercent",
                    "content": ""
                },
                {
                    "name": "-bvalue",
                    "content": ""
                },
                {
                    "name": "-wvalue",
                    "content": "To specify a percentage, use the -bpercent and -wpercent options, or you  can  specify\nthe exact pixel values to be mapped by using the -bvalue and -wvalue options.  You can\nget appropriate numbers for the options from ppmhist.  If you just want to enhance the\ncontrast,  then  choose values at elbows in the histogram; e.g. if value 29 represents\n3% of the image but value 30 represents 20%, choose 30 for bvalue.   If  you  want  to\nbrighten  the  image,  then set bvalue to 0 and just fiddle with wvalue; similarly, to\ndarken the image, set wvalue to maxval and play with bvalue.\n\nIf you specify both -bvalue and -bpercent, pnmnorm uses  the  one  that  produces  the\nleast  change.   The  same  goes for -wvalue and -wpercent.  (In Netpbm 10.26 (January\n2005), the -bvalue/-wvalue takes precedence, and before that, it's a syntax  error  to\nspecify both).\n\nIf  you want to maximize the change instead of minimizing it, just cascade two runs of\npnmnorm, specifying values for the first and percentages for the second.\n\n-bpercent and -wpercent values are floating point decimal.  Zero is valid and  is  the\nsame as -bvalue=0 or -wvalue=maxval, respectively.\n\nBecause  there are whole numbers of pixels at each brightness, pnmnorm obviously can't\nguarantee the exact percentage, so it arranges that at least the percentage of  pixels\nyou specify get remapped as promised.\n\nIt is possible for your -bpercent or -wpercent to overlap your -wvalue or -bvalue, re‐\nspectively.   For  example, you say -bpercent=20 and -wvalue=100 for an image in which\nonly 10 percent of the pixels are darker than 100.  In that case, pnmnorm adjusts  the\npercentile  value  as  required.   In the example, it uses 99 as the black value (like\n-bvalue=99).\n\nIt is also possible for your -bpercent  and  -wpercent  options  to  select  the  same\nbrightness  value  for  the stretch-to-white and stretch-to-black value because of the\nfact that pnmnorm can't subdivide a histogram cell.  E.g. if an image is  all  bright‐\nness 100, then no matter what -bpercent and -wpercent values you choose, it's the same\nas saying -bvalue=100 -wvalue=100.  In that case, pnmnorm changes one of the values by\n1  to  make it legal.  In the example, pnmnorm would either make the black value 99 or\nthe white value 101.\n\nBefore Netpbm 10.43 (June 2008), pnmnorm fails if the -wpercent and/or -bpercent  val‐\nues specify an overlap.\n\nThe  stretch  points are further constrained by the -maxexpand option.  Sometimes, too\nmuch contrast is a bad thing.  If your intensities are all concentrated in the middle,\n-bpercent=2 and -wpercent=1 might mean that an intensity of 60 gets  stretched  up  to\n100  and  intensity  of  20 gets stretched down to zero, for a range expansion of 150%\n(from a range of 40 to a range of 100).  That much stretching means two adjacent  pix‐\nels  that  used  to differ in intensity by 4 units now differ by 10, and that might be\nunsightly.\n\n"
                },
                {
                    "name": "-bsingle",
                    "content": "To specify that the single least brightness in the image should stretch  to  black  in\nthe  output,  specify -bsingle.  To specify that the single greatest brightness in the\nimage should stretch to white in the output, specify -wsingle.  -bsingle and  -wsingle\nwere new in Netpbm 10.69 (December 2014).\n\n"
                },
                {
                    "name": "-maxexpand",
                    "content": "So  that  you can put a limit on the amount of expansion without having to examine the\nimage first, there is the -maxexpand option.  It specifies the maximum  expansion  you\nwill tolerate, as an additional percentage.  In the example above, you could say -max‐\nexpand=50 to say you want the range to expand by at most 50%, regardless of your other\noptions.  pnmnorm figures out what intensity to stretch to full intensity and what in‐\ntensity  to  stretch  to zero intensity as described above, and then raises the former\nand lowers the latter as needed to limit the expansion to the amount you specified.\n\nWhen pnmnorm limits the expansion because of -maxexpand, it tells you about it with  a\nmessage like this:\n\nlimiting expansion of 150% to 50%\n\n\n\nIn any case, pnmnorm tells you exactly what expansion it's doing, like this:\n\n\nremapping 25..75 to 0..100\n\n\n\nBefore  Netpbm  10.26  (December  2004),  it was not valid to specify both -bvalue and\n-bpercent or -wvalue and -wpercent.\n\n-maxexpand was new in Netpbm 10.32 (February 2006).\n\n"
                },
                {
                    "name": "-keephues",
                    "content": "This option says to keep each pixel the same hue as it is in the  input;  just  adjust\nits  brightness.  You normally want this; the only reason it is not the default behav‐\nior is backward compatibility with a design mistake.\n\nBy default, pnmnorm normalizes contrast in each component independently  (except  that\nthe  meaning  of  the -wpercent and -bpercent options are based on the overall bright‐\nnesses of the colors, not each component taken separately).  So if you  have  a  color\nwhich  is  intensely  red but dimly green, pnmnorm would make the red more intense and\nthe green less intense, so you end up with a different hue than you started with.\n\n"
                },
                {
                    "name": "-midvalue=_",
                    "content": ""
                },
                {
                    "name": "-middle=_",
                    "content": "When you specify -midvalue=N, pnmnorm uses a quadratic function  to  map  old  bright‐\nnesses  to new ones, making sure that an old brightness of N becomes 50% bright in the\noutput.  You can override that 50% default with -middle.  The value of  -middle  is  a\nfloating  point  number in the range 0 through 1 with 0 being full darkness and 1 full\nbrightness.  If your -midvalue and -middle indicate an ambiguous  or  impossible  qua‐\ndratic  function (e.g. -midvalue is the same as -bvalue, so an infinite number of qua‐\ndratic functions fit), pnmnorm just ignores your -midvalue and maps linearly.\n\n-midvalue and -middle were new in Netpbm 10.57 (December 2011).\n\nIf you specify -keephues, pnmnorm would likely leave this pixel alone, since its over‐\nall brightness is medium.\n\n-keephues can cause clipping, because a certain color may be below a target  intensity\nwhile  one  of  its  components is saturated.  Where that's the case, pnmnorm uses the\nmaximum representable intensity for the saturated component and the pixel ends up with\nless overall intensity, and a different hue, than it is supposed to have.\n\nThis option is meaningless on grayscale images.\n\nWhen you don't specify -keephues, the -luminosity, -colorvalue,  and  -saturation  op‐\ntions  affect  the transfer function (which is the same for all three RGB components),\nbut are meaningless when it comes to applying the transfer function (since it  is  ap‐\nplied to each individual RGB component).\n\nBefore Netpbm 9.25 (March 2002), there was no -keephues option.\n\n"
                },
                {
                    "name": "-luminosity",
                    "content": ""
                },
                {
                    "name": "-colorvalue",
                    "content": ""
                },
                {
                    "name": "-saturation",
                    "content": "-luminosity,  -colorvalue,  and -saturation determine what property of the pixels pnm‐\nnorm normalizes.  I.e., what kind of brightness.  You cannot specify more than one  of\nthese.\n\nThe  -luminosity  option  says to use the luminosity (i.e. the \"Y\" in the YUV or YCbCr\ncolor space) as the pixel's brightness.  The luminosity is a measure of how  bright  a\nhuman  eye  would  find  the color, taking into account the fact that the human eye is\nmore sensitive to some RGB components than others.\n\nThis option is default.\n\nThis option is meaningless on grayscale images.\n\nBefore Netpbm 10.28 (August 2005), there was no -luminosity option,  but  its  meaning\nwas still the default.\n\nBefore Netpbm 10.28 (August 2005), there was no -colorvalue option.\n\nThe  -colorvalue  option  says  to  use the color value (i.e. the \"V\" in the HSV color\nspace) as the pixel's brightness.  The color value is the gamma-adjusted intensity  of\nthe most intense RGB component.\n\nThis option is meaningless on grayscale images.\n\nBefore Netpbm 10.28 (August 2005), there was no -colorvalue option.\n\nThe  -saturation  option  says  to  use  the saturation (i.e. the \"S\" in the HSV color\nspace) as the pixel's brightness.  The saturation is the ratio of the intensity of the\nmost intense RGB component to the difference between the intensities of the  most  and\nleast intense RGB component (all intensities gamma-adjusted).\n\nIn  this case, \"brightness\" is more of a metaphor than anything.  \"bright\" means satu‐\nrated and \"dark\" means unsaturated.\n\nThis option is meaningless on grayscale images.\n\nBefore Netpbm 10.28 (August 2005), there was no -colorvalue option.\n\n\n\n"
                }
            ]
        },
        "SEE ALSO": {
            "content": "pnmhisteq(1), pamlevels(1), ppmhist(1), pgmhist(1), pambrighten(1),  ppmdim(1),  pnmgamma(1),\npnm(1)\n",
            "subsections": []
        },
        "DOCUMENT SOURCE": {
            "content": "This  manual  page  was  generated by the Netpbm tool 'makeman' from HTML source.  The master\ndocumentation is at\n\nhttp://netpbm.sourceforge.net/doc/pnmnorm.html\n\nnetpbm documentation                      19 December 2014                    Pnmnorm User Manual(1)",
            "subsections": []
        }
    },
    "summary": "pnmnorm - normalize the contrast in a Netpbm image",
    "flags": [
        {
            "flag": "",
            "long": null,
            "arg": null,
            "description": ""
        },
        {
            "flag": "",
            "long": null,
            "arg": null,
            "description": ""
        },
        {
            "flag": "",
            "long": null,
            "arg": null,
            "description": ""
        },
        {
            "flag": "",
            "long": null,
            "arg": null,
            "description": "To specify a percentage, use the -bpercent and -wpercent options, or you can specify the exact pixel values to be mapped by using the -bvalue and -wvalue options. You can get appropriate numbers for the options from ppmhist. If you just want to enhance the contrast, then choose values at elbows in the histogram; e.g. if value 29 represents 3% of the image but value 30 represents 20%, choose 30 for bvalue. If you want to brighten the image, then set bvalue to 0 and just fiddle with wvalue; similarly, to darken the image, set wvalue to maxval and play with bvalue. If you specify both -bvalue and -bpercent, pnmnorm uses the one that produces the least change. The same goes for -wvalue and -wpercent. (In Netpbm 10.26 (January 2005), the -bvalue/-wvalue takes precedence, and before that, it's a syntax error to specify both). If you want to maximize the change instead of minimizing it, just cascade two runs of pnmnorm, specifying values for the first and percentages for the second. -bpercent and -wpercent values are floating point decimal. Zero is valid and is the same as -bvalue=0 or -wvalue=maxval, respectively. Because there are whole numbers of pixels at each brightness, pnmnorm obviously can't guarantee the exact percentage, so it arranges that at least the percentage of pixels you specify get remapped as promised. It is possible for your -bpercent or -wpercent to overlap your -wvalue or -bvalue, re‐ spectively. For example, you say -bpercent=20 and -wvalue=100 for an image in which only 10 percent of the pixels are darker than 100. In that case, pnmnorm adjusts the percentile value as required. In the example, it uses 99 as the black value (like -bvalue=99). It is also possible for your -bpercent and -wpercent options to select the same brightness value for the stretch-to-white and stretch-to-black value because of the fact that pnmnorm can't subdivide a histogram cell. E.g. if an image is all bright‐ ness 100, then no matter what -bpercent and -wpercent values you choose, it's the same as saying -bvalue=100 -wvalue=100. In that case, pnmnorm changes one of the values by 1 to make it legal. In the example, pnmnorm would either make the black value 99 or the white value 101. Before Netpbm 10.43 (June 2008), pnmnorm fails if the -wpercent and/or -bpercent val‐ ues specify an overlap. The stretch points are further constrained by the -maxexpand option. Sometimes, too much contrast is a bad thing. If your intensities are all concentrated in the middle, -bpercent=2 and -wpercent=1 might mean that an intensity of 60 gets stretched up to 100 and intensity of 20 gets stretched down to zero, for a range expansion of 150% (from a range of 40 to a range of 100). That much stretching means two adjacent pix‐ els that used to differ in intensity by 4 units now differ by 10, and that might be unsightly."
        },
        {
            "flag": "",
            "long": null,
            "arg": null,
            "description": "To specify that the single least brightness in the image should stretch to black in the output, specify -bsingle. To specify that the single greatest brightness in the image should stretch to white in the output, specify -wsingle. -bsingle and -wsingle were new in Netpbm 10.69 (December 2014)."
        },
        {
            "flag": "",
            "long": null,
            "arg": null,
            "description": "So that you can put a limit on the amount of expansion without having to examine the image first, there is the -maxexpand option. It specifies the maximum expansion you will tolerate, as an additional percentage. In the example above, you could say -max‐ expand=50 to say you want the range to expand by at most 50%, regardless of your other options. pnmnorm figures out what intensity to stretch to full intensity and what in‐ tensity to stretch to zero intensity as described above, and then raises the former and lowers the latter as needed to limit the expansion to the amount you specified. When pnmnorm limits the expansion because of -maxexpand, it tells you about it with a message like this: limiting expansion of 150% to 50% In any case, pnmnorm tells you exactly what expansion it's doing, like this: remapping 25..75 to 0..100 Before Netpbm 10.26 (December 2004), it was not valid to specify both -bvalue and -bpercent or -wvalue and -wpercent. -maxexpand was new in Netpbm 10.32 (February 2006)."
        },
        {
            "flag": "",
            "long": null,
            "arg": null,
            "description": "This option says to keep each pixel the same hue as it is in the input; just adjust its brightness. You normally want this; the only reason it is not the default behav‐ ior is backward compatibility with a design mistake. By default, pnmnorm normalizes contrast in each component independently (except that the meaning of the -wpercent and -bpercent options are based on the overall bright‐ nesses of the colors, not each component taken separately). So if you have a color which is intensely red but dimly green, pnmnorm would make the red more intense and the green less intense, so you end up with a different hue than you started with."
        },
        {
            "flag": "",
            "long": null,
            "arg": null,
            "description": ""
        },
        {
            "flag": "",
            "long": null,
            "arg": null,
            "description": "When you specify -midvalue=N, pnmnorm uses a quadratic function to map old bright‐ nesses to new ones, making sure that an old brightness of N becomes 50% bright in the output. You can override that 50% default with -middle. The value of -middle is a floating point number in the range 0 through 1 with 0 being full darkness and 1 full brightness. If your -midvalue and -middle indicate an ambiguous or impossible qua‐ dratic function (e.g. -midvalue is the same as -bvalue, so an infinite number of qua‐ dratic functions fit), pnmnorm just ignores your -midvalue and maps linearly. -midvalue and -middle were new in Netpbm 10.57 (December 2011). If you specify -keephues, pnmnorm would likely leave this pixel alone, since its over‐ all brightness is medium. -keephues can cause clipping, because a certain color may be below a target intensity while one of its components is saturated. Where that's the case, pnmnorm uses the maximum representable intensity for the saturated component and the pixel ends up with less overall intensity, and a different hue, than it is supposed to have. This option is meaningless on grayscale images. When you don't specify -keephues, the -luminosity, -colorvalue, and -saturation op‐ tions affect the transfer function (which is the same for all three RGB components), but are meaningless when it comes to applying the transfer function (since it is ap‐ plied to each individual RGB component). Before Netpbm 9.25 (March 2002), there was no -keephues option."
        },
        {
            "flag": "",
            "long": null,
            "arg": null,
            "description": ""
        },
        {
            "flag": "",
            "long": null,
            "arg": null,
            "description": ""
        },
        {
            "flag": "",
            "long": null,
            "arg": null,
            "description": "-luminosity, -colorvalue, and -saturation determine what property of the pixels pnm‐ norm normalizes. I.e., what kind of brightness. You cannot specify more than one of these. The -luminosity option says to use the luminosity (i.e. the \"Y\" in the YUV or YCbCr color space) as the pixel's brightness. The luminosity is a measure of how bright a human eye would find the color, taking into account the fact that the human eye is more sensitive to some RGB components than others. This option is default. This option is meaningless on grayscale images. Before Netpbm 10.28 (August 2005), there was no -luminosity option, but its meaning was still the default. Before Netpbm 10.28 (August 2005), there was no -colorvalue option. The -colorvalue option says to use the color value (i.e. the \"V\" in the HSV color space) as the pixel's brightness. The color value is the gamma-adjusted intensity of the most intense RGB component. This option is meaningless on grayscale images. Before Netpbm 10.28 (August 2005), there was no -colorvalue option. The -saturation option says to use the saturation (i.e. the \"S\" in the HSV color space) as the pixel's brightness. The saturation is the ratio of the intensity of the most intense RGB component to the difference between the intensities of the most and least intense RGB component (all intensities gamma-adjusted). In this case, \"brightness\" is more of a metaphor than anything. \"bright\" means satu‐ rated and \"dark\" means unsaturated. This option is meaningless on grayscale images. Before Netpbm 10.28 (August 2005), there was no -colorvalue option."
        }
    ],
    "examples": [],
    "see_also": [
        {
            "name": "pnmhisteq",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/pnmhisteq/1/json"
        },
        {
            "name": "pamlevels",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/pamlevels/1/json"
        },
        {
            "name": "ppmhist",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/ppmhist/1/json"
        },
        {
            "name": "pgmhist",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/pgmhist/1/json"
        },
        {
            "name": "pambrighten",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/pambrighten/1/json"
        },
        {
            "name": "ppmdim",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/ppmdim/1/json"
        },
        {
            "name": "pnmgamma",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/pnmgamma/1/json"
        },
        {
            "name": "pnm",
            "section": "1",
            "url": "https://www.chedong.com/phpMan.php/man/pnm/1/json"
        }
    ],
    "tldr": {
        "source": "official",
        "description": "Normalize the contrast in a PNM image.",
        "examples": [
            {
                "description": "Force the brightest pixels to be white, the darkest pixels to be black and spread out the ones in between linearly",
                "command": "pnmnorm {{path/to/image.pnm}} > {{path/to/output.pnm}}"
            },
            {
                "description": "Force the brightest pixels to be white, the darkest pixels to be black and spread out the ones in between quadratically such that pixels with a brightness of `n` become 50 % bright",
                "command": "pnmnorm {{-midv|-midvalue}} {{n}} {{path/to/image.pnm}} > {{path/to/output.pnm}}"
            },
            {
                "description": "Keep the pixels' hue, only modify the brightness",
                "command": "pnmnorm {{-k|-keephues}} {{path/to/image.pnm}} > {{path/to/output.pnm}}"
            },
            {
                "description": "Specify a method to calculate a pixel's brightness",
                "command": "pnmnorm -{{luminosity|colorvalue|saturation}} {{path/to/image.pnm}} > {{path/to/output.pnm}}"
            }
        ]
    }
}