0

I'm trying to my desktop image capture. (All images, including the desktop output to the monitor)

It's easy using window API (BitBlt or CImageClass) and it's not the way I want.

I want do it using opengl. so I found glReadPixel funtion and window TRANSPARENT.

But it just read pixel own Windows application screen.(Save as bmp file and check)

Initialize()

glfwSetErrorCallback(errorCallback);

if (!glfwInit()) {
    std::cerr << "Error: GLFW " << std::endl;
    exit(EXIT_FAILURE);
}
glfwWindowHint(GLFW_DEPTH_BITS, 16);
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_SAMPLES, 4);


const int Monitor_count = GetMonitors();

GLwindow = glfwCreateWindow(
    nWidth, // width
    nHeight, // height
    "OpenGL_Test", // window title
    NULL, NULL);
if (!GLwindow) {
    glfwTerminate();
    exit(EXIT_FAILURE);
}
glfwSwapInterval(1);


if (glfwGetWindowAttrib(GLwindow, GLFW_TRANSPARENT_FRAMEBUFFER))
{
    //...
}
glfwSetWindowOpacity(GLwindow, 0.0f);

auto Mode = glfwGetVideoMode(Monitor[0]);   

glfwMakeContextCurrent(GLwindow);   
glfwSetKeyCallback(GLwindow, keyCallback);

glewExperimental = GL_TRUE;                                         
GLenum errorCode = glewInit();

if (GLEW_OK != errorCode) {

    std::cerr << "Error: GLEW - " << glewGetErrorString(errorCode) << std::endl;
    glfwTerminate();
    exit(EXIT_FAILURE);
}
if (!GLEW_VERSION_3_3) {

    std::cerr << "OpenGL 3.3 API is not available." << std::endl;

    glfwTerminate();
    exit(EXIT_FAILURE);
}

glViewport(0, 0, nWidth, nHeight);

glBindFramebuffer(GL_FRAMEBUFFER, 0);

if (glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE) {
    std::cerr << "Error: " << std::endl;
}

return true;

Roop

while (!glfwWindowShouldClose(GLwindow)) {

    Sleep(10);

    glClearColor(0.0f, 0.3f, 0.3f, 0.5f);
    glClear(GL_COLOR_BUFFER_BIT);

    unsigned char *image = (unsigned char*)malloc(sizeof(unsigned char)*nWidth*nHeight * 3);

       glReadPixels(0, 0, nWidth, nHeight, GL_BGR_EXT, GL_UNSIGNED_BYTE, image);
    glfwPollEvents();

}

return true;

Q1. Is it possible desktop capture(Full Image GPU output) with OPENGL?

Q2. If Q1 is possible, Should I use FBO and PBO GL_BACK??

Q3. How to access to mother window or GPU adapter? >> GL seems to strongly reject this.(I don't want any rendering, just read pixel data from GPU(Desktop image. not rendered by my application.)(If it is possible ...))

Anybody shows to me about link or idea?

genpfault
  • 51,148
  • 11
  • 85
  • 139
Birds
  • 65
  • 2
  • 13
  • What is going wrong with the code you posted? – xaxxon Apr 18 '19 at 04:33
  • My code has no errors, but it is not what I want. Maybe the viewer can see and edit it? – Birds Apr 18 '19 at 05:10
  • Possible duplicate of [How can I access a graphics card's output directly?](https://stackoverflow.com/questions/38535809/how-can-i-access-a-graphics-cards-output-directly) – Spektre Apr 18 '19 at 05:26
  • @Spektre Thanks reply. That link is already exist in my favorite. But that is get rendered data from application in GPU. isn't it? or I misunderstood? – Birds Apr 18 '19 at 05:59
  • @Birds there are 2 parts in the answer linked. First one can obtain image only grom GL but the second obtain all GDI/GL/DX stuff on the screen basically it saves whatever you see on the screen unless some nasty techniques are used (overlay or streaming) ... or "optimized" gfx drivers are used ... but last time I had an issue like that was years ago... – Spektre Apr 18 '19 at 07:51
  • @Spektre In that link. The second part uses the VCL. It looks like it's out of range of OPENGL. When I give up OPENGL, If you implement the screen capture function, I will refer to it. Thanks. – Birds Apr 18 '19 at 08:47
  • @Birds the second part uses WinAPI ... the only thing used from VCL is the bitmap but you can use your own memory array instead or WinAPIs HBitmap ... the Canvas and stuff is just WinAPI GDI encapsulated in VCL for simpler use ... so you just do teh same in pure GDI the function/variables names are almost the same you just need to add the handles etc just google some GDI examples or docs on how to rewrite it to pure winapi/GDI. I am too lazy for that as I do not need it ... VCL do it for me in much simpler and user friendly way. – Spektre Apr 18 '19 at 09:04
  • @Birds this is first hit for pure WinAPI/GDI example [How to correctly draw simple non-client area (4 px red border)?](https://stackoverflow.com/a/50135792/2521214) I look for just now ... as you can see the names are the same only you just pass the handles instead of class member relation.... – Spektre Apr 18 '19 at 09:07

2 Answers2

1

I'm trying to my desktop image capture. (All images, including the desktop output to the monitor)

It's easy using window API (BitBlt or CImageClass) and it's not the way I want.

But it's the way it's supposed to be done.

I want do it using opengl. so I found glReadPixel funtion

You can't. OpenGL doesn't "know" about the desktop, or other windows (or actually what windows are at all). The function glReadPixels will work reliably only for images that have been drawn with OpenGL itself.

You can't use OpenGL to take screenshots! On older computers it might seem to work, but that's only because of their older memory management where when you create a new window, its memory will be "cut" from what was below and if you read that, it looks like a way to make screenshots. But it is not.

Community
  • 1
  • 1
datenwolf
  • 159,371
  • 13
  • 185
  • 298
0

What you're asking for is something completely outside the scope of OpenGL. OpenGL is designed to be a platform-agnostic API for applications to talk about drawing stuff into framebuffers in an abstract fashion. OpenGL has no notion of windows*, screens, or a desktop. OpenGL doesn't operate at a level where such concepts exist. Heck, OpenGL doesn't even know what a GPU is. OpenGL is supposed to be initialized through platform-specific mechanisms to establish a context which assigns actual meaning to OpenGL API calls. As far as I know, there is no way to set up an OpenGL context with a framebuffer whose contents would somehow correspond to the desktop on Windows (or any other platform I'm aware of). As far as my understanding goes, this wouldn't really make sense…

To do what you want to do, you'll have to rely on the respective platform-specific APIs. The probably simplest way on Windows is to get an HDC for the entire desktop and BitBlt from there. See, e.g., this question for more on that. A more modern approach would be to use the DXGI Desktop Duplication API.

(*) yes, I know the OpenGL specification technically does talk about "windows" in a few places; but it only really does so when it's talking about all the things it's not responsible for…

Michael Kenzel
  • 15,508
  • 2
  • 30
  • 39
  • Really Thanks for the answer. "only really does so when it's talking about all the things it's not responsible for…" What is the meaning of responsible? – Birds Apr 18 '19 at 05:26
  • @Birds The word "window" does appear in the OpenGL specification. But it only really does so in places where the specification is talking about all the stuff that OpenGL does not concern itself with, and in the name of a particular coordinate system. You can simply ignore that, it's a minor technicality, not really important. I just added that to be technically correct… ;) The point is that the abstraction of OpenGL exists at a level that is way beyond the stuff you're trying to do here… – Michael Kenzel Apr 18 '19 at 05:37
  • It's so helpful to me. Thanks. In summary, does that mean you can not do it with OPENGL? OR use WINAPI? – Birds Apr 18 '19 at 06:34
  • As far as I know, you cannot do what you're trying to do with OpenGL. You *can* do it with the Windows API. – Michael Kenzel Apr 18 '19 at 06:50