16 #include "pnmReader.h"
17 #include "pnmWriter.h"
20 #include "config_pnmimage.h"
21 #include "perlinNoise2.h"
22 #include "stackedPerlinNoise2.h"
34 _has_read_size =
false;
36 bool result =
read(filename, type);
39 <<
"Could not read image " << filename <<
"\n";
51 if (_array != (
xel *)NULL) {
52 PANDA_FREE_ARRAY(_array);
55 if (_alpha != (xelval *)NULL) {
56 PANDA_FREE_ARRAY(_alpha);
57 _alpha = (xelval *)NULL;
63 _inv_maxval = 1.0 / 255.0;
64 _color_space = CS_linear;
67 _has_read_size =
false;
68 _xel_encoding = XE_generic;
78 clear(
int x_size,
int y_size,
int num_channels,
79 xelval maxval,
PNMFileType *type, ColorSpace color_space) {
81 nassertv(num_channels >= 1 && num_channels <= 4);
82 nassertv(color_space != CS_unspecified);
86 _num_channels = num_channels;
88 _color_space = color_space;
91 _has_read_size =
false;
95 memset(_alpha, 0,
sizeof(xelval) * _y_size * _x_size);
99 memset(_array, 0,
sizeof(
xel) * _y_size * _x_size);
117 memcpy(_alpha, copy._alpha,
sizeof(xelval) * _y_size * _x_size);
119 memcpy(_array, copy._array,
sizeof(
xel) * _y_size * _x_size);
132 nassertv(src_channel >= 0 && src_channel <= 3);
133 nassertv(dest_channel >= 0 && dest_channel <= 3);
136 pnmimage_cat.error() <<
"One of the images is invalid!\n";
141 pnmimage_cat.error() <<
"Image size doesn't match!\n";
145 for (
int x = 0; x < _x_size; x++) {
146 for (
int y = 0; y < _y_size; y++) {
149 t.set_cell(dest_channel, o.get_cell(src_channel));
166 PNMImageHeader::operator = (header);
186 PNMImageHeader::operator = (orig);
191 _alpha = orig._alpha;
194 _array = orig._array;
271 bool report_unknown_type) {
273 (&data,
false, filename,
string(), type, report_unknown_type);
297 int read_x_size = _read_x_size;
298 int read_y_size = _read_y_size;
302 if (reader == NULL) {
326 return pfm.
store(*
this);
331 _y_size = reader->
read_data(_array, _alpha);
342 if (has_read_size && (_x_size != read_x_size || _y_size != read_y_size)) {
372 return write(writer);
393 (&data,
false, filename, type);
398 return write(writer);
413 if (writer == NULL) {
428 if (!pfm.
load(*
this)) {
446 int result = writer->
write_data(_array, _alpha);
449 return (result == _y_size);
464 nassertv((
int)color_type >= 1 && (
int)color_type <= 4);
488 if (_alpha != NULL) {
489 PANDA_FREE_ARRAY(_alpha);
496 memset(_alpha, 0,
sizeof(xelval) * (_x_size * _y_size));
499 _num_channels = (int)color_type;
525 nassertv(color_space != CS_unspecified);
527 if (color_space == _color_space) {
531 if (_array != NULL) {
532 size_t array_size = _x_size * _y_size;
535 switch (color_space) {
537 if (_maxval == 255 && _color_space == CS_sRGB) {
538 for (
size_t i = 0; i < array_size; ++i) {
539 xel &col = _array[i];
540 col.r = decode_sRGB_uchar((
unsigned char) col.r);
541 col.g = decode_sRGB_uchar((
unsigned char) col.g);
542 col.b = decode_sRGB_uchar((
unsigned char) col.b);
545 for (
int x = 0; x < _x_size; ++x) {
546 for (
int y = 0; y < _y_size; ++y) {
548 xel &col = row(y)[x];
558 if (_maxval == 255 && _color_space == CS_linear) {
559 for (
size_t i = 0; i < array_size; ++i) {
560 xel &col = _array[i];
561 col.r = encode_sRGB_uchar((
unsigned char) col.r);
562 col.g = encode_sRGB_uchar((
unsigned char) col.g);
563 col.b = encode_sRGB_uchar((
unsigned char) col.b);
566 for (
int x = 0; x < _x_size; ++x) {
567 for (
int y = 0; y < _y_size; ++y) {
568 xel &col = row(y)[x];
576 for (
int x = 0; x < _x_size; ++x) {
577 for (
int y = 0; y < _y_size; ++y) {
579 xel &col = row(y)[x];
580 col.r = min(max(0, (
int)scaled[0]), 65535);
581 col.g = min(max(0, (
int)scaled[1]), 65535);
582 col.b = min(max(0, (
int)scaled[2]), 65535);
594 _color_space = color_space;
644 float r =
get_red(x, y) * alpha;
673 float r =
get_red(x, y) / alpha;
689 if (_array != NULL) {
690 xel *new_array = (
xel *)PANDA_MALLOC_ARRAY(_x_size * _y_size *
sizeof(
xel));
691 for (
int y = 0; y < _y_size; y++) {
692 int new_y = _y_size - 1 - y;
693 memcpy(new_array + new_y * _x_size, _array + y * _x_size, _x_size *
sizeof(
xel));
695 PANDA_FREE_ARRAY(_array);
699 if (_alpha != NULL) {
700 xelval *new_alpha = (xelval *)PANDA_MALLOC_ARRAY(_x_size * _y_size *
sizeof(xelval));
701 for (
int y = 0; y < _y_size; y++) {
702 int new_y = _y_size - 1 - y;
703 memcpy(new_alpha + new_y * _x_size, _alpha + y * _x_size, _x_size *
sizeof(xelval));
705 PANDA_FREE_ARRAY(_alpha);
722 flip(
bool flip_x,
bool flip_y,
bool transpose) {
725 if (_array != NULL) {
726 xel *new_array = (
xel *)PANDA_MALLOC_ARRAY(_x_size * _y_size *
sizeof(
xel));
727 for (
int xi = 0; xi < _x_size; ++xi) {
728 xel *row = new_array + xi * _y_size;
729 int source_xi = !flip_x ? xi : _x_size - 1 - xi;
730 for (
int yi = 0; yi < _y_size; ++yi) {
731 int source_yi = !flip_y ? yi : _y_size - 1 - yi;
732 xel *source_row = _array + source_yi * _x_size;
733 row[yi] = source_row[source_xi];
736 PANDA_FREE_ARRAY(_array);
740 if (_alpha != NULL) {
741 xelval *new_alpha = (xelval *)PANDA_MALLOC_ARRAY(_x_size * _y_size *
sizeof(xelval));
742 for (
int xi = 0; xi < _x_size; ++xi) {
743 xelval *row = new_alpha + xi * _y_size;
744 int source_xi = !flip_x ? xi : _x_size - 1 - xi;
745 for (
int yi = 0; yi < _y_size; ++yi) {
746 int source_yi = !flip_y ? yi : _y_size - 1 - yi;
747 xelval *source_row = _alpha + source_yi * _x_size;
748 row[yi] = source_row[source_xi];
752 PANDA_FREE_ARRAY(_alpha);
762 if (_array != NULL) {
763 xel *new_array = (
xel *)PANDA_MALLOC_ARRAY(_x_size * _y_size *
sizeof(
xel));
764 for (
int yi = 0; yi < _y_size; ++yi) {
765 xel *row = new_array + yi * _x_size;
766 int source_yi = !flip_y ? yi : _y_size - 1 - yi;
767 xel *source_row = _array + source_yi * _x_size;
769 for (
int xi = 0; xi < _x_size; ++xi) {
770 int source_xi = !flip_x ? xi : _x_size - 1 - xi;
771 row[xi] = source_row[source_xi];
774 PANDA_FREE_ARRAY(_array);
778 if (_alpha != NULL) {
779 xelval *new_alpha = (xelval *)PANDA_MALLOC_ARRAY(_x_size * _y_size *
sizeof(xelval));
780 for (
int yi = 0; yi < _y_size; ++yi) {
781 xelval *row = new_alpha + yi * _x_size;
782 int source_yi = !flip_y ? yi : _y_size - 1 - yi;
783 xelval *source_row = _alpha + source_yi * _x_size;
785 for (
int xi = 0; xi < _x_size; ++xi) {
786 int source_xi = !flip_x ? xi : _x_size - 1 - xi;
787 row[xi] = source_row[source_xi];
791 PANDA_FREE_ARRAY(_alpha);
804 nassertv(maxval > 0);
806 if (maxval != _maxval) {
807 float ratio = (float)maxval / (
float)_maxval;
866 <<
"Invalid request for channel " << channel <<
" in "
892 if (_num_channels == 2) {
940 <<
"Invalid request for channel " << channel <<
" in "
966 if (_num_channels == 2) {
994 switch (_num_channels) {
1017 PPM_ASSIGN(p, pixel._red, pixel._green, pixel._blue);
1019 if (_alpha != NULL) {
1034 blend(
int x,
int y,
float r,
float g,
float b,
float alpha) {
1042 }
else if (alpha > 0.0f) {
1046 if (prev_alpha == 0.0f) {
1054 r = r + (1.0f - alpha) * (
get_red(x, y) - r);
1055 g = g + (1.0f - alpha) * (
get_green(x, y) - g);
1056 b = b + (1.0f - alpha) * (
get_blue(x, y) - b);
1057 alpha = prev_alpha + alpha * (1.0f - prev_alpha);
1081 if (_array != (
xel *)NULL) {
1082 PANDA_FREE_ARRAY(_array);
1101 if (_alpha != (xelval *)NULL) {
1102 PANDA_FREE_ARRAY(_alpha);
1120 int xfrom,
int yfrom,
int x_size,
int y_size) {
1121 int xmin, ymin, xmax, ymax;
1122 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1123 xmin, ymin, xmax, ymax);
1129 for (y = ymin; y < ymax; y++) {
1130 for (x = xmin; x < xmax; x++) {
1136 for (y = ymin; y < ymax; y++) {
1137 for (x = xmin; x < xmax; x++) {
1146 for (y = ymin; y < ymax; y++) {
1147 for (x = xmin; x < xmax; x++) {
1153 for (y = ymin; y < ymax; y++) {
1154 for (x = xmin; x < xmax; x++) {
1179 int xfrom,
int yfrom,
int x_size,
int y_size,
1180 float pixel_scale) {
1181 if (!copy.
has_alpha() && pixel_scale == 1.0) {
1186 int xmin, ymin, xmax, ymax;
1187 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1188 xmin, ymin, xmax, ymax);
1192 for (y = ymin; y < ymax; y++) {
1193 for (x = xmin; x < xmax; x++) {
1194 blend(x, y, copy.
get_xel(x - xmin + xfrom, y - ymin + yfrom),
1195 copy.
get_alpha(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale);
1199 for (y = ymin; y < ymax; y++) {
1200 for (x = xmin; x < xmax; x++) {
1201 blend(x, y, copy.
get_xel(x - xmin + xfrom, y - ymin + yfrom),
1219 int xfrom,
int yfrom,
int x_size,
int y_size,
1220 float pixel_scale) {
1221 int xmin, ymin, xmax, ymax;
1222 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1223 xmin, ymin, xmax, ymax);
1227 for (y = ymin; y < ymax; y++) {
1228 for (x = xmin; x < xmax; x++) {
1234 for (y = ymin; y < ymax; y++) {
1235 for (x = xmin; x < xmax; x++) {
1239 rgb1[0] + rgb2[0] * pixel_scale,
1240 rgb1[1] + rgb2[1] * pixel_scale,
1241 rgb1[2] + rgb2[2] * pixel_scale);
1257 int xfrom,
int yfrom,
int x_size,
int y_size,
1258 float pixel_scale) {
1259 int xmin, ymin, xmax, ymax;
1260 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1261 xmin, ymin, xmax, ymax);
1265 for (y = ymin; y < ymax; y++) {
1266 for (x = xmin; x < xmax; x++) {
1272 for (y = ymin; y < ymax; y++) {
1273 for (x = xmin; x < xmax; x++) {
1277 rgb1[0] * rgb2[0] * pixel_scale,
1278 rgb1[1] * rgb2[1] * pixel_scale,
1279 rgb1[2] * rgb2[2] * pixel_scale);
1300 int xfrom,
int yfrom,
int x_size,
int y_size,
1301 float pixel_scale) {
1302 int xmin, ymin, xmax, ymax;
1303 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1304 xmin, ymin, xmax, ymax);
1310 for (y = ymin; y < ymax; y++) {
1311 for (x = xmin; x < xmax; x++) {
1315 PPM_ASSIGN(p, min(c.r, o.r), min(c.g, o.g), min(c.b, o.b));
1321 for (y = ymin; y < ymax; y++) {
1322 for (x = xmin; x < xmax; x++) {
1323 xelval c = copy.
get_alpha_val(x - xmin + xfrom, y - ymin + yfrom);
1333 for (y = ymin; y < ymax; y++) {
1334 for (x = xmin; x < xmax; x++) {
1338 p.set(min(1.0f - ((1.0f - c[0]) * pixel_scale), o[0]),
1339 min(1.0f - ((1.0f - c[1]) * pixel_scale), o[1]),
1340 min(1.0f - ((1.0f - c[2]) * pixel_scale), o[2]));
1346 for (y = ymin; y < ymax; y++) {
1347 for (x = xmin; x < xmax; x++) {
1348 float c = copy.
get_alpha(x - xmin + xfrom, y - ymin + yfrom);
1350 set_alpha(x, y, min(1.0f - ((1.0f - c) * pixel_scale), o));
1371 int xfrom,
int yfrom,
int x_size,
int y_size,
1372 float pixel_scale) {
1373 int xmin, ymin, xmax, ymax;
1374 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1375 xmin, ymin, xmax, ymax);
1381 for (y = ymin; y < ymax; y++) {
1382 for (x = xmin; x < xmax; x++) {
1386 PPM_ASSIGN(p, max(c.r, o.r), max(c.g, o.g), max(c.b, o.b));
1392 for (y = ymin; y < ymax; y++) {
1393 for (x = xmin; x < xmax; x++) {
1394 xelval c = copy.
get_alpha_val(x - xmin + xfrom, y - ymin + yfrom);
1404 for (y = ymin; y < ymax; y++) {
1405 for (x = xmin; x < xmax; x++) {
1409 p.set(max(c[0] * pixel_scale, o[0]),
1410 max(c[1] * pixel_scale, o[1]),
1411 max(c[2] * pixel_scale, o[2]));
1417 for (y = ymin; y < ymax; y++) {
1418 for (x = xmin; x < xmax; x++) {
1419 float c = copy.
get_alpha(x - xmin + xfrom, y - ymin + yfrom);
1421 set_alpha(x, y, max(c * pixel_scale, o));
1456 xelval threshold_val = select_image.
to_val(threshold);
1463 xelval lt_alpha = 0;
1470 (xelval)(PPM_GETR(lt_val) * scale + 0.5),
1471 (xelval)(PPM_GETG(lt_val) * scale + 0.5),
1472 (xelval)(PPM_GETB(lt_val) * scale + 0.5));
1473 lt_alpha = (xelval)(lt_alpha * scale + 0.5);
1477 xelval ge_alpha = 0;
1484 (xelval)(PPM_GETR(ge_val) * scale + 0.5),
1485 (xelval)(PPM_GETG(ge_val) * scale + 0.5),
1486 (xelval)(PPM_GETB(ge_val) * scale + 0.5));
1487 ge_alpha = (xelval)(ge_alpha * scale + 0.5);
1675 nassertv(radius <= PNM_MAXMAXVAL);
1677 dist.fill_val(radius);
1679 xelval threshold_val = mask.
to_val(threshold);
1681 for (
int yi = 0; yi < mask.
get_y_size(); ++yi) {
1682 for (
int xi = 0; xi < mask.
get_x_size(); ++xi) {
1684 dist.do_fill_distance(xi, yi, 0);
1689 if (shrink_from_border) {
1691 for (
int yi = 0; yi < mask.
get_y_size(); ++yi) {
1692 dist.do_fill_distance(0, yi, 1);
1693 dist.do_fill_distance(mask.
get_x_size() - 1, yi, 1);
1695 for (
int xi = 0; xi < mask.
get_x_size(); ++xi) {
1696 dist.do_fill_distance(xi, 0, 1);
1697 dist.do_fill_distance(xi, mask.
get_y_size() - 1, 1);
1725 nassertv(radius <= PNM_MAXMAXVAL);
1727 dist.fill_val(radius);
1729 xelval threshold_val = mask.
to_val(threshold);
1731 for (
int yi = 0; yi < mask.
get_y_size(); ++yi) {
1732 for (
int xi = 0; xi < mask.
get_x_size(); ++xi) {
1734 dist.do_fill_distance(xi, yi, 0);
1753 float scale = max_val - min_val;
1755 if (_num_channels <= 2) {
1760 set_gray(x, y, (val - min_val) / scale);
1769 (xel[0] - min_val) / scale,
1770 (xel[1] - min_val) / scale,
1771 (xel[2] - min_val) / scale);
1786 int xfrom,
int yfrom,
int cfrom,
1787 int x_size,
int y_size) {
1788 int xmin, ymin, xmax, ymax;
1789 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1790 xmin, ymin, xmax, ymax);
1796 for (y = ymin; y < ymax; y++) {
1797 if (cto == 3 && cfrom == 3) {
1799 for (x = xmin; x < xmax; x++) {
1802 }
else if (cto == 3 && cfrom == 0) {
1804 for (x = xmin; x < xmax; x++) {
1807 }
else if (cto == 0 && cfrom == 3) {
1809 for (x = xmin; x < xmax; x++) {
1814 for (x = xmin; x < xmax; x++) {
1823 for (y = ymin; y < ymax; y++) {
1824 for (x = xmin; x < xmax; x++) {
1847 float min_radius,
float max_radius) {
1848 if (_x_size == 0 || _y_size == 0) {
1852 float x_scale = 2.0 / _x_size;
1853 float y_scale = 2.0 / _y_size;
1857 int x_center0 = _x_size / 2;
1858 int y_center0 = _y_size / 2;
1859 int x_center1 = (_x_size + 1) / 2;
1860 int y_center1 = (_y_size + 1) / 2;
1862 float min_r2 = min_radius * min_radius;
1863 float max_r2 = max_radius * max_radius;
1865 for (
int yi = 0; yi < y_center1; ++yi) {
1866 float y = yi * y_scale;
1867 float y2_inner = y * y;
1868 float y2_outer = (y + y_scale) * (y + y_scale);
1869 for (
int xi = 0; xi < x_center1; ++xi) {
1870 float x = xi * x_scale;
1871 float d2_inner = (x * x + y2_inner);
1872 float d2_outer = ((x + x_scale) * (x + x_scale) + y2_outer);
1873 float d2_a = ((x + x_scale) * (x + x_scale) + y2_inner);
1874 float d2_b = (x * x + y2_outer);
1876 if ((d2_inner <= min_r2) &&
1877 (d2_outer <= min_r2) &&
1881 set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, fg);
1882 set_xel_a(x_center0 + xi, y_center1 - 1 - yi, fg);
1883 set_xel_a(x_center1 - 1 - xi, y_center0 + yi, fg);
1884 set_xel_a(x_center0 + xi, y_center0 + yi, fg);
1886 }
else if ((d2_inner > max_r2) &&
1887 (d2_outer > max_r2) &&
1891 set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, bg);
1892 set_xel_a(x_center0 + xi, y_center1 - 1 - yi, bg);
1893 set_xel_a(x_center1 - 1 - xi, y_center0 + yi, bg);
1894 set_xel_a(x_center0 + xi, y_center0 + yi, bg);
1898 LColorf c_outer, c_inner, c_a, c_b;
1899 compute_spot_pixel(c_outer, d2_outer, min_radius, max_radius, fg, bg);
1900 compute_spot_pixel(c_inner, d2_inner, min_radius, max_radius, fg, bg);
1901 compute_spot_pixel(c_a, d2_a, min_radius, max_radius, fg, bg);
1902 compute_spot_pixel(c_b, d2_b, min_radius, max_radius, fg, bg);
1906 c = (c_outer + c_inner + c_a + c_b) * 0.25;
1908 set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, c);
1909 set_xel_a(x_center0 + xi, y_center1 - 1 - yi, c);
1910 set_xel_a(x_center1 - 1 - xi, y_center0 + yi, c);
1911 set_xel_a(x_center0 + xi, y_center0 + yi, c);
1934 new_image.
fill(color[0], color[1], color[2]);
1981 int num_pixels = _x_size * _y_size;
1983 compute_histogram(hist_map, _array, _alpha);
1985 pixels.reserve(hist_map.size());
1986 HistMap::const_iterator hi;
1987 for (hi = hist_map.begin(); hi != hist_map.end(); ++hi) {
1988 if ((*hi).second <= num_pixels) {
1992 ::sort(pixels.begin(), pixels.end());
1994 histogram.
swap(pixels, hist_map);
2011 PerlinNoise2 perlin (sx * _x_size, sy * _y_size, table_size, seed);
2012 for (x = 0; x < _x_size; ++x) {
2013 for (y = 0; y < _y_size; ++y) {
2014 noise = perlin.
noise(x, y);
2015 set_xel(x, y, 0.5 * (noise + 1.0));
2030 for (x = 0; x < _x_size; ++x) {
2031 for (y = 0; y < _y_size; ++y) {
2032 noise = perlin.
noise(x / (
float) _x_size, y / (
float) _y_size);
2033 set_xel(x, y, 0.5 * (noise + 1.0));
2048 nassertv((nchannels >= 3) && (nchannels <= 4));
2053 set_xel(x, y, outv[0], outv[1], outv[2]);
2070 float alpha_exponent) {
2071 int num_channels = _num_channels;
2072 if (
has_alpha() && alpha_exponent == 1.0f) {
2079 if (red_exponent == 1.0f && green_exponent == 1.0f && blue_exponent == 1.0f) {
2081 switch (num_channels) {
2088 for (y = 0; y < _y_size; ++y) {
2089 for (x = 0; x < _x_size; ++x) {
2091 alpha = cpow(alpha, blue_exponent);
2101 switch (num_channels) {
2103 for (y = 0; y < _y_size; ++y) {
2104 for (x = 0; x < _x_size; ++x) {
2106 gray = cpow(gray, blue_exponent);
2113 for (y = 0; y < _y_size; ++y) {
2114 for (x = 0; x < _x_size; ++x) {
2116 gray = cpow(gray, blue_exponent);
2120 alpha = cpow(alpha, blue_exponent);
2127 for (y = 0; y < _y_size; ++y) {
2128 for (x = 0; x < _x_size; ++x) {
2130 color[0] = cpow(color[0], red_exponent);
2131 color[1] = cpow(color[1], green_exponent);
2132 color[2] = cpow(color[2], blue_exponent);
2139 for (y = 0; y < _y_size; ++y) {
2140 for (x = 0; x < _x_size; ++x) {
2142 color[0] = cpow(color[0], red_exponent);
2143 color[1] = cpow(color[1], green_exponent);
2144 color[2] = cpow(color[2], blue_exponent);
2145 color[3] = cpow(color[3], alpha_exponent);
2169 _default_rc = lumin_red;
2170 _default_gc = lumin_grn;
2171 _default_bc = lumin_blu;
2190 _inv_maxval = 1.0f / (float)_maxval;
2194 switch (_color_space) {
2196 _xel_encoding = XE_generic_alpha;
2201 if (has_sse2_sRGB_encode()) {
2202 _xel_encoding = XE_uchar_sRGB_alpha_sse2;
2204 _xel_encoding = XE_uchar_sRGB_alpha;
2207 _xel_encoding = XE_generic_sRGB_alpha;
2212 _xel_encoding = XE_scRGB_alpha;
2221 switch (_color_space) {
2223 _xel_encoding = XE_generic;
2228 if (has_sse2_sRGB_encode()) {
2229 _xel_encoding = XE_uchar_sRGB_sse2;
2231 _xel_encoding = XE_uchar_sRGB;
2234 _xel_encoding = XE_generic_sRGB;
2239 _xel_encoding = XE_scRGB;
2282 if (_x_size == 0 || _y_size == 0) {
2286 float factor = 1.0f / (float)(_x_size * _y_size);
2289 for (x = 0; x < _x_size; ++x) {
2290 for (y = 0; y < _y_size; ++y) {
2291 color +=
get_xel(x, y) * factor;
2307 if (_x_size == 0 || _y_size == 0) {
2311 float factor = 1.0f / (float)(_x_size * _y_size);
2314 for (x = 0; x < _x_size; ++x) {
2315 for (y = 0; y < _y_size; ++y) {
2332 if (_x_size == 0 || _y_size == 0) {
2337 for (x = 0; x < _x_size; ++x) {
2338 for (y = 0; y < _y_size; ++y) {
2343 gray /= (float)(_x_size * _y_size);
2357 size_t array_size = _x_size * _y_size;
2359 if (_array != NULL && _alpha != NULL) {
2360 for (
size_t i = 0; i < array_size; ++i) {
2361 target._array[i].r = _maxval - _array[i].r;
2362 target._array[i].g = _maxval - _array[i].g;
2363 target._array[i].b = _maxval - _array[i].b;
2364 target._alpha[i] = _maxval - _alpha[i];
2366 }
else if (_array != NULL) {
2367 for (
size_t i = 0; i < array_size; ++i) {
2368 target._array[i].r = _maxval - _array[i].r;
2369 target._array[i].g = _maxval - _array[i].g;
2370 target._array[i].b = _maxval - _array[i].b;
2372 }
else if (_alpha != NULL) {
2373 for (
size_t i = 0; i < array_size; ++i) {
2374 target._alpha[i] = _maxval - _alpha[i];
2390 nassertv(_x_size == other._x_size && _y_size == other._y_size);
2395 size_t array_size = _x_size * _y_size;
2398 if (_alpha != NULL && other._alpha != NULL) {
2399 for (
size_t i = 0; i < array_size; ++i) {
2400 _array[i].r =
clamp_val((
int)_array[i].r + (
int)other._array[i].r);
2401 _array[i].g =
clamp_val((
int)_array[i].g + (
int)other._array[i].g);
2402 _array[i].b =
clamp_val((
int)_array[i].b + (
int)other._array[i].b);
2403 _alpha[i] =
clamp_val((
int)_alpha[i] + (
int)other._alpha[i]);
2406 for (
size_t i = 0; i < array_size; ++i) {
2407 _array[i].r =
clamp_val((
int)_array[i].r + (
int)other._array[i].r);
2408 _array[i].g =
clamp_val((
int)_array[i].g + (
int)other._array[i].g);
2409 _array[i].b =
clamp_val((
int)_array[i].b + (
int)other._array[i].b);
2415 for (x = 0; x < _x_size; ++x) {
2416 for (y = 0; y < _y_size; ++y) {
2433 size_t array_size = _x_size * _y_size;
2436 int add_r = (int)(other.get_x() *
get_maxval() + 0.5);
2437 int add_g = (int)(other.get_y() *
get_maxval() + 0.5);
2438 int add_b = (int)(other.get_z() *
get_maxval() + 0.5);
2439 int add_a = (int)(other.get_w() *
get_maxval() + 0.5);
2441 if (_alpha != NULL) {
2442 for (
size_t i = 0; i < array_size; ++i) {
2443 _array[i].r =
clamp_val((
int)_array[i].r + add_r);
2444 _array[i].g =
clamp_val((
int)_array[i].g + add_g);
2445 _array[i].b =
clamp_val((
int)_array[i].b + add_b);
2446 _alpha[i] =
clamp_val((
int)_alpha[i] + add_a);
2450 for (
size_t i = 0; i < array_size; ++i) {
2451 _array[i].r =
clamp_val((
int)_array[i].r + add_r);
2452 _array[i].g =
clamp_val((
int)_array[i].g + add_g);
2453 _array[i].b =
clamp_val((
int)_array[i].b + add_b);
2459 for (x = 0; x < _x_size; ++x) {
2460 for (y = 0; y < _y_size; ++y) {
2477 nassertv(_x_size == other._x_size && _y_size == other._y_size);
2482 size_t array_size = _x_size * _y_size;
2485 if (_alpha != NULL && other._alpha != NULL) {
2486 for (
size_t i = 0; i < array_size; ++i) {
2487 _array[i].r =
clamp_val((
int)_array[i].r - (
int)other._array[i].r);
2488 _array[i].g =
clamp_val((
int)_array[i].g - (
int)other._array[i].g);
2489 _array[i].b =
clamp_val((
int)_array[i].b - (
int)other._array[i].b);
2490 _alpha[i] =
clamp_val((
int)_alpha[i] - (
int)other._alpha[i]);
2493 for (
size_t i = 0; i < array_size; ++i) {
2494 _array[i].r =
clamp_val((
int)_array[i].r - (
int)other._array[i].r);
2495 _array[i].g =
clamp_val((
int)_array[i].g - (
int)other._array[i].g);
2496 _array[i].b =
clamp_val((
int)_array[i].b - (
int)other._array[i].b);
2502 for (x = 0; x < _x_size; ++x) {
2503 for (y = 0; y < _y_size; ++y) {
2533 nassertv(_x_size == other._x_size && _y_size == other._y_size);
2536 for (x = 0; x < _x_size; ++x) {
2537 for (y = 0; y < _y_size; ++y) {
2555 size_t array_size = _x_size * _y_size;
2557 if (_alpha != NULL) {
2558 for (
size_t i = 0; i < array_size; ++i) {
2559 _array[i].r =
clamp_val((
int)(_array[i].r * multiplier + 0.5f));
2560 _array[i].g =
clamp_val((
int)(_array[i].g * multiplier + 0.5f));
2561 _array[i].b =
clamp_val((
int)(_array[i].b * multiplier + 0.5f));
2562 _alpha[i] =
clamp_val((
int)(_alpha[i] * multiplier + 0.5f));
2566 for (
size_t i = 0; i < array_size; ++i) {
2567 _array[i].r =
clamp_val((
int)(_array[i].r * multiplier + 0.5f));
2568 _array[i].g =
clamp_val((
int)(_array[i].g * multiplier + 0.5f));
2569 _array[i].b =
clamp_val((
int)(_array[i].b * multiplier + 0.5f));
2575 for (x = 0; x < _x_size; ++x) {
2576 for (y = 0; y < _y_size; ++y) {
2594 size_t array_size = _x_size * _y_size;
2596 if (_alpha != NULL) {
2597 for (
size_t i = 0; i < array_size; ++i) {
2598 _array[i].r =
clamp_val((
int)(_array[i].r * other[0] + 0.5f));
2599 _array[i].g =
clamp_val((
int)(_array[i].g * other[1] + 0.5f));
2600 _array[i].b =
clamp_val((
int)(_array[i].b * other[2] + 0.5f));
2601 _alpha[i] =
clamp_val((
int)(_alpha[i] * other[3] + 0.5f));
2605 for (
size_t i = 0; i < array_size; ++i) {
2606 _array[i].r =
clamp_val((
int)(_array[i].r * other[0] + 0.5f));
2607 _array[i].g =
clamp_val((
int)(_array[i].g * other[1] + 0.5f));
2608 _array[i].b =
clamp_val((
int)(_array[i].b * other[2] + 0.5f));
2614 for (x = 0; x < _x_size; ++x) {
2615 for (y = 0; y < _y_size; ++y) {
2617 color.componentwise_mult(other);
LRGBColorf get_average_xel() const
Returns the average color of all of the pixels in the image.
xelval clamp_val(int input_value) const
A handy function to clamp values to [0..get_maxval()].
void set_gray_val(int x, int y, xelval gray)
Sets the gray component color at the indicated pixel.
void remix_channels(const LMatrix4 &conv)
Transforms every pixel using the operation (Ro,Go,Bo) = conv.xform_point(Ri,Gi,Bi); Input must be a c...
void set_pixel(int x, int y, const PixelSpec &pixel)
Sets the (r, g, b, a) pixel value at the indicated pixel, using a PixelSpec object.
double noise(double x, double y)
Returns the noise function of the three inputs.
void set_alpha_array(xelval *alpha)
Replaces the underlying PNMImage alpha array with the indicated pointer.
void set_channel_val(int x, int y, int channel, xelval value)
Sets the nth component color at the indicated pixel.
virtual bool supports_grayscale() const
Returns true if this particular PNMWriter understands grayscale images.
void rescale(float min_val, float max_val)
Rescales the RGB channel values so that any values in the original image between min_val and max_val ...
This is the base class for all three-component vectors and points.
void set_green(int x, int y, float g)
Sets the green component color only at the indicated pixel.
void copy_header_from(const PNMImageHeader &header)
Initializes all the data in the header (x_size, y_size, num_channels, etc.) to the same values indica...
bool write(const Filename &filename, PNMFileType *type=NULL) const
Writes the image to the indicated filename.
LColorf get_average_xel_a() const
Returns the average color of all of the pixels in the image, including the alpha channel.
void copy_sub_image(const PNMImage ©, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1)
Copies a rectangular area of another image into a rectangular area of this image. ...
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
void set_channel(int x, int y, int channel, float value)
Sets the nth component color at the indicated pixel.
bool is_valid() const
Returns true if the image has been read in or correctly initialized with a height and width...
void set_read_size(int x_size, int y_size)
Instructs the reader to attempt to scale the image to the indicated size while reading it...
void blend(int x, int y, const LRGBColorf &val, float alpha)
Smoothly blends the indicated pixel value in with whatever was already in the image, based on the given alpha value.
virtual int read_data(xel *array, xelval *alpha)
Reads in an entire image all at once, storing it in the pre-allocated _x_size * _y_size array and alp...
void blend_sub_image(const PNMImage ©, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1, float pixel_scale=1.0)
Behaves like copy_sub_image(), except the alpha channel of the copy is used to blend the copy into th...
void alpha_fill(float alpha=0.0)
Sets the entire alpha channel to the given level.
xelval to_val(float input_value) const
A handy function to scale non-alpha values from [0..1] to [0..get_maxval()].
LColorf get_xel_a(int x, int y) const
Returns the RGBA color at the indicated pixel.
void set_green_val(int x, int y, xelval g)
Sets the green component color only at the indicated pixel.
float get_red(int x, int y) const
Returns the red component color at the indicated pixel.
bool store(PNMImage &pnmimage) const
Copies the data to the indicated PNMImage, converting to RGB values.
void apply_exponent(float gray_exponent)
Adjusts each channel of the image by raising the corresponding component value to the indicated expon...
float get_blue(int x, int y) const
Returns the blue component color at the indicated pixel.
float get_bright(int x, int y) const
Returns the linear brightness of the given xel, as a linearized float in the range 0...
virtual bool write_pfm(const PfmFile &pfm)
Writes floating-point data from the indicated PfmFile.
PNMImage operator~() const
Returns a new PNMImage that is the complement of this PNMImage.
bool read(const Filename &filename, PNMFileType *type=NULL, bool report_unknown_type=true)
Reads the indicated image filename.
PixelSpec get_pixel(int x, int y) const
Returns the (r, g, b, a) pixel value at the indicated pixel, using a PixelSpec object.
virtual bool is_floating_point()
Returns true if this PNMFileType represents a floating-point image type, false if it is a normal...
void set_xel_val(int x, int y, const xel &value)
Changes the RGB color at the indicated pixel.
xelval get_blue_val(int x, int y) const
Returns the blue component color at the indicated pixel.
void perlin_noise_fill(float sx, float sy, int table_size=256, unsigned long seed=0)
Fills the image with a grayscale perlin noise pattern based on the indicated parameters.
This is the base class of a family of classes that represent particular image file types that PNMImag...
float get_gray(int x, int y) const
Returns the gray component color at the indicated pixel.
void add_sub_image(const PNMImage ©, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1, float pixel_scale=1.0)
Behaves like copy_sub_image(), except the copy pixels are added to the pixels of the destination...
void set_color_type(ColorType color_type)
Translates the image to or from grayscale, color, or four-color mode.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
double noise(double x, double y) const
Returns the noise function of the three inputs.
float get_average_gray() const
Returns the average grayscale component of all of the pixels in the image.
float get_channel(int x, int y, int channel) const
Returns the nth component color at the indicated pixel.
void set_red(int x, int y, float r)
Sets the red component color only at the indicated pixel.
static const LVecBase3f & zero()
Returns a zero-length vector.
void flip(bool flip_x, bool flip_y, bool transpose)
Reverses, transposes, and/or rotates the image in-place according to the specified parameters...
float get_alpha(int x, int y) const
Returns the alpha component color at the indicated pixel.
void set_color_space(ColorSpace color_space)
Converts the colors in the image to the indicated color space.
void make_histogram(Histogram &hist)
Computes a histogram of the colors used in the image.
void fill_distance_outside(const PNMImage &mask, float threshold, int radius)
Replaces this image with a grayscale image whose gray channel represents the linear Manhattan distanc...
void quick_filter_from(const PNMImage ©, int xborder=0, int yborder=0)
Resizes from the given image, with a fixed radius of 0.5.
virtual bool read_pfm(PfmFile &pfm)
Reads floating-point data directly into the indicated PfmFile.
xel & get_xel_val(int x, int y)
Returns the RGB color at the indicated pixel.
xelval get_green_val(int x, int y) const
Returns the green component color at the indicated pixel.
This class provides an implementation of Perlin noise for 2 variables.
void copy_channel(const PNMImage ©, int src_channel, int dest_channel)
Copies a channel from one image into another.
float get_green(int x, int y) const
Returns the green component color at the indicated pixel.
Implements a multi-layer PerlinNoise, with one or more high-frequency noise functions added to a lowe...
void expand_border(int left, int right, int bottom, int top, const LColorf &color)
Expands the image by the indicated number of pixels on each edge.
void operator-=(const PNMImage &other)
Subtracts each pixel from the right image from each pixel value in this image.
The name of a file, such as a texture file or an Egg file.
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component, or with a special extension, 2- or 4-component.
void lighten_sub_image(const PNMImage ©, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1, float pixel_scale=1.0)
Behaves like copy_sub_image(), but the resulting color will be the lighter of the source and destinat...
void set_blue_val(int x, int y, xelval b)
Sets the blue component color only at the indicated pixel.
This is a 4-by-4 transform matrix.
void do_fill_distance(int xi, int yi, int d)
Recursively fills in the minimum distance measured from a certain set of points into the gray channel...
void set_gray(int x, int y, float gray)
Sets the gray component color at the indicated pixel.
void copy_header_from(const PNMImageHeader &header)
Copies just the header information into this image.
void set_blue(int x, int y, float b)
Sets the blue component color only at the indicated pixel.
void fill_distance_inside(const PNMImage &mask, float threshold, int radius, bool shrink_from_border)
Replaces this image with a grayscale image whose gray channel represents the linear Manhattan distanc...
bool is_valid() const
Returns true if the PNMReader can be used to read data, false if something is wrong.
void set_xel_a(int x, int y, const LColorf &value)
Changes the RGBA color at the indicated pixel.
virtual void prepare_read()
This method will be called before read_data() or read_row() is called.
xelval get_channel_val(int x, int y, int channel) const
Returns the nth component color at the indicated pixel.
void threshold(const PNMImage &select_image, int channel, float threshold, const PNMImage <, const PNMImage &ge)
Selectively copies each pixel from either one source or another source, depending on the pixel value ...
void darken_sub_image(const PNMImage ©, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1, float pixel_scale=1.0)
Behaves like copy_sub_image(), but the resulting color will be the darker of the source and destinati...
void alpha_fill_val(xelval alpha=0)
Sets the entire alpha channel to the given level.
void mult_sub_image(const PNMImage ©, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1, float pixel_scale=1.0)
Behaves like copy_sub_image(), except the copy pixels are multiplied to the pixels of the destination...
This is an abstract base class that defines the interface for reading image files of various types...
This is an abstract base class that defines the interface for writing image files of various types...
ColorSpace get_color_space() const
Returns the color space in which the image is encoded.
void operator+=(const PNMImage &other)
Sets each pixel value to the sum of the corresponding pixel values in the two given images...
xelval get_alpha_val(int x, int y) const
Returns the alpha component color at the indicated pixel.
void set_array(xel *array)
Replaces the underlying PNMImage array with the indicated pointer.
bool has_read_size() const
Returns true if set_read_size() has been called.
void unfiltered_stretch_from(const PNMImage ©)
Resizes from the indicated image into this one by performing a nearest-point sample.
bool load(const PNMImage &pnmimage)
Fills the PfmFile with the data from the indicated PNMImage, converted to floating-point values...
This is the base class for all three-component vectors and points.
virtual int write_data(xel *array, xelval *alpha)
Writes out an entire image all at once, including the header, based on the image data stored in the g...
void add_alpha()
Adds an alpha channel to the image, if it does not already have one.
void set_red_val(int x, int y, xelval r)
Sets the red component color only at the indicated pixel.
void clear()
Frees all memory allocated for the image, and clears all its parameters (size, color, type, etc).
void set_alpha(int x, int y, float a)
Sets the alpha component color only at the indicated pixel.
void take_from(PNMImage &orig)
Move the contents of the other image into this one, and empty the other image.
void render_spot(const LColorf &fg, const LColorf &bg, float min_radius, float max_radius)
Renders a solid-color circle, with a fuzzy edge, into the center of the PNMImage. ...
void copy_from(const PNMImage ©)
Makes this image become a copy of the other image.
void set_alpha_val(int x, int y, xelval a)
Sets the alpha component color only at the indicated pixel.
xelval get_red_val(int x, int y) const
Returns the red component color at the indicated pixel.
LRGBColorf get_xel(int x, int y) const
Returns the RGB color at the indicated pixel.
void set_maxval(xelval maxval)
Rescales the image to the indicated maxval.
void unpremultiply_alpha()
Converts an image in-place to its "straight alpha" form (presumably from a "premultiplied" form)...
void reverse_rows()
Performs an in-place reversal of the row (y) data.
void fill(float red, float green, float blue)
Sets the entire image (except the alpha channel) to the given color.
void make_grayscale()
Converts the image from RGB to grayscale.
virtual bool supports_integer()
Returns true if this PNMFileType can accept an integer image type, false if it can only accept a floa...
void set_xel(int x, int y, const LRGBColorf &value)
Changes the RGB color at the indicated pixel.
void operator*=(const PNMImage &other)
Multiples each pixel in this image by each pixel value from the right image.
void fill_val(xelval red, xelval green, xelval blue)
Sets the entire image (except the alpha channel) to the given color.
LVecBase3f xform_point(const LVecBase3f &v) const
The matrix transforms a 3-component point (including translation component) and returns the result...
xelval get_gray_val(int x, int y) const
Returns the gray component color at the indicated pixel.
static const LVecBase4f & zero()
Returns a zero-length vector.
void premultiply_alpha()
Converts an image in-place to its "premultiplied" form, where, for every pixel in the image...