34 _has_read_size =
false;
36 bool result =
read(filename, type);
39 <<
"Could not read image " << filename <<
"\n";
49 if (_array !=
nullptr) {
50 PANDA_FREE_ARRAY(_array);
53 if (_alpha !=
nullptr) {
54 PANDA_FREE_ARRAY(_alpha);
61 _inv_maxval = 1.0 / 255.0;
62 _color_space = CS_linear;
65 _has_read_size =
false;
66 _xel_encoding = XE_generic;
74 clear(
int x_size,
int y_size,
int num_channels,
75 xelval maxval,
PNMFileType *type, ColorSpace color_space) {
77 nassertv(num_channels >= 1 && num_channels <= 4);
78 nassertv(color_space != CS_unspecified);
82 _num_channels = num_channels;
84 _color_space = color_space;
87 _has_read_size =
false;
91 memset(_alpha, 0,
sizeof(xelval) * _y_size * _x_size);
95 memset(_array, 0,
sizeof(
xel) * _y_size * _x_size);
111 memcpy(_alpha, copy._alpha,
sizeof(xelval) * _y_size * _x_size);
113 memcpy(_array, copy._array,
sizeof(
xel) * _y_size * _x_size);
123 nassertv(src_channel >= 0 && src_channel <= 3);
124 nassertv(dest_channel >= 0 && dest_channel <= 3);
127 pnmimage_cat.error() <<
"One of the images is invalid!\n";
132 pnmimage_cat.error() <<
"Image size doesn't match!\n";
136 for (
int x = 0; x < _x_size; x++) {
137 for (
int y = 0; y < _y_size; y++) {
140 t.set_cell(dest_channel, o.get_cell(src_channel));
156 nassertv(src_channel >= 0 && src_channel <= 3);
157 nassertv(dest_channel >= 0 && dest_channel <= 3);
160 pnmimage_cat.error() <<
"One of the images is invalid!\n";
165 pnmimage_cat.error() <<
"Image size doesn't match!\n";
170 if (right_shift >= 0) {
171 xelval dest_mask = ~(src_mask >> right_shift);
172 for (
int x = 0; x < _x_size; x++) {
173 for (
int y = 0; y < _y_size; y++) {
176 dest = (dest & dest_mask) | ((src & src_mask) >> right_shift);
181 int left_shift = -right_shift;
182 xelval dest_mask = ~(src_mask << left_shift);
183 for (
int x = 0; x < _x_size; x++) {
184 for (
int y = 0; y < _y_size; y++) {
187 dest = (dest & dest_mask) | ((src & src_mask) << left_shift);
202 PNMImageHeader::operator = (header);
207 _inv_maxval = 1.0f / (float)_maxval;
226 PNMImageHeader::operator = (orig);
231 _alpha = orig._alpha;
232 orig._alpha =
nullptr;
234 _array = orig._array;
235 orig._array =
nullptr;
280 if (reader ==
nullptr) {
302 bool report_unknown_type) {
304 (&data,
false, filename, std::string(), type, report_unknown_type);
305 if (reader ==
nullptr) {
323 int read_x_size = _read_x_size;
324 int read_y_size = _read_y_size;
328 if (reader ==
nullptr) {
352 return pfm.
store(*
this);
357 _y_size = reader->
read_data(_array, _alpha);
368 if (
has_read_size && (_x_size != read_x_size || _y_size != read_y_size)) {
391 if (writer ==
nullptr) {
395 return write(writer);
414 (&data,
false, filename, type);
415 if (writer ==
nullptr) {
419 return write(writer);
431 if (writer ==
nullptr) {
446 if (!pfm.
load(*
this)) {
464 int result = writer->
write_data(_array, _alpha);
467 return (result == _y_size);
479 nassertv((
int)color_type >= 1 && (
int)color_type <= 4);
503 if (_alpha !=
nullptr) {
504 PANDA_FREE_ARRAY(_alpha);
511 memset(_alpha, 0,
sizeof(xelval) * (_x_size * _y_size));
514 _num_channels = (int)color_type;
535 nassertv(color_space != CS_unspecified);
537 if (color_space == _color_space) {
541 if (_array !=
nullptr) {
542 size_t array_size = _x_size * _y_size;
545 switch (color_space) {
547 if (_maxval == 255 && _color_space == CS_sRGB) {
548 for (
size_t i = 0; i < array_size; ++i) {
549 xel &col = _array[i];
555 for (
int x = 0; x < _x_size; ++x) {
556 for (
int y = 0; y < _y_size; ++y) {
557 LRGBColorf scaled =
get_xel(x, y) * _maxval + 0.5f;
558 xel &col = row(y)[x];
568 if (_maxval == 255 && _color_space == CS_linear) {
569 for (
size_t i = 0; i < array_size; ++i) {
570 xel &col = _array[i];
576 for (
int x = 0; x < _x_size; ++x) {
577 for (
int y = 0; y < _y_size; ++y) {
578 xel &col = row(y)[x];
586 for (
int x = 0; x < _x_size; ++x) {
587 for (
int y = 0; y < _y_size; ++y) {
588 LRGBColorf scaled =
get_xel(x, y) * 8192.f + 4096.5f;
589 xel &col = row(y)[x];
590 col.r = min(max(0, (
int)scaled[0]), 65535);
591 col.g = min(max(0, (
int)scaled[1]), 65535);
592 col.b = min(max(0, (
int)scaled[2]), 65535);
599 nassert_raise(
"invalid color space");
604 _color_space = color_space;
647 float r =
get_red(x, y) * alpha;
672 float r =
get_red(x, y) / alpha;
686 if (_array !=
nullptr) {
687 xel *new_array = (
xel *)PANDA_MALLOC_ARRAY(_x_size * _y_size *
sizeof(
xel));
688 for (
int y = 0; y < _y_size; y++) {
689 int new_y = _y_size - 1 - y;
690 memcpy(new_array + new_y * _x_size, _array + y * _x_size, _x_size *
sizeof(
xel));
692 PANDA_FREE_ARRAY(_array);
696 if (_alpha !=
nullptr) {
697 xelval *new_alpha = (xelval *)PANDA_MALLOC_ARRAY(_x_size * _y_size *
sizeof(xelval));
698 for (
int y = 0; y < _y_size; y++) {
699 int new_y = _y_size - 1 - y;
700 memcpy(new_alpha + new_y * _x_size, _alpha + y * _x_size, _x_size *
sizeof(xelval));
702 PANDA_FREE_ARRAY(_alpha);
715 flip(
bool flip_x,
bool flip_y,
bool transpose) {
718 if (_array !=
nullptr) {
719 xel *new_array = (
xel *)PANDA_MALLOC_ARRAY(_x_size * _y_size *
sizeof(
xel));
720 for (
int xi = 0; xi < _x_size; ++xi) {
721 xel *row = new_array + xi * _y_size;
722 int source_xi = !flip_x ? xi : _x_size - 1 - xi;
723 for (
int yi = 0; yi < _y_size; ++yi) {
724 int source_yi = !flip_y ? yi : _y_size - 1 - yi;
725 xel *source_row = _array + source_yi * _x_size;
726 row[yi] = source_row[source_xi];
729 PANDA_FREE_ARRAY(_array);
733 if (_alpha !=
nullptr) {
734 xelval *new_alpha = (xelval *)PANDA_MALLOC_ARRAY(_x_size * _y_size *
sizeof(xelval));
735 for (
int xi = 0; xi < _x_size; ++xi) {
736 xelval *row = new_alpha + xi * _y_size;
737 int source_xi = !flip_x ? xi : _x_size - 1 - xi;
738 for (
int yi = 0; yi < _y_size; ++yi) {
739 int source_yi = !flip_y ? yi : _y_size - 1 - yi;
740 xelval *source_row = _alpha + source_yi * _x_size;
741 row[yi] = source_row[source_xi];
745 PANDA_FREE_ARRAY(_alpha);
755 if (_array !=
nullptr) {
756 xel *new_array = (
xel *)PANDA_MALLOC_ARRAY(_x_size * _y_size *
sizeof(
xel));
757 for (
int yi = 0; yi < _y_size; ++yi) {
758 xel *row = new_array + yi * _x_size;
759 int source_yi = !flip_y ? yi : _y_size - 1 - yi;
760 xel *source_row = _array + source_yi * _x_size;
762 for (
int xi = 0; xi < _x_size; ++xi) {
763 int source_xi = !flip_x ? xi : _x_size - 1 - xi;
764 row[xi] = source_row[source_xi];
767 PANDA_FREE_ARRAY(_array);
771 if (_alpha !=
nullptr) {
772 xelval *new_alpha = (xelval *)PANDA_MALLOC_ARRAY(_x_size * _y_size *
sizeof(xelval));
773 for (
int yi = 0; yi < _y_size; ++yi) {
774 xelval *row = new_alpha + yi * _x_size;
775 int source_yi = !flip_y ? yi : _y_size - 1 - yi;
776 xelval *source_row = _alpha + source_yi * _x_size;
778 for (
int xi = 0; xi < _x_size; ++xi) {
779 int source_xi = !flip_x ? xi : _x_size - 1 - xi;
780 row[xi] = source_row[source_xi];
784 PANDA_FREE_ARRAY(_alpha);
795 nassertv(maxval > 0);
797 if (maxval != _maxval) {
798 float ratio = (float)maxval / (
float)_maxval;
853 <<
"Invalid request for channel " << channel <<
" in " 855 nassert_raise(
"unexpected channel count");
875 if (_num_channels == 2) {
891 nassert_raise(
"unexpected channel count");
920 <<
"Invalid request for channel " << channel <<
" in " 922 nassert_raise(
"unexpected channel count");
942 if (_num_channels == 2) {
958 nassert_raise(
"unexpected channel count");
969 switch (_num_channels) {
992 if (_alpha !=
nullptr) {
1004 blend(
int x,
int y,
float r,
float g,
float b,
float alpha) {
1012 }
else if (alpha > 0.0f) {
1016 if (prev_alpha == 0.0f) {
1023 LRGBColorf prev_rgb =
get_xel(x, y);
1024 r = r + (1.0f - alpha) * (prev_rgb[0] - r);
1025 g = g + (1.0f - alpha) * (prev_rgb[1] - g);
1026 b = b + (1.0f - alpha) * (prev_rgb[2] - b);
1027 alpha = prev_alpha + alpha * (1.0f - prev_alpha);
1047 if (_array !=
nullptr) {
1048 PANDA_FREE_ARRAY(_array);
1063 if (_alpha !=
nullptr) {
1064 PANDA_FREE_ARRAY(_alpha);
1078 int xfrom,
int yfrom,
int x_size,
int y_size) {
1079 int xmin, ymin, xmax, ymax;
1080 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1081 xmin, ymin, xmax, ymax);
1087 for (y = ymin; y < ymax; y++) {
1088 for (x = xmin; x < xmax; x++) {
1094 for (y = ymin; y < ymax; y++) {
1095 for (x = xmin; x < xmax; x++) {
1104 for (y = ymin; y < ymax; y++) {
1105 for (x = xmin; x < xmax; x++) {
1111 for (y = ymin; y < ymax; y++) {
1112 for (x = xmin; x < xmax; x++) {
1133 int xfrom,
int yfrom,
int x_size,
int y_size,
1134 float pixel_scale) {
1135 if (!copy.
has_alpha() && pixel_scale == 1.0) {
1140 int xmin, ymin, xmax, ymax;
1141 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1142 xmin, ymin, xmax, ymax);
1146 for (y = ymin; y < ymax; y++) {
1147 for (x = xmin; x < xmax; x++) {
1148 blend(x, y, copy.
get_xel(x - xmin + xfrom, y - ymin + yfrom),
1149 copy.
get_alpha(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale);
1153 for (y = ymin; y < ymax; y++) {
1154 for (x = xmin; x < xmax; x++) {
1155 blend(x, y, copy.
get_xel(x - xmin + xfrom, y - ymin + yfrom),
1169 int xfrom,
int yfrom,
int x_size,
int y_size,
1170 float pixel_scale) {
1171 int xmin, ymin, xmax, ymax;
1172 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1173 xmin, ymin, xmax, ymax);
1177 for (y = ymin; y < ymax; y++) {
1178 for (x = xmin; x < xmax; x++) {
1184 for (y = ymin; y < ymax; y++) {
1185 for (x = xmin; x < xmax; x++) {
1186 LRGBColorf rgb1 =
get_xel(x, y);
1187 LRGBColorf rgb2 = copy.
get_xel(x, y);
1189 rgb1[0] + rgb2[0] * pixel_scale,
1190 rgb1[1] + rgb2[1] * pixel_scale,
1191 rgb1[2] + rgb2[2] * pixel_scale);
1203 int xfrom,
int yfrom,
int x_size,
int y_size,
1204 float pixel_scale) {
1205 int xmin, ymin, xmax, ymax;
1206 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1207 xmin, ymin, xmax, ymax);
1211 for (y = ymin; y < ymax; y++) {
1212 for (x = xmin; x < xmax; x++) {
1218 for (y = ymin; y < ymax; y++) {
1219 for (x = xmin; x < xmax; x++) {
1220 LRGBColorf rgb1 =
get_xel(x, y);
1221 LRGBColorf rgb2 = copy.
get_xel(x, y);
1223 rgb1[0] * rgb2[0] * pixel_scale,
1224 rgb1[1] * rgb2[1] * pixel_scale,
1225 rgb1[2] * rgb2[2] * pixel_scale);
1242 int xfrom,
int yfrom,
int x_size,
int y_size,
1243 float pixel_scale) {
1244 int xmin, ymin, xmax, ymax;
1245 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1246 xmin, ymin, xmax, ymax);
1252 for (y = ymin; y < ymax; y++) {
1253 for (x = xmin; x < xmax; x++) {
1257 PPM_ASSIGN(p, min(c.r, o.r), min(c.g, o.g), min(c.b, o.b));
1263 for (y = ymin; y < ymax; y++) {
1264 for (x = xmin; x < xmax; x++) {
1265 xelval c = copy.
get_alpha_val(x - xmin + xfrom, y - ymin + yfrom);
1275 for (y = ymin; y < ymax; y++) {
1276 for (x = xmin; x < xmax; x++) {
1277 LRGBColorf c = copy.
get_xel(x - xmin + xfrom, y - ymin + yfrom);
1280 p.set(min(1.0f - ((1.0f - c[0]) * pixel_scale), o[0]),
1281 min(1.0f - ((1.0f - c[1]) * pixel_scale), o[1]),
1282 min(1.0f - ((1.0f - c[2]) * pixel_scale), o[2]));
1288 for (y = ymin; y < ymax; y++) {
1289 for (x = xmin; x < xmax; x++) {
1290 float c = copy.
get_alpha(x - xmin + xfrom, y - ymin + yfrom);
1292 set_alpha(x, y, min(1.0f - ((1.0f - c) * pixel_scale), o));
1309 int xfrom,
int yfrom,
int x_size,
int y_size,
1310 float pixel_scale) {
1311 int xmin, ymin, xmax, ymax;
1312 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1313 xmin, ymin, xmax, ymax);
1319 for (y = ymin; y < ymax; y++) {
1320 for (x = xmin; x < xmax; x++) {
1324 PPM_ASSIGN(p, max(c.r, o.r), max(c.g, o.g), max(c.b, o.b));
1330 for (y = ymin; y < ymax; y++) {
1331 for (x = xmin; x < xmax; x++) {
1332 xelval c = copy.
get_alpha_val(x - xmin + xfrom, y - ymin + yfrom);
1342 for (y = ymin; y < ymax; y++) {
1343 for (x = xmin; x < xmax; x++) {
1344 LRGBColorf c = copy.
get_xel(x - xmin + xfrom, y - ymin + yfrom);
1347 p.set(max(c[0] * pixel_scale, o[0]),
1348 max(c[1] * pixel_scale, o[1]),
1349 max(c[2] * pixel_scale, o[2]));
1355 for (y = ymin; y < ymax; y++) {
1356 for (x = xmin; x < xmax; x++) {
1357 float c = copy.
get_alpha(x - xmin + xfrom, y - ymin + yfrom);
1359 set_alpha(x, y, max(c * pixel_scale, o));
1396 xelval lt_alpha = 0;
1403 (xelval)(PPM_GETR(lt_val) * scale + 0.5),
1404 (xelval)(PPM_GETG(lt_val) * scale + 0.5),
1405 (xelval)(PPM_GETB(lt_val) * scale + 0.5));
1406 lt_alpha = (xelval)(lt_alpha * scale + 0.5);
1410 xelval ge_alpha = 0;
1417 (xelval)(PPM_GETR(ge_val) * scale + 0.5),
1418 (xelval)(PPM_GETG(ge_val) * scale + 0.5),
1419 (xelval)(PPM_GETB(ge_val) * scale + 0.5));
1420 ge_alpha = (xelval)(ge_alpha * scale + 0.5);
1603 nassertv(radius <= PNM_MAXMAXVAL);
1609 for (
int yi = 0; yi < mask.
get_y_size(); ++yi) {
1610 for (
int xi = 0; xi < mask.
get_x_size(); ++xi) {
1612 dist.do_fill_distance(xi, yi, 0);
1617 if (shrink_from_border) {
1619 for (
int yi = 0; yi < mask.
get_y_size(); ++yi) {
1620 dist.do_fill_distance(0, yi, 1);
1621 dist.do_fill_distance(mask.
get_x_size() - 1, yi, 1);
1623 for (
int xi = 0; xi < mask.
get_x_size(); ++xi) {
1624 dist.do_fill_distance(xi, 0, 1);
1625 dist.do_fill_distance(xi, mask.
get_y_size() - 1, 1);
1647 nassertv(radius <= PNM_MAXMAXVAL);
1653 for (
int yi = 0; yi < mask.
get_y_size(); ++yi) {
1654 for (
int xi = 0; xi < mask.
get_x_size(); ++xi) {
1656 dist.do_fill_distance(xi, yi, 0);
1687 nassertv(v >= 0 && v < pixel_values.
get_x_size());
1704 float scale = max_val - min_val;
1706 if (_num_channels <= 2) {
1711 set_gray(x, y, (val - min_val) / scale);
1720 (
xel[0] - min_val) / scale,
1721 (
xel[1] - min_val) / scale,
1722 (
xel[2] - min_val) / scale);
1734 int xfrom,
int yfrom,
int cfrom,
1735 int x_size,
int y_size) {
1736 int xmin, ymin, xmax, ymax;
1737 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1738 xmin, ymin, xmax, ymax);
1744 for (y = ymin; y < ymax; y++) {
1745 if (cto == 3 && cfrom == 3) {
1747 for (x = xmin; x < xmax; x++) {
1750 }
else if (cto == 3 && cfrom == 0) {
1752 for (x = xmin; x < xmax; x++) {
1755 }
else if (cto == 0 && cfrom == 3) {
1757 for (x = xmin; x < xmax; x++) {
1762 for (x = xmin; x < xmax; x++) {
1771 for (y = ymin; y < ymax; y++) {
1772 for (x = xmin; x < xmax; x++) {
1790 float min_radius,
float max_radius) {
1791 if (_x_size == 0 || _y_size == 0) {
1795 float x_scale = 2.0 / _x_size;
1796 float y_scale = 2.0 / _y_size;
1800 int x_center0 = _x_size / 2;
1801 int y_center0 = _y_size / 2;
1802 int x_center1 = (_x_size + 1) / 2;
1803 int y_center1 = (_y_size + 1) / 2;
1805 float min_r2 = min_radius * min_radius;
1806 float max_r2 = max_radius * max_radius;
1808 for (
int yi = 0; yi < y_center1; ++yi) {
1809 float y = yi * y_scale;
1810 float y2_inner = y * y;
1811 float y2_outer = (y + y_scale) * (y + y_scale);
1812 for (
int xi = 0; xi < x_center1; ++xi) {
1813 float x = xi * x_scale;
1814 float d2_inner = (x * x + y2_inner);
1815 float d2_outer = ((x + x_scale) * (x + x_scale) + y2_outer);
1816 float d2_a = ((x + x_scale) * (x + x_scale) + y2_inner);
1817 float d2_b = (x * x + y2_outer);
1819 if ((d2_inner <= min_r2) &&
1820 (d2_outer <= min_r2) &&
1824 set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, fg);
1825 set_xel_a(x_center0 + xi, y_center1 - 1 - yi, fg);
1826 set_xel_a(x_center1 - 1 - xi, y_center0 + yi, fg);
1827 set_xel_a(x_center0 + xi, y_center0 + yi, fg);
1829 }
else if ((d2_inner > max_r2) &&
1830 (d2_outer > max_r2) &&
1834 set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, bg);
1835 set_xel_a(x_center0 + xi, y_center1 - 1 - yi, bg);
1836 set_xel_a(x_center1 - 1 - xi, y_center0 + yi, bg);
1837 set_xel_a(x_center0 + xi, y_center0 + yi, bg);
1841 LColorf c_outer, c_inner, c_a, c_b;
1842 compute_spot_pixel(c_outer, d2_outer, min_radius, max_radius, fg, bg);
1843 compute_spot_pixel(c_inner, d2_inner, min_radius, max_radius, fg, bg);
1844 compute_spot_pixel(c_a, d2_a, min_radius, max_radius, fg, bg);
1845 compute_spot_pixel(c_b, d2_b, min_radius, max_radius, fg, bg);
1849 c = (c_outer + c_inner + c_a + c_b) * 0.25;
1851 set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, c);
1852 set_xel_a(x_center0 + xi, y_center1 - 1 - yi, c);
1853 set_xel_a(x_center1 - 1 - xi, y_center0 + yi, c);
1854 set_xel_a(x_center0 + xi, y_center0 + yi, c);
1868 const LColorf &color) {
1873 new_image.
fill(color[0], color[1], color[2]);
1915 int num_pixels = _x_size * _y_size;
1917 compute_histogram(hist_map, _array, _alpha);
1919 pixels.reserve(hist_map.size());
1920 HistMap::const_iterator hi;
1921 for (hi = hist_map.begin(); hi != hist_map.end(); ++hi) {
1922 if ((*hi).second <= num_pixels) {
1926 std::sort(pixels.begin(), pixels.end());
1928 histogram.
swap(pixels, hist_map);
1941 PerlinNoise2 perlin (sx * _x_size, sy * _y_size, table_size, seed);
1942 for (x = 0; x < _x_size; ++x) {
1943 for (y = 0; y < _y_size; ++y) {
1944 noise = perlin.
noise(x, y);
1945 set_xel(x, y, 0.5 * (noise + 1.0));
1958 for (x = 0; x < _x_size; ++x) {
1959 for (y = 0; y < _y_size; ++y) {
1960 noise = perlin.
noise(x / (
float) _x_size, y / (
float) _y_size);
1961 set_xel(x, y, 0.5 * (noise + 1.0));
1973 nassertv((nchannels >= 3) && (nchannels <= 4));
1977 LVector3 outv(conv.xform_point(inv));
1978 set_xel(x, y, outv[0], outv[1], outv[2]);
1991 float alpha_exponent) {
1992 int num_channels = _num_channels;
1993 if (
has_alpha() && alpha_exponent == 1.0f) {
2000 if (red_exponent == 1.0f && green_exponent == 1.0f && blue_exponent == 1.0f) {
2002 switch (num_channels) {
2009 for (y = 0; y < _y_size; ++y) {
2010 for (x = 0; x < _x_size; ++x) {
2012 alpha = cpow(alpha, blue_exponent);
2022 switch (num_channels) {
2024 for (y = 0; y < _y_size; ++y) {
2025 for (x = 0; x < _x_size; ++x) {
2027 gray = cpow(gray, blue_exponent);
2034 for (y = 0; y < _y_size; ++y) {
2035 for (x = 0; x < _x_size; ++x) {
2037 gray = cpow(gray, blue_exponent);
2041 alpha = cpow(alpha, blue_exponent);
2048 for (y = 0; y < _y_size; ++y) {
2049 for (x = 0; x < _x_size; ++x) {
2050 LRGBColorf color =
get_xel(x, y);
2051 color[0] = cpow(color[0], red_exponent);
2052 color[1] = cpow(color[1], green_exponent);
2053 color[2] = cpow(color[2], blue_exponent);
2060 for (y = 0; y < _y_size; ++y) {
2061 for (x = 0; x < _x_size; ++x) {
2063 color[0] = cpow(color[0], red_exponent);
2064 color[1] = cpow(color[1], green_exponent);
2065 color[2] = cpow(color[2], blue_exponent);
2066 color[3] = cpow(color[3], alpha_exponent);
2087 _default_rc = lumin_red;
2088 _default_gc = lumin_grn;
2089 _default_bc = lumin_blu;
2104 _inv_maxval = 1.0f / (float)_maxval;
2108 switch (_color_space) {
2110 _xel_encoding = XE_generic_alpha;
2115 if (has_sse2_sRGB_encode()) {
2116 _xel_encoding = XE_uchar_sRGB_alpha_sse2;
2118 _xel_encoding = XE_uchar_sRGB_alpha;
2121 _xel_encoding = XE_generic_sRGB_alpha;
2126 _xel_encoding = XE_scRGB_alpha;
2131 nassert_raise(
"invalid color space");
2135 switch (_color_space) {
2137 _xel_encoding = XE_generic;
2142 if (has_sse2_sRGB_encode()) {
2143 _xel_encoding = XE_uchar_sRGB_sse2;
2145 _xel_encoding = XE_uchar_sRGB;
2148 _xel_encoding = XE_generic_sRGB;
2153 _xel_encoding = XE_scRGB;
2158 nassert_raise(
"invalid color space");
2190 LRGBColorf color (LRGBColorf::zero());
2191 if (_x_size == 0 || _y_size == 0) {
2195 float factor = 1.0f / (float)(_x_size * _y_size);
2198 for (x = 0; x < _x_size; ++x) {
2199 for (y = 0; y < _y_size; ++y) {
2200 color +=
get_xel(x, y) * factor;
2213 LColorf color (LColorf::zero());
2214 if (_x_size == 0 || _y_size == 0) {
2218 float factor = 1.0f / (float)(_x_size * _y_size);
2221 for (x = 0; x < _x_size; ++x) {
2222 for (y = 0; y < _y_size; ++y) {
2236 if (_x_size == 0 || _y_size == 0) {
2241 for (x = 0; x < _x_size; ++x) {
2242 for (y = 0; y < _y_size; ++y) {
2247 gray /= (float)(_x_size * _y_size);
2258 size_t array_size = _x_size * _y_size;
2260 if (_array !=
nullptr && _alpha !=
nullptr) {
2261 for (
size_t i = 0; i < array_size; ++i) {
2262 target._array[i].r = _maxval - _array[i].r;
2263 target._array[i].g = _maxval - _array[i].g;
2264 target._array[i].b = _maxval - _array[i].b;
2265 target._alpha[i] = _maxval - _alpha[i];
2267 }
else if (_array !=
nullptr) {
2268 for (
size_t i = 0; i < array_size; ++i) {
2269 target._array[i].r = _maxval - _array[i].r;
2270 target._array[i].g = _maxval - _array[i].g;
2271 target._array[i].b = _maxval - _array[i].b;
2273 }
else if (_alpha !=
nullptr) {
2274 for (
size_t i = 0; i < array_size; ++i) {
2275 target._alpha[i] = _maxval - _alpha[i];
2288 nassertv(_x_size == other._x_size && _y_size == other._y_size);
2293 size_t array_size = _x_size * _y_size;
2296 if (_alpha !=
nullptr && other._alpha !=
nullptr) {
2297 for (
size_t i = 0; i < array_size; ++i) {
2298 _array[i].r =
clamp_val((
int)_array[i].r + (
int)other._array[i].r);
2299 _array[i].g =
clamp_val((
int)_array[i].g + (
int)other._array[i].g);
2300 _array[i].b =
clamp_val((
int)_array[i].b + (
int)other._array[i].b);
2301 _alpha[i] =
clamp_val((
int)_alpha[i] + (
int)other._alpha[i]);
2304 for (
size_t i = 0; i < array_size; ++i) {
2305 _array[i].r =
clamp_val((
int)_array[i].r + (
int)other._array[i].r);
2306 _array[i].g =
clamp_val((
int)_array[i].g + (
int)other._array[i].g);
2307 _array[i].b =
clamp_val((
int)_array[i].b + (
int)other._array[i].b);
2313 for (x = 0; x < _x_size; ++x) {
2314 for (y = 0; y < _y_size; ++y) {
2329 size_t array_size = _x_size * _y_size;
2332 int add_r = (int)(other.get_x() *
get_maxval() + 0.5);
2333 int add_g = (int)(other.get_y() *
get_maxval() + 0.5);
2334 int add_b = (int)(other.get_z() *
get_maxval() + 0.5);
2335 int add_a = (int)(other.get_w() *
get_maxval() + 0.5);
2337 if (_alpha !=
nullptr) {
2338 for (
size_t i = 0; i < array_size; ++i) {
2339 _array[i].r =
clamp_val((
int)_array[i].r + add_r);
2340 _array[i].g =
clamp_val((
int)_array[i].g + add_g);
2341 _array[i].b =
clamp_val((
int)_array[i].b + add_b);
2342 _alpha[i] =
clamp_val((
int)_alpha[i] + add_a);
2346 for (
size_t i = 0; i < array_size; ++i) {
2347 _array[i].r =
clamp_val((
int)_array[i].r + add_r);
2348 _array[i].g =
clamp_val((
int)_array[i].g + add_g);
2349 _array[i].b =
clamp_val((
int)_array[i].b + add_b);
2355 for (x = 0; x < _x_size; ++x) {
2356 for (y = 0; y < _y_size; ++y) {
2370 nassertv(_x_size == other._x_size && _y_size == other._y_size);
2375 size_t array_size = _x_size * _y_size;
2378 if (_alpha !=
nullptr && other._alpha !=
nullptr) {
2379 for (
size_t i = 0; i < array_size; ++i) {
2380 _array[i].r =
clamp_val((
int)_array[i].r - (
int)other._array[i].r);
2381 _array[i].g =
clamp_val((
int)_array[i].g - (
int)other._array[i].g);
2382 _array[i].b =
clamp_val((
int)_array[i].b - (
int)other._array[i].b);
2383 _alpha[i] =
clamp_val((
int)_alpha[i] - (
int)other._alpha[i]);
2386 for (
size_t i = 0; i < array_size; ++i) {
2387 _array[i].r =
clamp_val((
int)_array[i].r - (
int)other._array[i].r);
2388 _array[i].g =
clamp_val((
int)_array[i].g - (
int)other._array[i].g);
2389 _array[i].b =
clamp_val((
int)_array[i].b - (
int)other._array[i].b);
2395 for (x = 0; x < _x_size; ++x) {
2396 for (y = 0; y < _y_size; ++y) {
2420 nassertv(_x_size == other._x_size && _y_size == other._y_size);
2423 for (x = 0; x < _x_size; ++x) {
2424 for (y = 0; y < _y_size; ++y) {
2439 size_t array_size = _x_size * _y_size;
2441 if (_alpha !=
nullptr) {
2442 for (
size_t i = 0; i < array_size; ++i) {
2443 _array[i].r =
clamp_val((
int)(_array[i].r * multiplier + 0.5f));
2444 _array[i].g =
clamp_val((
int)(_array[i].g * multiplier + 0.5f));
2445 _array[i].b =
clamp_val((
int)(_array[i].b * multiplier + 0.5f));
2446 _alpha[i] =
clamp_val((
int)(_alpha[i] * multiplier + 0.5f));
2450 for (
size_t i = 0; i < array_size; ++i) {
2451 _array[i].r =
clamp_val((
int)(_array[i].r * multiplier + 0.5f));
2452 _array[i].g =
clamp_val((
int)(_array[i].g * multiplier + 0.5f));
2453 _array[i].b =
clamp_val((
int)(_array[i].b * multiplier + 0.5f));
2459 for (x = 0; x < _x_size; ++x) {
2460 for (y = 0; y < _y_size; ++y) {
2476 size_t array_size = _x_size * _y_size;
2478 if (_alpha !=
nullptr) {
2479 for (
size_t i = 0; i < array_size; ++i) {
2480 _array[i].r =
clamp_val((
int)(_array[i].r * other[0] + 0.5f));
2481 _array[i].g =
clamp_val((
int)(_array[i].g * other[1] + 0.5f));
2482 _array[i].b =
clamp_val((
int)(_array[i].b * other[2] + 0.5f));
2483 _alpha[i] =
clamp_val((
int)(_alpha[i] * other[3] + 0.5f));
2487 for (
size_t i = 0; i < array_size; ++i) {
2488 _array[i].r =
clamp_val((
int)(_array[i].r * other[0] + 0.5f));
2489 _array[i].g =
clamp_val((
int)(_array[i].g * other[1] + 0.5f));
2490 _array[i].b =
clamp_val((
int)(_array[i].b * other[2] + 0.5f));
2496 for (x = 0; x < _x_size; ++x) {
2497 for (y = 0; y < _y_size; ++y) {
2499 color.componentwise_mult(other);
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.
EXPCL_PANDA_PNMIMAGE unsigned char decode_sRGB_uchar(unsigned char val)
Decodes the sRGB-encoded unsigned char value to a linearized unsigned char value.
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.
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 ...
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
float get_channel(int x, int y, int channel) const
Returns the nth component color at the indicated pixel.
xelval to_val(float input_value) const
A handy function to scale non-alpha values from [0..1] to [0..get_maxval()].
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.
xelval get_channel_val(int x, int y, int channel) const
Returns the nth component color at the indicated pixel.
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.
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.
ColorSpace get_color_space() const
Returns the color space in which the image is encoded.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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,...
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
xelval get_gray_val(int x, int y) const
Returns the gray component color at the indicated pixel.
void alpha_fill(float alpha=0.0)
Sets the entire alpha channel to the given level.
void set_green_val(int x, int y, xelval g)
Sets the green component color only at the indicated pixel.
void apply_exponent(float gray_exponent)
Adjusts each channel of the image by raising the corresponding component value to the indicated expon...
float get_gray(int x, int y) const
Returns the gray component color at the indicated pixel.
virtual bool write_pfm(const PfmFile &pfm)
Writes floating-point data from the indicated PfmFile.
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.
float get_blue(int x, int y) const
Returns the blue component color at the indicated pixel.
void copy_channel_bits(const PNMImage ©, int src_channel, int dest_channel, xelval src_mask, int right_shift)
Copies some subset of the bits of the specified channel from one image into some subset of the bits o...
bool write(const Filename &filename, PNMFileType *type=nullptr) const
Writes the image to the indicated filename.
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...
virtual bool supports_grayscale() const
Returns true if this particular PNMWriter understands grayscale images.
bool read(const Filename &filename, PNMFileType *type=nullptr, bool report_unknown_type=true)
Reads the indicated image filename.
xelval clamp_val(int input_value) const
A handy function to clamp values to [0..get_maxval()].
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.
void set_red(int x, int y, float r)
Sets the red component color only at the indicated pixel.
void flip(bool flip_x, bool flip_y, bool transpose)
Reverses, transposes, and/or rotates the image in-place according to the specified parameters.
LRGBColorf get_average_xel() const
Returns the average color of all of the pixels in the image.
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.
float get_red(int x, int y) const
Returns the red 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.
xel & get_xel_val(int x, int y)
Returns the RGB 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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Implements a multi-layer PerlinNoise, with one or more high-frequency noise functions added to a lowe...
bool is_valid() const
Returns true if the PNMReader can be used to read data, false if something is wrong.
LRGBColorf get_xel(int x, int y) const
Returns the RGB color at the indicated pixel.
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.
LColorf get_xel_a(int x, int y) const
Returns the RGBA color at the indicated pixel.
PixelSpec get_pixel(int x, int y) const
Returns the (r, g, b, a) pixel value at the indicated pixel, using a PixelSpec object.
The name of a file, such as a texture file or an Egg file.
float get_green(int x, int y) const
Returns the green component color at the indicated pixel.
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
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.
xelval get_blue_val(int x, int y) const
Returns the blue component color at the indicated pixel.
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...
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.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void operator+=(const PNMImage &other)
Sets each pixel value to the sum of the corresponding pixel values in the two given images.
void operator *=(const PNMImage &other)
Multiples each pixel in this image by each pixel value from the right image.
void set_array(xel *array)
Replaces the underlying PNMImage array with the indicated pointer.
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.
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...
double noise(double x, double y) const
Returns the noise function of the three inputs.
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,...
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 operator -=(const PNMImage &other)
Subtracts each pixel from the right image from each pixel value in this 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.
bool has_read_size() const
Returns true if set_read_size() has been called.
float get_average_gray() const
Returns the average grayscale component of all of the pixels in the image.
void copy_from(const PNMImage ©)
Makes this image become a copy of the other image.
PNMImage operator ~() const
Returns a new PNMImage that is the complement of this PNMImage.
void set_alpha_val(int x, int y, xelval a)
Sets the alpha component color only at the indicated pixel.
void set_maxval(xelval maxval)
Rescales the image to the indicated maxval.
xelval get_alpha_val(int x, int y) const
Returns the alpha component color at the indicated pixel.
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.
bool store(PNMImage &pnmimage) const
Copies the data to the indicated PNMImage, converting to RGB values.
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...
float get_bright(int x, int y) const
Returns the linear brightness of the given xel, as a linearized float in the range 0....
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_xel(int x, int y, const LRGBColorf &value)
Changes the RGB color at the indicated pixel.
void indirect_1d_lookup(const PNMImage &index_image, int channel, const PNMImage &pixel_values)
index_image is a WxH grayscale image, while pixel_values is an Nx1 color (or grayscale) image.
xelval get_green_val(int x, int y) const
Returns the green component color at the indicated pixel.
EXPCL_PANDA_PNMIMAGE unsigned char encode_sRGB_uchar(unsigned char val)
Encodes the linearized unsigned char value to an sRGB-encoded unsigned char value.
xelval get_red_val(int x, int y) const
Returns the red component color at the indicated pixel.
void fill_val(xelval red, xelval green, xelval blue)
Sets the entire image (except the alpha channel) to the given color.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
float get_alpha(int x, int y) const
Returns the alpha component color at the indicated pixel.
void premultiply_alpha()
Converts an image in-place to its "premultiplied" form, where, for every pixel in the image,...
LColorf get_average_xel_a() const
Returns the average color of all of the pixels in the image, including the alpha channel.