当前位置:   article > 正文

C++ OSD水印叠加_rk1126 osd叠加

rk1126 osd叠加

视频相关领域(监控、LED大屏)很多场合可能会涉及到在一幅画面上进行文字或时间的叠加,常规做法都是在后端实现,即先渲染图像,然后叠加OSD文字信息,这种方法简单且高效。但是有些场合必须要求在前端进行叠加,比如监控领域中视频名称信息、时间信息等这些都需要在前端图像编码的时候就已经叠加到图像上,以防止用户修改和验伪。如果你有这种想法,那么这篇文章就算是帮助到你了,算是抛砖引玉的作用吧。

示例中采用jpeg图像作为底图,所以需要借助libjpeg将图像解码还原RGB原始图像数据,叠加OSD文字信息需借助freetype生成点阵RGB图像数据,然后对2个图像进行像素合并或重写。

  1. // JpegOSD.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. //
  3. #define _CRT_SECURE_NO_WARNINGS
  4. #include <iostream>
  5. #include <fstream>
  6. #include <string>
  7. #include <windows.h>
  8. #include "./libjpeg-turbo-win/jpeglib.h"
  9. #include "./libjpeg-turbo-win/jerror.h"
  10. #ifdef _DEBUG
  11. #pragma comment(lib, "./x64/debug/libjpeg-turbo-win.lib")
  12. #else
  13. #pragma comment(lib, "./x64/release/libjpeg-turbo-win.lib")
  14. #endif // _DEBUG
  15. #include "ft2build.h"
  16. #include FT_FREETYPE_H
  17. #pragma comment(lib, "./freetype/freetype.lib")
  18. // 将图像数据编码为.jpeg图像文件
  19. bool saveJPEG(const char* filename, const unsigned char* image, int width, int height, int channels, int quality) {
  20. struct jpeg_compress_struct cinfo;
  21. struct jpeg_error_mgr jerr;
  22. FILE* file = fopen(filename, "wb");
  23. if (!file) {
  24. std::cout << "无法创建文件:" << filename << std::endl;
  25. return false;
  26. }
  27. cinfo.err = jpeg_std_error(&jerr);
  28. jpeg_create_compress(&cinfo);
  29. jpeg_stdio_dest(&cinfo, file);
  30. cinfo.image_width = width;
  31. cinfo.image_height = height;
  32. cinfo.input_components = channels;
  33. cinfo.in_color_space = JCS_RGB;
  34. jpeg_set_defaults(&cinfo);
  35. jpeg_set_quality(&cinfo, quality, TRUE);
  36. jpeg_start_compress(&cinfo, TRUE);
  37. JSAMPROW row_pointer[1];
  38. while (cinfo.next_scanline < cinfo.image_height) {
  39. row_pointer[0] = const_cast<JSAMPROW>(&image[cinfo.next_scanline * width * channels]);
  40. jpeg_write_scanlines(&cinfo, row_pointer, 1);
  41. }
  42. jpeg_finish_compress(&cinfo);
  43. fclose(file);
  44. jpeg_destroy_compress(&cinfo);
  45. return true;
  46. }
  47. int main()
  48. {
  49. const char* filename = "D:/1.jpg";
  50. FILE* file = fopen(filename, "rb");
  51. if (!file) {
  52. std::cout << "打开文件失败: " << filename << std::endl;
  53. return -1;
  54. }
  55. unsigned long long dw1 = GetTickCount64();
  56. jpeg_decompress_struct cinfo;
  57. jpeg_error_mgr jerr;
  58. cinfo.err = jpeg_std_error(&jerr);
  59. jpeg_create_decompress(&cinfo);
  60. // 加载图像文件
  61. jpeg_stdio_src(&cinfo, file);
  62. // 获取图像压缩信息
  63. jpeg_read_header(&cinfo, TRUE);
  64. jpeg_start_decompress(&cinfo);
  65. // 获取图像信息
  66. int width = cinfo.output_width;
  67. int height = cinfo.output_height;
  68. int channels = cinfo.output_components;
  69. // 申请图像数据内存
  70. unsigned char* image = new unsigned char[width * height * channels];
  71. while (cinfo.output_scanline < cinfo.output_height) {
  72. unsigned char* row = image + (cinfo.output_scanline * width * channels);
  73. jpeg_read_scanlines(&cinfo, &row, 1);
  74. }
  75. //加载FreeType字体库
  76. FT_Library ftLibrary;
  77. if (FT_Init_FreeType(&ftLibrary)) {
  78. std::cout << "Failed to initialize FreeType library" << std::endl;
  79. return -1;
  80. }
  81. FT_Face ftFace;
  82. if (FT_New_Face(ftLibrary, "font.ttf", 0, &ftFace)) {
  83. std::cout << "Failed to load font file" << std::endl;
  84. FT_Done_FreeType(ftLibrary);
  85. return -1;
  86. }
  87. // 设置字符大小
  88. int fontSize = 48;
  89. FT_Set_Pixel_Sizes(ftFace, 0, fontSize);
  90. // 叠加OSD字符信息
  91. const char* osdString = "Hello World!";
  92. // OSD颜色
  93. unsigned char textColor[4] = { 255, 0, 0, 255 }; // 红色
  94. // OSD叠加位置
  95. int posX = 100;
  96. int posY = 200;
  97. // 水印叠加
  98. for (int i = 0; i < strlen(osdString); ++i) {
  99. if (FT_Load_Char(ftFace, osdString[i], FT_LOAD_RENDER))
  100. continue;
  101. FT_GlyphSlot ftGlyph = ftFace->glyph;
  102. int glyphWidth = ftGlyph->bitmap.width;
  103. int glyphHeight = ftGlyph->bitmap.rows;
  104. unsigned char* glyphBitmap = ftGlyph->bitmap.buffer;
  105. for (int y = 0; y < glyphHeight; ++y) {
  106. for (int x = 0; x < glyphWidth; ++x) {
  107. if (glyphBitmap[y * glyphWidth + x] != 0x00)//透明叠加
  108. {
  109. int imgX = posX + ftGlyph->bitmap_left + x;
  110. int imgY = posY - ftGlyph->bitmap_top + y;
  111. if (imgX >= 0 && imgX < width && imgY >= 0 && imgY < height) {
  112. int pixelIndex = (imgY * width + imgX) * channels;
  113. for (int c = 0; c < channels; ++c) {
  114. image[pixelIndex + c] = textColor[c];
  115. }
  116. }
  117. }
  118. }
  119. }
  120. posX += ftGlyph->advance.x >> 6; // 移动到下一个字符的位置
  121. }
  122. unsigned long long dw2 = GetTickCount64();
  123. std::cout << "水印叠加时间:" << (dw2 - dw1) << "ms" << std::endl;
  124. // 将修改后的图像数据编码为.jpeg图像文件
  125. const char* outputFilename = "D:/watermarked_image.jpg";
  126. int quality = 90;
  127. if (!saveJPEG(outputFilename, image, width, height, channels, quality)) {
  128. std::cout << "Failed to save JPEG file: " << outputFilename << std::endl;
  129. }
  130. else {
  131. unsigned long long dw3 = GetTickCount64();
  132. std::cout << "水印图像已保存至:" << outputFilename << ",保存时间:" << (dw3 - dw2) << "ms" << std::endl;
  133. }
  134. // 释放内存
  135. delete[] image;
  136. FT_Done_Face(ftFace);
  137. FT_Done_FreeType(ftLibrary);
  138. jpeg_finish_decompress(&cinfo);
  139. jpeg_destroy_decompress(&cinfo);
  140. fclose(file);
  141. return 0;
  142. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/354330
推荐阅读
相关标签
  

闽ICP备14008679号