嵌入式 SDL进行图片的切割与移动

本文介绍了一位博主如何在嵌入式环境中使用SDL库将一张400*400像素的图片切割成四个圆形,并尝试将背景设为透明。博主在SDL_fun.h中创建了一个类来管理屏幕接口,并展示了drawClips方法的实现,用于图片切割。在main函数中,博主展示了图片切割的效果,但未能完全实现背景透明。最后,博主讨论了如何结合SDL的按键事件功能实现图片的移动。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

测试Demo,但不要以为就可以随意为之,良好的代码风格和设计思想在哪都是需要注意的

下面来看看博主的工程结构:

工程下多了一个sheet.jpg,这就是今天要用于切割的图片

图片是400 * 400 pixel(像素)
接下来我们要做的工作就是,把这张图切割成4个圆,并且把背景变成透明

说明:博主在SDL_fun.h这个头文件中增加了一个类,用于管理全局唯一的屏幕接口我的考虑是,screen surface实际上只需要建立一个。并且,其他的surface实际上都是“依赖”于这个surface才能显示出来的。在SDL中,多次SDL_SetVideoMode()的效果实际上是保留了最后一次的surface作为了screen surface,所以,多次SDL_SetVideoMode()其实是没有实际意义的。

01 
07 
08#ifndef SDL_FUN_H_
09#define SDL_FUN_H_
10 
11#include
12#include
13 
14class ScreenSurface{
15 
16public:
17ScreenSurface(SDL_Surface* screen);
18ScreenSurface(int width, int height, int bpp = 32, Uint32 flags = SDL_SWSURFACE);
19~ScreenSurface(void);
20bool flip(void) const;
21SDL_Surface* acquire(void);
22 
23private:
24SDL_Surface* screen;
25};
26 
27void drawBitmap(ScreenSurface s, const char* fileName);
28void readKeyboard(ScreenSurface s);
29void getRadioInfo(ScreenSurface s);
30void renderPictures(ScreenSurface s, const char* fgFile, const char* bgFile);
31void drawClips(ScreenSurface s, const char* file, SDL_Rect* clip = NULL, int size = 0);
32 
33#endif
大家看到了吧,其中的ScreenSurface的flip方法是将数据化的SDL_Surface Push到屏幕上,让用户看到,而acquire是获取当前的屏幕接口,其他的就是一些构造方法和构析方法。下面的方法都需要传一个ScreenSurface,这样是不是就统一管理了呢?全局就只需创建一个唯一的通向物理屏幕的接口~


头文件中的drawClips就是图片分割的方法,下面是它的实现:

01 
02void drawClips(ScreenSurface s, const char* file, SDL_Rect* clip, int size) {
03 
04SDL_Surface* dots = IMG_Load(file);
05SDL_Surface* optimizedImage = NULL;
06 
07if (s.acquire() == 0 || dots == 0 || clip == NULL) {
08std::cerr << SDL_GetError() << " 227 \n";
09return;
10} else {
11optimizedImage = SDL_DisplayFormat(dots);
12SDL_FreeSurface(dots);
13//这两句代码把图片背景置为透明
14Uint32 colorkey = SDL_MapRGB(optimizedImage->format, 0, 0xFF, 0xFF);
15SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, colorkey);
16}
17 
18//把整个背景填充为白色
19SDL_FillRect(s.acquire(), &s.acquire()->clip_rect,
20SDL_MapRGB(s.acquire()->format, 0xFF, 0xFF, 0xFF));
21 
22bool over = false;
23SDL_Event event;
24SDL_Rect offset;
25while (!over) {
26 
27SDL_ClearError();
28SDL_PollEvent(&event);
29if (event.type == SDL_QUIT || event.key.keysym.sym == SDLK_ESCAPE) {
30over = true;
31}
32//参数size代表图片切割的数量,也就是clip数组的数量
33for (int x = 0; x < size; x++) {
34 
35offset.x = clip[x].x + x*100;
36offset.y = clip[x].y + x*100;
37 
38if (SDL_BlitSurface(optimizedImage, &clip[x], s.acquire(), &offset)
39!= 0) {
40std::cerr << SDL_GetError() << " 275 \n";
41break;
42}
43}
44 
45if (!s.flip()) {
46std::cerr << SDL_GetError() << " 281\n";
47break;
48}
49}
50 
51SDL_FreeSurface(dots);
52}

再来看看main的入口函数:

01//===================================================================
02// Name : SDL_demo.cpp
03// Author : Christian
04// Version :
05// Copyright : Copyright (c) Christian 2012/9/28
06// Description : Hello World in C++, Ansi-style
07//===================================================================
08#include "include/SDL_init.h"
09#include "include/SDL_fun.h"
10 
11using namespace std;
12//这里定义了4个clip
13void cutPic(ScreenSurface s){
14SDL_Rect clip[4];
15//Clip range for the top left
16clip[0].x = 0;
17clip[0].y = 0;
18clip[0].w = 100;
19clip[0].h = 100;
20 
21//Clip range for the top right
22clip[1].x = 100;
23clip[1].y = 0;
24clip[1].w = 100;
25clip[1].h = 100;
26 
27//Clip range for the bottom left
28clip[2].x = 0;
29clip[2].y = 100;
30clip[2].w = 100;
31clip[2].h = 100;
32 
33//Clip range for the bottom right
34clip[3].x = 100;
35clip[3].y = 100;
36clip[3].w = 100;
37clip[3].h = 100;
38 
39drawClips(s, "sheet.jpg", clip, 4);
40}
41 
42int main(int argc, char* args[]) {
43//SDL_putenv("SDL_VIDEODRIVER=directx");
44//putenv("SDL_VIDEODRIVER=directx");
45 
46createSDL("Christian Test");
47ScreenSurface s(600, 600);
48 
49//drawBitmap(s, "3.jpg");
50//readKeyboard();
51//getRadioInfo();
52//renderPictures(s, "3.jpg", "2.bmp");
53cutPic(s);
54 
55 
56atexit(destorySDL);
57 
58return EXIT_SUCCESS;
59}

下面是运行效果:

博主是按照官网文档去做的,为什么图片背景还是没有完全透明请高手解答一下。

好了,图片切割完成!下面讲讲如果对图片进行移动~第一章的时候咱们不是讲了SDL的按键的事件功能么,是时候结合一下了~

下面是改动后的drawClips函数:

01 
02void drawClips(ScreenSurface s, const char* file, SDL_Rect* clip, int size) {
03 
04SDL_Surface* dots = IMG_Load(file);
05SDL_Surface* optimizedImage = NULL;
06 
07if (s.acquire() == 0 || dots == 0 || clip == NULL) {
08std::cerr << SDL_GetError() << " 227 \n";
09return;
10} else {
11optimizedImage = SDL_DisplayFormat(dots);
12SDL_FreeSurface(dots);
13 
14Uint32 colorkey = SDL_MapRGB(optimizedImage->format, 0, 0xFF, 0xFF);
15SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, colorkey);
16}
17 
18//把整个背景填充为白色
19SDL_FillRect(s.acquire(), &s.acquire()->clip_rect,
20SDL_MapRGB(s.acquire()->format, 0xFF, 0xFF, 0xFF));
21 
22bool over = false;
23SDL_Event event;
24SDL_Rect offset;
25Uint8* keys;
26offset.x = 0;
27offset.y = 0;
28 
29while (!over) {
30//从这里获取每个按键的即时状态,监听8个按键,w/s/a/d/up/down/left/right
31keys = SDL_GetKeyState(0);
32if (keys[SDLK_UP] || keys[SDLK_w]) {
33offset.y -= 1;
34}
35if (keys[SDLK_DOWN] || keys[SDLK_s]) {
36offset.y += 1;
37}
38if (keys[SDLK_LEFT] || keys[SDLK_a]) {
39offset.x -= 1;
40}
41if (keys[SDLK_RIGHT] || keys[SDLK_d]) {
42offset.x += 1;
43}
44 
45SDL_ClearError();
46SDL_PollEvent(&event);
47if (event.type == SDL_QUIT || event.key.keysym.sym == SDLK_ESCAPE) {
48over = true;
49}
50 
51for (int x = 0; x < size; x++) {
52 
53// offset.x = clip[x].x;
54// offset.y = clip[x].y;
55 
56if (SDL_BlitSurface(optimizedImage, &clip[x], s.acquire(), &offset)
57!= 0) {
58std::cerr << SDL_GetError() << " 275 \n";
59break;
60}
61}
62 
63if (!s.flip()) {
64std::cerr << SDL_GetError() << " 281\n";
65break;
66}
67}
68 
69SDL_FreeSurface(dots);
70}

好了,就这么简单~只需在轮询线程内加上事件监听,判断后做出响应即可
运行结果图:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值