placeholder.cpp 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #include <windows.h>
  2. #include <strsafe.h>
  3. #include <gdiplus.h>
  4. #include <stdint.h>
  5. #include <vector>
  6. using namespace Gdiplus;
  7. extern HINSTANCE dll_inst;
  8. static std::vector<uint8_t> placeholder;
  9. static bool initialized = false;
  10. int cx, cy;
  11. /* XXX: optimize this later. or don't, it's only called once. */
  12. static void convert_placeholder(const uint8_t *rgb_in, int width, int height)
  13. {
  14. size_t size = width * height * 3;
  15. size_t linesize = width * 3;
  16. std::vector<uint8_t> yuv_out;
  17. yuv_out.resize(size);
  18. const uint8_t *in = rgb_in;
  19. const uint8_t *end = in + size;
  20. uint8_t *out = &yuv_out[0];
  21. while (in < end) {
  22. const int16_t b = *(in++);
  23. const int16_t g = *(in++);
  24. const int16_t r = *(in++);
  25. *(out++) = (uint8_t)(((66 * r + 129 * g + 25 * b + 128) >> 8) + 16);
  26. *(out++) = (uint8_t)(((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128);
  27. *(out++) = (uint8_t)(((112 * r - 94 * g - 18 * b + 128) >> 8) + 128);
  28. }
  29. placeholder.resize(width * height * 3 / 2);
  30. in = &yuv_out[0];
  31. end = in + size;
  32. out = &placeholder[0];
  33. uint8_t *chroma = out + width * height;
  34. while (in < end) {
  35. const uint8_t *in2 = in + linesize;
  36. const uint8_t *end2 = in2;
  37. uint8_t *out2 = out + width;
  38. while (in < end2) {
  39. int16_t u;
  40. int16_t v;
  41. *(out++) = *(in++);
  42. u = *(in++);
  43. v = *(in++);
  44. *(out++) = *(in++);
  45. u += *(in++);
  46. v += *(in++);
  47. *(out2++) = *(in2++);
  48. u += *(in2++);
  49. v += *(in2++);
  50. *(out2++) = *(in2++);
  51. u += *(in2++);
  52. v += *(in2++);
  53. *(chroma++) = (uint8_t)(u / 4);
  54. *(chroma++) = (uint8_t)(v / 4);
  55. }
  56. in = in2;
  57. out = out2;
  58. }
  59. }
  60. static bool load_placeholder_internal()
  61. {
  62. Status s;
  63. wchar_t file[MAX_PATH];
  64. if (!GetModuleFileNameW(dll_inst, file, MAX_PATH)) {
  65. return false;
  66. }
  67. wchar_t *slash = wcsrchr(file, '\\');
  68. if (!slash) {
  69. return false;
  70. }
  71. slash[1] = 0;
  72. StringCbCat(file, sizeof(file), L"placeholder.png");
  73. Bitmap bmp(file);
  74. if (bmp.GetLastStatus() != Status::Ok) {
  75. return false;
  76. }
  77. cx = bmp.GetWidth();
  78. cy = bmp.GetHeight();
  79. BitmapData bmd = {};
  80. Rect r(0, 0, cx, cy);
  81. s = bmp.LockBits(&r, ImageLockModeRead, PixelFormat24bppRGB, &bmd);
  82. if (s != Status::Ok) {
  83. return false;
  84. }
  85. convert_placeholder((const uint8_t *)bmd.Scan0, cx, cy);
  86. bmp.UnlockBits(&bmd);
  87. return true;
  88. }
  89. bool initialize_placeholder()
  90. {
  91. if (initialized)
  92. return true;
  93. GdiplusStartupInput si;
  94. ULONG_PTR token;
  95. GdiplusStartup(&token, &si, nullptr);
  96. initialized = load_placeholder_internal();
  97. GdiplusShutdown(token);
  98. return initialized;
  99. }
  100. const uint8_t *get_placeholder_ptr()
  101. {
  102. if (initialized)
  103. return placeholder.data();
  104. return nullptr;
  105. }
  106. const bool get_placeholder_size(int *out_cx, int *out_cy)
  107. {
  108. if (initialized) {
  109. *out_cx = cx;
  110. *out_cy = cy;
  111. return true;
  112. }
  113. return false;
  114. }