00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "pnmTextGlyph.h"
00016 #include "indent.h"
00017
00018
00019
00020
00021
00022
00023 PNMTextGlyph::
00024 PNMTextGlyph(double advance) :
00025 _advance(advance)
00026 {
00027 _left = 0;
00028 _top = 0;
00029 _int_advance = (int)floor(_advance + 0.5);
00030 }
00031
00032
00033
00034
00035
00036
00037 PNMTextGlyph::
00038 ~PNMTextGlyph() {
00039 }
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 void PNMTextGlyph::
00052 place(PNMImage &dest_image, int xp, int yp, const LColor &fg) {
00053 if (!_image.is_valid()) {
00054
00055 return;
00056 }
00057 LRGBColord fg_rgb(fg[0], fg[1], fg[2]);
00058 double fg_alpha = fg[3];
00059
00060 int left = xp + _left;
00061 int top = yp - _top;
00062 int right = left + _image.get_x_size();
00063 int bottom = top + _image.get_y_size();
00064
00065
00066 int cleft = max(left, 0);
00067 int ctop = max(top, 0);
00068 int cright = min(right, dest_image.get_x_size());
00069 int cbottom = min(bottom, dest_image.get_y_size());
00070
00071 for (int y = ctop; y < cbottom; y++) {
00072 for (int x = cleft; x < cright; x++) {
00073 double gval = get_value(x - left, y - top);
00074 if (gval == 1.0) {
00075 dest_image.set_xel(x, y, fg_rgb);
00076 if (dest_image.has_alpha()) {
00077 dest_image.set_alpha(x, y, fg_alpha);
00078 }
00079
00080 } else if (gval > 0.0) {
00081 LRGBColord bg_rgb = dest_image.get_xel(x, y);
00082 dest_image.set_xel(x, y, fg_rgb * gval + bg_rgb * (1.0 - gval));
00083 if (dest_image.has_alpha()) {
00084 double bg_alpha = dest_image.get_alpha(x, y);
00085 dest_image.set_alpha(x, y, fg_alpha * gval + bg_alpha * (1.0 - gval));
00086 }
00087 }
00088 }
00089 }
00090 }
00091
00092
00093
00094
00095
00096
00097
00098
00099 void PNMTextGlyph::
00100 place(PNMImage &dest_image, int xp, int yp, const LColor &fg,
00101 const LColor &interior) {
00102 if (!_image.is_valid()) {
00103
00104 return;
00105 }
00106 LRGBColord fg_rgb(fg[0], fg[1], fg[2]);
00107 double fg_alpha = fg[3];
00108 LRGBColord interior_rgb(interior[0], interior[1], interior[2]);
00109 double interior_alpha = interior[3];
00110
00111 int left = xp + _left;
00112 int top = yp - _top;
00113 int right = left + _image.get_x_size();
00114 int bottom = top + _image.get_y_size();
00115
00116
00117 int cleft = max(left, 0);
00118 int ctop = max(top, 0);
00119 int cright = min(right, dest_image.get_x_size());
00120 int cbottom = min(bottom, dest_image.get_y_size());
00121
00122 for (int y = ctop; y < cbottom; y++) {
00123 for (int x = cleft; x < cright; x++) {
00124 double gval = get_value(x - left, y - top);
00125 if (gval == 1.0) {
00126 dest_image.set_xel(x, y, fg_rgb);
00127 if (dest_image.has_alpha()) {
00128 dest_image.set_alpha(x, y, fg_alpha);
00129 }
00130
00131 } else if (gval > 0.0) {
00132 bool is_interior = get_interior_flag(x - left, y - top);
00133 LRGBColord bg_rgb;
00134 if (is_interior) {
00135 bg_rgb = interior_rgb;
00136 } else {
00137 bg_rgb = dest_image.get_xel(x, y);
00138 }
00139
00140 dest_image.set_xel(x, y, fg_rgb * gval + bg_rgb * (1.0 - gval));
00141 if (dest_image.has_alpha()) {
00142 double bg_alpha;
00143
00144 if (is_interior) {
00145 bg_alpha = interior_alpha;
00146 } else {
00147 bg_alpha = dest_image.get_alpha(x, y);
00148 }
00149 dest_image.set_alpha(x, y, fg_alpha * gval + bg_alpha * (1.0 - gval));
00150 }
00151 } else {
00152 bool is_interior = get_interior_flag(x - left, y - top);
00153 if (is_interior) {
00154 dest_image.set_xel(x, y, interior_rgb);
00155 if (dest_image.has_alpha()) {
00156 dest_image.set_alpha(x, y, interior_alpha);
00157 }
00158 }
00159 }
00160 }
00161 }
00162 }
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 void PNMTextGlyph::
00174 determine_interior() {
00175
00176
00177 int x_size = _image.get_x_size();
00178 int y_size = _image.get_y_size();
00179 xelval maxval = _image.get_maxval();
00180 for (int yi = 0; yi < y_size; yi++) {
00181 for (int xi = 0; xi < x_size; xi++) {
00182 _image.set_red_val(xi, yi, maxval);
00183 }
00184 }
00185
00186
00187
00188
00189
00190
00191 _scan_interior_points.clear();
00192 for (int yi = 0; yi < y_size; yi++) {
00193 scan_interior(0, yi, 0, false, 0);
00194 scan_interior(x_size - 1, yi, 0, false, 0);
00195 }
00196 for (int xi = 0; xi < x_size; xi++) {
00197 scan_interior(xi, 0, 0, false, 0);
00198 scan_interior(xi, y_size - 1, 0, false, 0);
00199 }
00200
00201
00202
00203 while (!_scan_interior_points.empty()) {
00204 int index = _scan_interior_points.back();
00205 _scan_interior_points.pop_back();
00206 int y = index / _image.get_x_size();
00207 int x = index % _image.get_x_size();
00208 xelval new_code = _image.get_red_val(x, y);
00209 bool this_dark = (_image.get_blue_val(x, y) > 0);
00210
00211 scan_interior(x - 1, y, new_code, this_dark, 0);
00212 scan_interior(x, y - 1, new_code, this_dark, 0);
00213 scan_interior(x + 1, y, new_code, this_dark, 0);
00214 scan_interior(x, y + 1, new_code, this_dark, 0);
00215 }
00216 _scan_interior_points.clear();
00217
00218
00219
00220
00221 for (int yi = 0; yi < y_size; yi++) {
00222 for (int xi = 0; xi < x_size; xi++) {
00223 xelval code = _image.get_red_val(xi, yi);
00224 if (((code + 2) & 0x3) == 0) {
00225 _image.set_red_val(xi, yi, maxval);
00226 } else {
00227 _image.set_red_val(xi, yi, 0);
00228 }
00229 }
00230 }
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241 void PNMTextGlyph::
00242 scan_interior(int x, int y, xelval new_code, bool neighbor_dark,
00243 int recurse_level) {
00244 if (x < 0 || y < 0 || x >= _image.get_x_size() || y >= _image.get_y_size()) {
00245 return;
00246 }
00247 bool this_dark = (_image.get_blue_val(x, y) > 0);
00248 if (this_dark != neighbor_dark) {
00249
00250 if (new_code < _image.get_maxval()) {
00251 new_code++;
00252 }
00253 nassertv(new_code > 0);
00254 }
00255
00256 if (new_code < _image.get_red_val(x, y)) {
00257 _image.set_red_val(x, y, new_code);
00258 recurse_level++;
00259 if (recurse_level > 1024) {
00260
00261
00262
00263
00264 int index = y * _image.get_x_size() + x;
00265 _scan_interior_points.push_back(index);
00266
00267 } else {
00268 scan_interior(x - 1, y, new_code, this_dark, recurse_level);
00269 scan_interior(x, y - 1, new_code, this_dark, recurse_level);
00270 scan_interior(x + 1, y, new_code, this_dark, recurse_level);
00271 scan_interior(x, y + 1, new_code, this_dark, recurse_level);
00272 }
00273 }
00274 }
00275
00276
00277
00278
00279
00280
00281
00282 void PNMTextGlyph::
00283 rescale(double scale_factor) {
00284 if (scale_factor == 1.0) {
00285 return;
00286 }
00287 nassertv(scale_factor != 0.0);
00288 _advance /= scale_factor;
00289 _int_advance = (int)floor(_advance + 0.5);
00290
00291 if (_image.is_valid()) {
00292 int orig_x_size = _image.get_x_size();
00293 int orig_y_size = _image.get_y_size();
00294 int orig_left = _left;
00295 int orig_top = _top;
00296
00297
00298
00299 int extra_pad = (int)ceil(scale_factor);
00300 orig_x_size += 2*extra_pad;
00301 orig_y_size += 2*extra_pad;
00302 orig_left -= extra_pad;
00303 orig_top += extra_pad;
00304
00305
00306 int new_x_size = (int)ceil(orig_x_size / scale_factor);
00307 int new_y_size = (int)ceil(orig_y_size / scale_factor);
00308 int new_left = (int)floor(orig_left / scale_factor);
00309 int new_top = (int)ceil(orig_top / scale_factor);
00310
00311
00312
00313
00314 int old_x_size = (int)(new_x_size * scale_factor + 0.5);
00315 int old_y_size = (int)(new_y_size * scale_factor + 0.5);
00316 int old_left = (int)(new_left * scale_factor + 0.5);
00317 int old_top = (int)(new_top * scale_factor + 0.5);
00318
00319 int pad_left = orig_left - old_left;
00320 int pad_top = old_top - orig_top;
00321
00322
00323 nassertv(extra_pad + pad_left >= 0 && extra_pad + pad_top >= 0);
00324
00325 PNMImage enlarged(old_x_size, old_y_size, _image.get_num_channels());
00326 enlarged.copy_sub_image(_image, pad_left + extra_pad, pad_top + extra_pad);
00327
00328 _image.clear(new_x_size, new_y_size, _image.get_num_channels());
00329 _image.quick_filter_from(enlarged);
00330
00331 _left = new_left;
00332 _top = new_top;
00333 }
00334 }