반응형

렌더러에 그려진 화면을 BMP로 저장해 보자.

2025.04.18 - [C, C++] - [SDL3] Particle 파티클

위 링크를 참고해 눈내리는 장면을 연출한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#define SDL_MAIN_USE_CALLBACKS 1
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#include <stdio.h>
 
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
 
int screen_width = 640;
int screen_height = 480;
 
Uint64 start;
Uint64 end;
float fps;
 
typedef struct {
    float x, y;
    float vx, vy;
} s_particle;
 
const int number_particles = 400;
s_particle particles[number_particles];
 
// 파티클 이미지 텍스쳐와 렉트
SDL_Texture* texture;
SDL_FRect rect;
 
// 스냅샷
bool snap = false;
 
void spawn_particle(s_particle* pt) {
    pt->= (SDL_randf() * 2 - 1* screen_width * 10;
    pt->= SDL_randf() * screen_height * -2;
    // 넓은 범위에서 눈이 생성되게 해서 실행 초기에 눈이 쏟아져 내리는걸 방지.
    pt->vx = SDL_randf() * 0.5f; // 눈은 오른쪽으로만 흩날린다.
    pt->vy = SDL_randf() + 0.8f;
}
 
void draw_particle(s_particle pt[]) {
    for (int i = 0; i < number_particles; i++) {
        s_particle* particle = &particles[i];
        particle->+= particle->vx;
        particle->+= particle->vy;
        // 눈이 화면 왼쪽에서도 바람에 날려 올 수 있도록 생존 범위 조정.
        if (particle->> screen_width || particle->< -screen_width || particle->> screen_height)
            spawn_particle(particle);
 
        // 텍스쳐 그리기
        rect.x = particle->- rect.w / 2;
        rect.y = particle->- rect.h / 2;
        SDL_RenderTexture(renderer, texture, NULL&rect);
 
        //SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
        //SDL_RenderPoint(renderer, particle->x, particle->y);
    }
}
 
void take_snapshot(SDL_Renderer* renderer, const char* filename) {
    SDL_Surface* surface = SDL_RenderReadPixels(renderer, NULL);
    if (surface) {
        SDL_SaveBMP(surface, filename);
        SDL_DestroySurface(surface);
    }
    snap = false;
}
 
SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[])
{
    SDL_SetAppMetadata("Example""1.0""sean");
 
    if (!SDL_Init(SDL_INIT_VIDEO)) {
        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1");
    // A variable controlling whether updates to the SDL screen surface should be synchronized
    // with the vertical refresh, to avoid tearing.
 
    if (!SDL_CreateWindowAndRenderer("example", screen_width, screen_height, 0&window, &renderer)) {
        SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    for (int i = 0; i < number_particles; i++) {
        spawn_particle(&particles[i]);
    }
 
    // 비트맵 로드
    SDL_Surface* bmpSurface = SDL_LoadBMP("snow.bmp");
    if (!bmpSurface) {
        SDL_Log("Couldn't load BMP: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }
 
    // 컬러키(투명) 설정
    SDL_SetSurfaceColorKey(bmpSurface, true, SDL_MapSurfaceRGB(bmpSurface, 0x000x000x00));
    //SDL_SetSurfaceColorKey(bmpSurface, true, SDL_MapRGB(SDL_GetPixelFormatDetails(bmpSurface->format), NULL, 0x00, 0x00, 0x00));
    rect = { 00, (float)bmpSurface->w, (float)bmpSurface->h };
    texture = SDL_CreateTextureFromSurface(renderer, bmpSurface);
 
    SDL_DestroySurface(bmpSurface);
 
    return SDL_APP_CONTINUE;
}
 
SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
{
    switch (event->type) {
    case SDL_EVENT_QUIT:
        return SDL_APP_SUCCESS;
    case SDL_EVENT_KEY_DOWN:
        printf("Key pressed: %s\n", SDL_GetKeyName(event->key.key));
        if (event->key.key == SDLK_ESCAPE)
            return SDL_APP_SUCCESS;
        else if (event->key.key == SDLK_S)
            snap = true;
        break;
    default:
        break;
    }
 
    return SDL_APP_CONTINUE;
}
 
SDL_AppResult SDL_AppIterate(void* appstate)
{
    // FPS 계산. 사용하지는 않음.
    start = SDL_GetPerformanceCounter();
 
    {
        SDL_SetRenderDrawColor(renderer, 000, SDL_ALPHA_OPAQUE);
        SDL_RenderClear(renderer);
 
        draw_particle(particles);
 
        if (snap)
            take_snapshot(renderer, "snapshot.bmp");
 
        SDL_RenderPresent(renderer);
    }
 
    end = SDL_GetPerformanceCounter();
    fps = 1.0f / ((end - start) / (float)SDL_GetPerformanceFrequency());
 
    return SDL_APP_CONTINUE;
}
 
void SDL_AppQuit(void* appstate, SDL_AppResult result)
{
    SDL_DestroyTexture(texture);
 
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
}
 

 

bool snap 변수 선언, take_snapshot() 함수 선언, SDL_AppEvent()에서 's'키 입력 처리, SDL_AppIterate()에서 take_snapshot() 호출이 추가되었다.

 

프로그램을 실행하고 's'키를 누르면 snapshot.bmp 파일이 생성된다.

 

반응형
Posted by J-sean
:
반응형

간단히 화면을 캡쳐해 보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
using System.Windows.Forms;
using System.Drawing;
 
namespace CS
{
    class Program
    {
        static void Main(string[] args)
        {
            Bitmap screen = GetScreen();
            screen.Save("screen.png"System.Drawing.Imaging.ImageFormat.Png);
        }
 
        static Bitmap GetScreen()
        {
            Bitmap bitmap = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
            Graphics g = Graphics.FromImage(bitmap);
            g.CopyFromScreen(0000, bitmap.Size);
            g.Dispose();
 
            return bitmap;
        }
    }
}
 

 

소스를 입력하고 빌드한다.

 

실행하면 Output 폴더에 screen.png 파일이 생성된다.

 

반응형
Posted by J-sean
:
반응형

C#으로 스크린을 캡쳐 해 보자.

 

폼과 버튼을 적당히 배치한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
using System.Runtime.InteropServices;
 
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();            
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap bm = ScreenCapture.Capture();
 
            Graphics g = CreateGraphics();
            g.DrawImage(bm, 1040new Rectangle(100100450250), GraphicsUnit.Pixel);
            g.Dispose();
        }
    }
 
    public class ScreenCapture
    {
        [DllImport("user32.dll", ExactSpelling = true, SetLastError = true)]
        private static extern IntPtr GetDC(IntPtr hWnd);
 
        [DllImport("user32.dll", ExactSpelling = true)]
        private static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
 
        [DllImport("gdi32.dll", ExactSpelling = true)]
        private static extern IntPtr BitBlt(IntPtr hDestDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
 
        [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
        private static extern IntPtr GetDesktopWindow();
 
        public static Bitmap Capture()
        {
            int screenWidth = Screen.PrimaryScreen.Bounds.Width;
            int screenHeight = Screen.PrimaryScreen.Bounds.Height;
 
            Bitmap screenBmp = new Bitmap(screenWidth, screenHeight);
            Graphics g = Graphics.FromImage(screenBmp);
 
            IntPtr desktopDC = GetDC(GetDesktopWindow());
            IntPtr hDC = g.GetHdc();
 
            BitBlt(hDC, 00, screenWidth, screenHeight, desktopDC, 000x00CC0020);    //SRCCOPY (DWORD)0x00CC0020
 
            ReleaseDC(GetDesktopWindow(), desktopDC);
            g.ReleaseHdc(hDC);
            g.Dispose();
 
            return screenBmp;
        }
    }
}
 

 

소스를 입력하고 빌드한다.

 

실행하면 버튼만 하나 나타난다. 클릭하자.

 

지정한 위치의 화면이 캡쳐되어 표시된다.

 

반응형
Posted by J-sean
:
반응형

Screen capture with Windows API and OpenCV.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include <Windows.h>
#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
 
using namespace std;
using namespace cv;
 
class hWnd2Mat
{
public:
    hWnd2Mat(HWND hWindow, float scale = 1);
    virtual ~hWnd2Mat();
    virtual void Read();
    Mat capture;
 
private:
    HWND hWnd;
    HDC hWindowDC, hWindowCompatibleDC;
    int height, width, srcHeight, srcWidth;
    HBITMAP hBitmap;
    BITMAPINFOHEADER bi;
};
 
hWnd2Mat::hWnd2Mat(HWND hWindow, float scale)
{
    hWnd = hWindow;
    hWindowDC = GetDC(hWnd);
    hWindowCompatibleDC = CreateCompatibleDC(hWindowDC);
    SetStretchBltMode(hWindowCompatibleDC, COLORONCOLOR);
 
    RECT windowsize;    // get the height and width of the screen
    GetClientRect(hWnd, &windowsize);
 
    srcHeight = windowsize.bottom;
    srcWidth = windowsize.right;
    height = (int)(windowsize.bottom * scale);
    width = (int)(windowsize.right * scale);
 
    capture.create(height, width, CV_8UC4);
 
    // create a bitmap
    hBitmap = CreateCompatibleBitmap(hWindowDC, width, height);
    bi.biSize = sizeof(BITMAPINFOHEADER);    // http://msdn.microsoft.com/en-us/library/windows/window/dd183402%28v=vs.85%29.aspx
    bi.biWidth = width;
    bi.biHeight = -height;  //this is the line that makes it draw upside down or not
    bi.biPlanes = 1;
    bi.biBitCount = 32;
    bi.biCompression = BI_RGB;
    bi.biSizeImage = 0;
    bi.biXPelsPerMeter = 0;
    bi.biYPelsPerMeter = 0;
    bi.biClrUsed = 0;
    bi.biClrImportant = 0;
 
    // use the previously created device context with the bitmap
    SelectObject(hWindowCompatibleDC, hBitmap);
};
 
void hWnd2Mat::Read()
{
    // copy from the window device context to the bitmap device context
    StretchBlt(hWindowCompatibleDC, 00, width, height, hWindowDC, 00, srcWidth, srcHeight, SRCCOPY);
    //change SRCCOPY to NOTSRCCOPY for wacky colors!
    GetDIBits(hWindowCompatibleDC, hBitmap, 0, height, capture.data, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
    //copy from hWindowCompatibleDC to hBitmap
};
 
hWnd2Mat::~hWnd2Mat()
{
    DeleteObject(hBitmap);
    DeleteDC(hWindowCompatibleDC);
    ReleaseDC(hWnd, hWindowDC);
};
 
int main()
{
    HWND hWndDesktop = GetDesktopWindow();
    hWnd2Mat desktop(hWndDesktop, 1);    // scale = 1
 
    cout << "Screen capure in 3 seconds." << endl;
    
    for (int i = 3; i > 0; i--)
    {
        cout << i << ".." << endl;
        Sleep(1000);
    }
 
    desktop.Read();
    imshow("Capture", desktop.capture);
 
    waitKey();
 
    return 0;
}



It captures your desktop image in 3 seconds.


반응형
Posted by J-sean
: