如何在SDL2中无窗口绘制矩形并保存图片?
问题
能否在不弹出窗口的情况下,在图片上绘制矩形?我已通过以下代码实现了在图片上绘制矩形,但不想弹出窗口,是否可行?我想要实现的流程是:加载JPG图片→绘制矩形→保存为JPG。
int main(int argc, char** argv) { bool quit = false; SDL_Event event; SDL_Init(SDL_INIT_VIDEO); IMG_Init(IMG_INIT_JPG); SDL_Window* window = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0); SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0); SDL_Surface* image = IMG_Load("test.jpg"); if (!image) { printf("Image NULL\n"); return -1; } SDL_Texture* texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, image->w, image->h); image = SDL_ConvertSurfaceFormat(image, SDL_PIXELFORMAT_ARGB8888, 0); while (!quit) { SDL_UpdateTexture(texture, NULL, image->pixels, image->w * sizeof(Uint32)); SDL_WaitEvent(&event); switch (event.type) { case SDL_QUIT: quit = true; break; } SDL_SetRenderDrawColor(renderer, 136, 8, 8, 255); SDL_Rect dstrect = { 20, 10, 320, 145}; SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderDrawRect(renderer, &dstrect); SDL_RenderPresent(renderer); } SDL_DestroyTexture(texture); SDL_FreeSurface(image); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); IMG_Quit(); SDL_Quit(); return 0; }
解决方案
当然可以实现——完全不需要弹出可见窗口就能完成图片加载、绘制矩形和保存的流程。以下是两种高效的实现方案:
方案一:直接在SDL_Surface上绘制矩形
跳过渲染器和窗口,直接在图像表面上操作像素绘制矩形,这种方式轻量且高效:
#include <SDL2/SDL.h> #include <SDL2/SDL_image.h> #include <stdio.h> int main(int argc, char** argv) { SDL_Init(SDL_INIT_VIDEO); IMG_Init(IMG_INIT_JPG); // 加载原始JPG图片 SDL_Surface* image = IMG_Load("test.jpg"); if (!image) { printf("加载图片失败: %s\n", IMG_GetError()); return -1; } // 转换为支持Alpha的ARGB8888格式(确保颜色绘制正常) SDL_Surface* drawSurface = SDL_ConvertSurfaceFormat(image, SDL_PIXELFORMAT_ARGB8888, 0); SDL_FreeSurface(image); // 释放原始表面 if (!drawSurface) { printf("格式转换失败: %s\n", SDL_GetError()); IMG_Quit(); SDL_Quit(); return -1; } // 将目标颜色映射为表面支持的像素格式 SDL_Color rectColor = {136, 8, 8, 255}; Uint32 color = SDL_MapRGBA(drawSurface->format, rectColor.r, rectColor.g, rectColor.b, rectColor.a); // 定义要绘制的矩形区域 SDL_Rect dstrect = {20, 10, 320, 145}; // 绘制矩形边框(逐像素操作) // 绘制上下边 for (int x = dstrect.x; x < dstrect.x + dstrect.w; x++) { Uint32* topPixel = (Uint32*)((Uint8*)drawSurface->pixels + dstrect.y * drawSurface->pitch + x * sizeof(Uint32)); *topPixel = color; Uint32* bottomPixel = (Uint32*)((Uint8*)drawSurface->pixels + (dstrect.y + dstrect.h - 1) * drawSurface->pitch + x * sizeof(Uint32)); *bottomPixel = color; } // 绘制左右边 for (int y = dstrect.y; y < dstrect.y + dstrect.h; y++) { Uint32* leftPixel = (Uint32*)((Uint8*)drawSurface->pixels + y * drawSurface->pitch + dstrect.x * sizeof(Uint32)); *leftPixel = color; Uint32* rightPixel = (Uint32*)((Uint8*)drawSurface->pixels + y * drawSurface->pitch + (dstrect.x + dstrect.w - 1) * sizeof(Uint32)); *rightPixel = color; } // 保存修改后的图片到output.jpg,质量设为90(0-100,数值越高质量越好) if (!IMG_SaveJPG(drawSurface, "output.jpg", 90)) { printf("保存图片失败: %s\n", IMG_GetError()); } else { printf("图片已成功保存为output.jpg\n"); } // 释放所有资源 SDL_FreeSurface(drawSurface); IMG_Quit(); SDL_Quit(); return 0; }
方案二:使用离屏渲染器(隐藏窗口)
如果习惯用SDL渲染器的API,可以创建一个隐藏窗口,在后台完成渲染,再导出结果:
#include <SDL2/SDL.h> #include <SDL2/SDL_image.h> #include <stdio.h> int main(int argc, char** argv) { SDL_Init(SDL_INIT_VIDEO); IMG_Init(IMG_INIT_JPG); // 加载原始图片 SDL_Surface* image = IMG_Load("test.jpg"); if (!image) { printf("加载图片失败: %s\n", IMG_GetError()); return -1; } // 创建与图片尺寸一致的隐藏窗口 SDL_Window* window = SDL_CreateWindow("Hidden Render", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, image->w, image->h, SDL_WINDOW_HIDDEN); // 创建软件渲染器(避免依赖硬件加速) SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_SOFTWARE); // 将图片转换为纹理 SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, image); SDL_FreeSurface(image); // 设置矩形绘制颜色(红棕色) SDL_SetRenderDrawColor(renderer, 136, 8, 8, 255); // 执行渲染流程 SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, NULL); // 绘制原始图片 SDL_Rect dstrect = {20, 10, 320, 145}; SDL_RenderDrawRect(renderer, &dstrect); // 绘制矩形边框 SDL_RenderPresent(renderer); // 将渲染结果读取到Surface中 SDL_Surface* resultSurface = SDL_CreateRGBSurface(0, image->w, image->h, 32, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000); SDL_RenderReadPixels(renderer, NULL, resultSurface->format->format, resultSurface->pixels, resultSurface->pitch); // 保存图片 if (!IMG_SaveJPG(resultSurface, "output.jpg", 90)) { printf("保存图片失败: %s\n", IMG_GetError()); } else { printf("图片已成功保存为output.jpg\n"); } // 释放资源 SDL_FreeSurface(resultSurface); SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); IMG_Quit(); SDL_Quit(); return 0; }
核心优化点
- 移除了原代码中的事件循环和窗口显示逻辑,避免弹出窗口
- 新增
IMG_SaveJPG调用,完成最终图片的保存 - 方案一直接操作像素,性能开销更低;方案二兼容SDL渲染器的API,适合复杂绘制场景
- 确保所有SDL资源都被正确释放,避免内存泄漏
内容的提问来源于stack exchange,提问作者lifang
相关产品推荐
相关产品推荐

