Fix some signed-to-unsigned compares and missing headers
[ilaris-y4m-tools.git] / rendertext.cpp
blob3643bb7819b96044ee6c3b4bcc3b82420a188a5f
1 #include "rendertext.hpp"
2 #include "parseval.hpp"
3 #include "yuv4mpeg.hpp"
4 #include "yuvconvert.hpp"
5 #include <fstream>
6 #include <iostream>
7 #include <ft2build.h>
8 #include FT_FREETYPE_H
10 namespace
12 static bool ft_init;
13 static FT_Library ft_handle;
15 void mix(uint16_t& a, uint16_t b, uint32_t t)
17 a = (a * (65536 - t) + b * t) >> 16;
20 void mix(uint8_t& a, uint8_t b, uint32_t t)
22 a = (a * (256 - t) + b * t) >> 8;
25 void render_halo(uint8_t* dest, const uint8_t* src, size_t width, size_t height, signed thickness)
27 if(dest != src)
28 memcpy(dest, src, width * height);
29 for(unsigned j = 0; j < height; j++)
30 for(unsigned i = 0; i < width; i++)
31 if(dest[j * width + i] == 1)
32 for(signed y = -thickness; y <= thickness; y++) {
33 if(j + y < 0)
34 continue;
35 if(j + y >= height)
36 break;
37 for(signed x = -thickness; x <= thickness; x++) {
38 if(i + x < 0)
39 continue;
40 if(i + x >= width)
41 break;
42 if(dest[(j + y) * width + (i + x)] == 0)
43 dest[(j + y) * width + (i + x)] = 2;
48 struct errmsg
50 int code;
51 const char* message;
54 void throw_ft_error(FT_Error code)
56 if(!code)
57 return;
58 //There's no built-in error table in Freetype 2???
59 #undef __FTERRORS_H__
60 #define FT_ERRORDEF(e, v, s) {e, s},
61 #define FT_ERROR_START_LIST {
62 #define FT_ERROR_END_LIST {0, 0}};
63 static struct errmsg freetype_errors[] =
64 #include FT_ERRORS_H
65 struct errmsg* i = freetype_errors;
66 while(i->message) {
67 if(i->code == code)
68 throw std::runtime_error(std::string("Freetype2 error: ") + i->message);
69 i++;
71 std::ostringstream s;
72 s << "Freetype2 error: Unknown error #" << code;
73 throw std::runtime_error(s.str());
76 struct render_line_info
78 size_t width;
79 size_t height;
80 size_t baseline;
81 size_t offset;
84 struct render_line_info ft_rendered_size_line(FT_Face face, const std::string& text)
86 struct render_line_info l;
87 uint16_t state = utf8_initial_state;
88 size_t len = text.length();
89 size_t basepos = 0;
90 l.width = l.height = l.baseline = l.offset = 0;
91 for(size_t i = 0; i <= len; i++) {
92 ssize_t base;
93 int32_t sym = utf8_parse_byte((i < len) ? static_cast<uint8_t>(text[i]) : -1, state);
94 if(sym < 0)
95 continue;
96 //Got unicode symbol.
97 unsigned gslot = FT_Get_Char_Index(face, sym);
98 if(!gslot) {
99 //Missing symbol!
100 std::cerr << "Warning: Symbol " << sym << " not present in font!" << std::endl;
101 continue;
103 try {
104 throw_ft_error(FT_Load_Glyph(face, gslot, FT_LOAD_DEFAULT));
105 throw_ft_error(FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO));
106 } catch(std::exception& e) {
107 std::cerr << "Warning: Symbol " << sym << " can't be rendered: " << e.what()
108 << std::endl;
109 continue;
111 //If offset needs adjustment, do that.
112 base = basepos + face->glyph->bitmap_left;
113 if(base < 0 && l.offset < static_cast<size_t>(-base))
114 l.offset = static_cast<size_t>(-base);
115 //If baseline need adjustment, do that.
116 base = -face->glyph->bitmap_top;
117 if(base < 0 && l.baseline < static_cast<size_t>(-base))
118 l.baseline = static_cast<size_t>(-base);
119 //Compute width.
120 base = basepos + face->glyph->bitmap_left + face->glyph->bitmap.width;
121 if(base > static_cast<ssize_t>(l.width))
122 l.width = base;
123 //Compute height.
124 base = -face->glyph->bitmap_top + face->glyph->bitmap.rows;
125 if(base > static_cast<ssize_t>(l.height))
126 l.height = base;
127 basepos = basepos + (face->glyph->advance.x >> 6);
129 //Width / height don't take negative excursions into account.
130 l.width = l.width + l.offset;
131 l.height = l.height + l.baseline;
133 return l;
136 ssize_t align_position(size_t space, size_t size, int32_t pos)
138 ssize_t freespace = space - size;
139 return ((pos + 1000) * freespace) / 2000;
142 void ft_render_text_line(FT_Face face, const std::string& text, std::vector<uint8_t>& data, size_t width,
143 size_t height, ssize_t alignment, size_t y, struct render_line_info l)
145 ssize_t p = align_position(width, l.width, alignment);
146 if(y >= height || p >= static_cast<ssize_t>(width))
147 return; //Nothing fits.
148 ssize_t offset_x;
149 ssize_t offset_y;
150 ssize_t basepos = 0;
151 uint16_t state = utf8_initial_state;
152 size_t len = text.length();
153 //We need to compute the window offset.
154 offset_y = l.baseline + y;
155 offset_x = l.offset + p;
156 for(size_t i = 0; i <= len; i++) {
157 int32_t sym = utf8_parse_byte((i < len) ? static_cast<uint8_t>(text[i]) : -1, state);
158 if(sym < 0)
159 continue;
160 //Got unicode symbol.
161 unsigned gslot = FT_Get_Char_Index(face, sym);
162 if(!gslot) {
163 //Missing symbol!
164 std::cerr << "Warning: Symbol " << sym << " not present in font!" << std::endl;
165 continue;
167 try {
168 throw_ft_error(FT_Load_Glyph(face, gslot, FT_LOAD_DEFAULT));
169 throw_ft_error(FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO));
170 } catch(std::exception& e) {
171 std::cerr << "Warning: Symbol " << sym << " can't be rendered: " << e.what()
172 << std::endl;
173 continue;
175 ssize_t render_x = basepos + face->glyph->bitmap_left + offset_x;
176 ssize_t render_y = -face->glyph->bitmap_top + offset_y;
177 for(int j = 0; (unsigned)j < face->glyph->bitmap.rows && render_y + j <
178 static_cast<ssize_t>(height); j++) {
179 if(render_y + j < 0)
180 continue;
181 const uint8_t* ldata = face->glyph->bitmap.buffer + j * face->glyph->bitmap.pitch;
182 uint8_t* tmpr = &data[(render_y + j) * width];
183 for(int k = 0; (unsigned)k < face->glyph->bitmap.width && render_x + k <
184 static_cast<ssize_t>(width); k++) {
185 if(render_x + k < 0)
186 continue;
187 tmpr[render_x + k] = ((ldata[k >> 3] >> (7 - (k & 7))) & 1) ? 1 : 0;
190 basepos = basepos + (face->glyph->advance.x >> 6);
194 void ft_render_text(FT_Face face, const std::string& text, std::vector<uint8_t>& data, size_t width,
195 size_t height, ssize_t alignment, size_t spacing, size_t y = 0)
197 std::string _text = text;
198 //If the string contains linefeeds, break it up.
199 size_t p = _text.find("\\n");
200 if(p < _text.length()) {
201 std::string t1 = _text.substr(0, p);
202 std::string t2 = _text.substr(p + 2);
203 auto g1 = ft_rendered_size_line(face, t1);
204 ft_render_text_line(face, t1, data, width, height, alignment, y, g1);
205 ft_render_text(face, t2, data, width, height, alignment, spacing, y + g1.height + spacing);
206 return;
208 //The text is in one piece if this place is reached.
209 auto g1 = ft_rendered_size_line(face, text);
210 ft_render_text_line(face, text, data, width, height, alignment, y, g1);
213 std::pair<size_t, size_t> ft_rendered_size(FT_Face face, const std::string& text, size_t spacing)
215 std::string _text = text;
216 //If the string contains linefeeds, break it up.
217 size_t p = _text.find("\\n");
218 if(p < _text.length()) {
219 std::string t1 = _text.substr(0, p);
220 std::string t2 = _text.substr(p + 2);
221 auto g1 = ft_rendered_size_line(face, t1);
222 auto g2 = ft_rendered_size(face, t2, spacing);
223 size_t w, h;
224 w = (g1.width > g2.first) ? g1.width : g2.first;
225 h = g1.height + spacing + g2.second;
226 return std::make_pair(w, h);
228 //The text is in one piece if this place is reached.
229 auto g = ft_rendered_size_line(face, text);
230 return std::make_pair(g.width, g.height);
233 std::string read_subtitle_from_file(std::string filename)
235 std::string content;
236 std::string tmp;
237 std::ifstream x(filename);
238 if(!x)
239 throw std::runtime_error("Can't open '" + filename + "'");
240 while(std::getline(x, tmp)) {
241 if(content != "")
242 content = content + "\n" + tmp;
243 else
244 content = tmp;
246 std::ostringstream content2;
247 for(size_t i = 0; i < content.length(); i++)
248 if(content[i] == '\n')
249 content2 << "\\n";
250 else if(content[i] == '\\')
251 content2 << "\\\\";
252 else
253 content2 << content[i];
254 return content2.str();
257 ssize_t position_subtitle(size_t space, size_t size, int32_t pos, bool absolute)
259 if(absolute)
260 return pos;
261 else {
262 ssize_t freespace = space - size;
263 return ((pos + 1000) * freespace) / 2000;
267 yuvc_converter* get_converter(const regex_results& r)
269 std::string csp = "rec601";
270 if(r)
271 csp = r[1];
272 yuvc_converter* c = yuvc_get_converter(RGB_RGB, csp);
273 if(c)
274 return c;
275 if(r)
276 std::cerr << "Warning: Stream YUV variant unspecified, assuming rec601." << std::endl;
277 else
278 std::cerr << "Warning: Stream YUV variant unsupported, falling back to rec601." << std::endl;
279 return yuvc_get_converter(RGB_RGB, "rec601");
282 void stamp_pos(size_t space, size_t dimension, ssize_t pos, size_t& fpos, size_t& spos, size_t& sdim)
284 sdim = dimension;
285 if(pos < 0) {
286 spos = -pos;
287 if(sdim <= spos) {
288 fpos = 0;
289 spos = 0;
290 sdim = 0;
291 return;
293 sdim = sdim + pos;
294 fpos = 0;
295 } else {
296 spos = 0;
297 fpos = pos;
299 if(fpos > space)
300 sdim = 0;
301 else if(fpos + sdim > space)
302 sdim = space - fpos;
306 std::pair<size_t, size_t> text_render_parameters::render_size(const std::string& text)
308 FT_Face face;
310 //Init freetype2 if needed.
311 if(!ft_init)
312 throw_ft_error(FT_Init_FreeType(&ft_handle));
313 ft_init = true;
315 //Load the font face.
316 if(fontfile == "")
317 throw std::runtime_error("Font file needed for text rendering");
318 throw_ft_error(FT_New_Face(ft_handle, fontfile.c_str(), fontface, &face));
319 throw_ft_error(FT_Set_Pixel_Sizes(face, 0, fontsize));
321 auto g = ft_rendered_size(face, text, text_spacing);
322 return std::make_pair(g.first + 2 * halo_thickness, g.second + 2 * halo_thickness);
325 parsed_png& text_render_parameters::render(const std::string& text)
327 FT_Face face;
328 std::vector<uint8_t> tmp;
329 size_t width, height;
330 size_t width2, height2;
332 //Init freetype2 if needed.
333 if(!ft_init)
334 throw_ft_error(FT_Init_FreeType(&ft_handle));
335 ft_init = true;
337 //Load the font face.
338 if(fontfile == "")
339 throw std::runtime_error("Font file needed for text rendering");
340 throw_ft_error(FT_New_Face(ft_handle, fontfile.c_str(), fontface, &face));
341 throw_ft_error(FT_Set_Pixel_Sizes(face, 0, fontsize));
343 //First we need to figure out the size of the rendered bitmap. Then render the actual bitmap.
344 auto g = ft_rendered_size(face, text, text_spacing);
345 width = g.first;
346 height = g.second;
347 width2 = width + 2 * halo_thickness;
348 height2 = height + 2 * halo_thickness;
349 tmp.resize(width2 * height2);
350 memset(&tmp[0], 0, width2 * height2);
351 ft_render_text(face, text, tmp, width, height, text_alignment, text_spacing);
353 //Do in-place padding by halo_thickness on all sides.
354 if(halo_thickness > 0) {
355 for(size_t i = height - 1; i < height; i--)
356 memmove(&tmp[width2 * (i + halo_thickness) + halo_thickness], &tmp[width * i], width);
357 for(size_t i = 0; i < height; i++) {
358 memset(&tmp[width2 * (i + halo_thickness)], 0, halo_thickness);
359 memset(&tmp[width2 * (i + halo_thickness + 1) - halo_thickness], 0, halo_thickness);
361 memset(&tmp[0], 0, width2 * halo_thickness);
362 render_halo(&tmp[0], &tmp[0], width2, height2, halo_thickness);
365 parsed_png& png = *new parsed_png(width2, height2);
366 for(size_t i = 0; i < width2 * height2; i++) {
367 if(tmp[i] == 0) png.data[i] = bg_color;
368 if(tmp[i] == 1) png.data[i] = fg_color;
369 if(tmp[i] == 2) png.data[i] = halo_color;
371 return png;
374 text_render_parameters::text_render_parameters()
376 fontsize = 12;
377 text_alignment = 0;
378 text_spacing = 0;
379 fontface = 0;
380 fg_color = 0xFFFFFFFFU;
381 halo_color = 0xFF000000U;
382 bg_color = 0;
383 halo_thickness = 1;
386 bool text_render_parameters::argument(const std::string& arg)
388 regex_results r;
389 if(r = regex("--font-file=(.*)", arg)) {
390 fontfile = r[1];
391 return true;
392 } else if(r = regex("--font-size=(.*)", arg)) {
393 fontsize = parse_value<unsigned>(r[1]);
394 return true;
395 } else if(r = regex("--text-alignment=left", arg)) {
396 text_alignment = -1000;
397 return true;
398 } else if(r = regex("--text-alignment=center", arg)) {
399 text_alignment = 0;
400 return true;
401 } else if(r = regex("--text-alignment=right", arg)) {
402 text_alignment = 1000;
403 return true;
404 } else if(r = regex("--text-alignment=(.*)", arg)) {
405 text_alignment = parse_value<signed>(r[1]);
406 return true;
407 } else if(r = regex("--text-spacing=(.*)", arg)) {
408 text_spacing = parse_value<signed>(r[1]);
409 return true;
410 } else if(r = regex("--font-face=(.*)", arg)) {
411 fontface = parse_value<long>(r[1]);
412 return true;
413 } else if(r = regex("--fg-color=(.*),(.*),(.*),(.*)", arg)) {
414 unsigned R = parse_value<unsigned>(r[1]);
415 unsigned g = parse_value<unsigned>(r[2]);
416 unsigned b = parse_value<unsigned>(r[3]);
417 unsigned a = parse_value<unsigned>(r[4]);
418 fg_color = (a << 24) | (b << 16) | (g << 8) | R;
419 return true;
420 } else if(r = regex("--fg-color=(.*),(.*),(.*)", arg)) {
421 unsigned R = parse_value<unsigned>(r[1]);
422 unsigned g = parse_value<unsigned>(r[2]);
423 unsigned b = parse_value<unsigned>(r[3]);
424 fg_color = (fg_color & 0xFF000000U) | (b << 16) | (g << 8) | R;
425 return true;
426 } else if(r = regex("--fg-alpha=(.*)", arg)) {
427 unsigned a = parse_value<unsigned>(r[1]);
428 fg_color = (fg_color & 0xFFFFFFU) | (a << 24);
429 return true;
430 } else if(r = regex("--bg-color=(.*),(.*),(.*),(.*)", arg)) {
431 unsigned R = parse_value<unsigned>(r[1]);
432 unsigned g = parse_value<unsigned>(r[2]);
433 unsigned b = parse_value<unsigned>(r[3]);
434 unsigned a = parse_value<unsigned>(r[4]);
435 bg_color = (a << 24) | (b << 16) | (g << 8) | R;
436 return true;
437 } else if(r = regex("--bg-color=(.*),(.*),(.*)", arg)) {
438 unsigned R = parse_value<unsigned>(r[1]);
439 unsigned g = parse_value<unsigned>(r[2]);
440 unsigned b = parse_value<unsigned>(r[3]);
441 bg_color = (bg_color & 0xFF000000U) | (b << 16) | (g << 8) | R;
442 return true;
443 } else if(r = regex("--bg-alpha=(.*)", arg)) {
444 unsigned a = parse_value<unsigned>(r[1]);
445 bg_color = (bg_color & 0xFFFFFFU) | (a << 24);
446 return true;
447 } else if(r = regex("--halo-color=(.*),(.*),(.*),(.*)", arg)) {
448 unsigned R = parse_value<unsigned>(r[1]);
449 unsigned g = parse_value<unsigned>(r[2]);
450 unsigned b = parse_value<unsigned>(r[3]);
451 unsigned a = parse_value<unsigned>(r[4]);
452 halo_color = (a << 24) | (b << 16) | (g << 8) | R;
453 return true;
454 } else if(r = regex("--halo-color=(.*),(.*),(.*)", arg)) {
455 unsigned R = parse_value<unsigned>(r[1]);
456 unsigned g = parse_value<unsigned>(r[2]);
457 unsigned b = parse_value<unsigned>(r[3]);
458 halo_color = (halo_color & 0xFF000000U) | (b << 16) | (g << 8) | R;
459 return true;
460 } else if(r = regex("--halo-alpha=(.*)", arg)) {
461 unsigned a = parse_value<unsigned>(r[1]);
462 halo_color = (halo_color & 0xFFFFFFU) | (a << 24);
463 return true;
464 } else if(r = regex("--halo-thickness=(.*)", arg)) {
465 halo_thickness = parse_value<unsigned>(r[1]);
466 if(halo_thickness < 0)
467 halo_thickness = 0;
468 return true;
469 } else
470 return false;
473 pre_subtitle::pre_subtitle()
475 image = NULL;
478 pre_subtitle::~pre_subtitle()
480 delete[] image;
483 subtitle::subtitle(const pre_subtitle& presub, const yuv4mpeg_stream_header& strmh)
485 double fps = 25;
486 if(strmh.fps_n && strmh.fps_d)
487 fps = 1.0 * strmh.fps_n / strmh.fps_d;
488 frame = presub.start.get_frame(fps, 0);
489 duration = presub.duration.get_frame(fps, 0);
490 width = presub.image->width;
491 height = presub.image->height;
492 x = position_subtitle(strmh.width, width, presub.xpos, presub.xabsolute);
493 y = position_subtitle(strmh.height, height, presub.ypos, presub.yabsolute);
494 if(x < 0 || y < 0 || x + width > strmh.width || y + height > strmh.height)
495 std::cerr << "Warning: Subtitle is partially offscreen" << std::endl;
497 if(strmh.chroma == "rgb") {
498 bits16 = false;
499 data = new uint8_t[width * height * 3];
500 planes = 1;
501 planesep = width * height * 3;
502 for(size_t i = 0; i < width * height; i++) {
503 data[3 * i + 0] = presub.image->data[i];
504 data[3 * i + 1] = presub.image->data[i] >> 8;
505 data[3 * i + 2] = presub.image->data[i] >> 16;
507 } else if(strmh.chroma == "444" || strmh.chroma == "444p16") {
508 std::vector<uint8_t> tmp;
509 bits16 = (strmh.chroma == "444p16");
510 tmp.resize(width * height * 3);
511 data = new uint8_t[width * height * (bits16 ? 6 : 3)];
512 uint16_t* data16 = reinterpret_cast<uint16_t*>(data);
513 planes = 3;
514 planesep = width * height;
515 yuvc_converter* conv = get_converter(strmh.find_extension("yuvmatrix=(.*)"));
516 for(size_t i = 0; i < width * height; i++) {
517 tmp[3 * i + 0] = presub.image->data[i];
518 tmp[3 * i + 1] = presub.image->data[i] >> 8;
519 tmp[3 * i + 2] = presub.image->data[i] >> 16;
521 if(bits16)
522 conv->transform(data16, &tmp[0], width * height);
523 else
524 conv->transform(data, &tmp[0], width * height);
525 } else
526 (stringfmt() << "Chroma type " << strmh.chroma << " not supported for subtitling").throwex();
527 alpha = new uint32_t[width * height];
528 if(bits16)
529 for(size_t i = 0; i < width * height; i++)
530 alpha[i] = ((presub.image->data[i] >> 24) + (presub.image->data[i] >> 31)) << 8;
531 else
532 for(size_t i = 0; i < width * height; i++)
533 alpha[i] = (presub.image->data[i] >> 24) + (presub.image->data[i] >> 31);
536 subtitle::~subtitle()
538 delete[] data;
539 delete[] alpha;
543 subtitle_render_context::subtitle_render_context()
545 xpos = 0;
546 ypos = -1000;
547 xabsolute = false;
548 yabsolute = false;
549 duration = timemarker("5.0");
552 bool subtitle_render_context::argument(const std::string& arg, pre_subtitle*& presub)
554 regex_results r;
555 if(tparams.argument(arg))
556 return true;
557 if(r = regex("--(text|file|png)=([^,]*),(.*)", arg)) {
558 std::string text = r[3];
559 timemarker start(r[2]);
560 parsed_png* png;
561 if(r[1] == "file")
562 text = read_subtitle_from_file(text);
563 if(r[1] == "png")
564 png = new parsed_png(text);
565 else
566 png = &tparams.render(text);
567 presub = new pre_subtitle;
568 presub->image = png;
569 presub->xpos = xpos;
570 presub->ypos = ypos;
571 presub->xabsolute = xabsolute;
572 presub->yabsolute = yabsolute;
573 presub->start = start;
574 presub->duration = duration;
575 return true;
576 } else if(r = regex("--duration=(.*)", arg)) {
577 duration = timemarker(r[1]);
578 return true;
579 } else if(r = regex("--xpos=left", arg)) {
580 xabsolute = false;
581 xpos = -1000;
582 return true;
583 } else if(r = regex("--xpos=center", arg)) {
584 xabsolute = false;
585 xpos = 0;
586 return true;
587 } else if(r = regex("--xpos=right", arg)) {
588 xabsolute = false;
589 xpos = 1000;
590 return true;
591 } else if(r = regex("--xpos=abs:([+-]?[0-9]+)", arg)) {
592 xabsolute = true;
593 xpos = parse_value<ssize_t>(r[1]);
594 return true;
595 } else if(r = regex("--xpos=([+-]?[0-9]+)", arg)) {
596 xabsolute = false;
597 xpos = parse_value<ssize_t>(r[1]);
598 return true;
599 } else if(r = regex("--ypos=top", arg)) {
600 yabsolute = false;
601 ypos = -1000;
602 return true;
603 } else if(r = regex("--ypos=center", arg)) {
604 yabsolute = false;
605 ypos = 0;
606 return true;
607 } else if(r = regex("--ypos=bottom", arg)) {
608 yabsolute = false;
609 ypos = 1000;
610 return true;
611 } else if(r = regex("--ypos=abs:([+-]?[0-9]+)", arg)) {
612 yabsolute = true;
613 ypos = parse_value<ssize_t>(r[1]);
614 return true;
615 } else if(r = regex("--ypos=([+-]?[0-9]+)", arg)) {
616 yabsolute = false;
617 ypos = parse_value<ssize_t>(r[1]);
618 return true;
619 } else {
620 return false;
624 std::vector<subtitle*> subtitle::from_presub(const std::vector<pre_subtitle*>& presubs,
625 const yuv4mpeg_stream_header& strmh)
627 std::vector<subtitle*> ret;
628 for(auto i : presubs) {
629 try {
630 ret.push_back(new subtitle(*i, strmh));
631 } catch(...) {
632 for(auto j : ret)
633 delete j;
636 return ret;
639 void subtitle::stamp(uint8_t* idata, size_t iwidth, size_t iheight, uint64_t frameno) const
641 if(frameno < frame || frameno > frame + duration)
642 return;
643 size_t fpos_x, spos_x, swidth;
644 size_t fpos_y, spos_y, sheight;
645 stamp_pos(iwidth, width, x, fpos_x, spos_x, swidth);
646 stamp_pos(iheight, height, y, fpos_y, spos_y, sheight);
647 if(!swidth || !sheight)
648 return;
649 if(planes == 3 && bits16) {
650 size_t iplanesep = iwidth * iheight;
651 uint16_t* idata2 = reinterpret_cast<uint16_t*>(idata);
652 const uint16_t* data2 = reinterpret_cast<const uint16_t*>(data);
653 for(size_t i = 0; i < sheight; i++)
654 for(size_t j = 0; j < swidth; j++) {
655 size_t ioffset = (fpos_y + i) * iwidth + (fpos_x + j);
656 size_t offset = (spos_y + i) * width + (spos_x + j);
657 mix(idata2[ioffset], data2[offset], alpha[offset]);
658 mix(idata2[ioffset + iplanesep], data2[offset + planesep], alpha[offset]);
659 mix(idata2[ioffset + iplanesep], data2[offset + planesep], alpha[offset]);
661 } else if(planes == 3 && !bits16) {
662 size_t iplanesep = iwidth * iheight;
663 for(size_t i = 0; i < sheight; i++)
664 for(size_t j = 0; j < swidth; j++) {
665 size_t ioffset = (fpos_y + i) * iwidth + (fpos_x + j);
666 size_t offset = (spos_y + i) * width + (spos_x + j);
667 mix(idata[ioffset], data[offset], alpha[offset]);
668 mix(idata[ioffset + iplanesep], data[offset + planesep], alpha[offset]);
669 mix(idata[ioffset + 2 * iplanesep], data[offset + 2 * planesep], alpha[offset]);
671 } else if(planes == 1) {
672 for(size_t i = 0; i < sheight; i++)
673 for(size_t j = 0; j < swidth; j++) {
674 size_t ioffset = (fpos_y + i) * 3 * iwidth + 3 * (fpos_x + j);
675 size_t offset2 = (spos_y + i) * width + (spos_x + j);
676 size_t offset = offset2 * 3;
677 mix(idata[ioffset], data[offset], alpha[offset2]);
678 mix(idata[ioffset + 1], data[offset + 1], alpha[offset2]);
679 mix(idata[ioffset + 2], data[offset + 2], alpha[offset2]);