Screenshot unter 500KB



  • Schau mal hier: http://stackoverflow.com/a/1034609

    Dort wird deine Frage beantwortet. Dort wird das Bild als .jpeg abgespeichert.



  • Danke für den Link,
    Leider funktionieren die Beispiele nur mit GDIplus 😞
    Trotzdem danke 🙂



  • Und warum willst Du Gdiplus nicht verwenden?



  • TimDerVerzweifelte schrieb:

    volkard schrieb:

    Besteht die Möglichkeit, sie nicht als BMP, sondern als PNG abzuspeichern?

    Ja das Funktioniert aber das PNG hat dann trotzdem eine Größe von 7.91MB 😕
    Danke für den Versuch 🙂

    Screenshots von einer Anwendungen (ohne Hintergrundbild) werden als PNG total winzig.
    Außerdem packt es verlustfrei.
    JPG kommt da nicht mit, es wird größer und hat Farbabweichungen um die Buchstaben.

    Wenn im Bild Farbverläufe und sowas drin sind, dann halt JPG. Vor allem bei Fotos.

    BMP ist einfach groß.



  • @Unregistriert :
    Ich werde mich heute Abend mal an GDIplus dran setzen. Danke für die Hilfe 🙂

    @Volkard :
    Ne bei mir leider nicht, egal welches Format es bleibt bei der Größe..



  • TimDerVerzweifelte schrieb:

    @Volkard :
    Ne bei mir leider nicht, egal welches Format es bleibt bei der Größe..

    Bei genau der Größe?



  • Es reicht nicht, einfach nur die Dateinamenerweiterung auf ".png" zu ändern - du mußt schon eine entsprechende PNG-Library verwenden (bezogen auf deinen 2. Code)!



  • TimDerVerzweifelte schrieb:

    //Make Screenshot
    	keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(VK_SNAPSHOT, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    
    	//Creates the Image
    	std::ofstream a_file(filename);
    	a_file.close();
    
    	//Sleep for a short while
    	Sleep(10);
    
    	//Opens the Image secretly
    	ShellExecute(NULL, NULL, convertCharArrayToLPCWSTR("C:\\WINDOWS\\system32\\mspaint.exe"), convertCharArrayToLPCWSTR(filename), NULL, SW_HIDE );
    
    	//Sleep for a short while
    	Sleep(30);
    
    	//Sets paint to ForeGround
    	HWND windowHandel = FindWindow(0, convertCharArrayToLPCWSTR("Paint"));
    	SetForegroundWindow(windowHandel);  
    
    	//Paste Screenshot
    	keybd_event(VK_CONTROL, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(86, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(86, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    	keybd_event(VK_CONTROL, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    
    	//Paste Screenshot
    	keybd_event(VK_F12, 0x45, KEYEVENTF_EXTENDEDKEY, 0); Sleep(300);
    	keybd_event(VK_TAB, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(VK_TAB, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    	keybd_event(VK_DOWN, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(VK_DOWN, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    	keybd_event(VK_UP, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(VK_UP, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    	keybd_event(VK_UP, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(VK_UP, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    	keybd_event(VK_RETURN, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(VK_RETURN, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    	keybd_event(VK_RETURN, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(VK_RETURN, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0); 
    	keybd_event(VK_LEFT, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(VK_LEFT, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    	keybd_event(VK_LEFT, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(VK_LEFT, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);  
    	keybd_event(VK_RETURN, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(VK_RETURN, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    	keybd_event(VK_RETURN, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(VK_RETURN, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    	keybd_event(VK_F12, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    
    	//Save Screenshot
    	keybd_event(VK_CONTROL, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(83, 0x45, KEYEVENTF_EXTENDEDKEY, 0);
    	keybd_event(83, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    	keybd_event(VK_CONTROL, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
    

    😮
    Ich habe Angst vor dir...



  • volkard schrieb:

    TimDerVerzweifelte schrieb:

    @Volkard :
    Ne bei mir leider nicht, egal welches Format es bleibt bei der Größe..

    Bei genau der Größe?

    Jap 😕

    Th69 schrieb:

    Es reicht nicht, einfach nur die Dateinamenerweiterung auf ".png" zu ändern - du mußt schon eine entsprechende PNG-Library verwenden (bezogen auf deinen 2. Code)!

    Okay wollte aber eigentlich es mit der WinApi schaffen, bzw. ohne Library.



  • hustbaer schrieb:

    Ich habe Angst vor dir...

    😃 Warum ?



  • TimDerVerzweifelte schrieb:

    Okay wollte aber eigentlich es mit der WinApi schaffen, bzw. ohne Library.

    https://www.google.de/#q=save+png+msdn



  • volkard schrieb:

    TimDerVerzweifelte schrieb:

    Okay wollte aber eigentlich es mit der WinApi schaffen, bzw. ohne Library.

    https://www.google.de/#q=save+png+msdn

    Vielen Dank für den Google-Link.
    Aber wie gesagt ich habe schon gegoogelt und bin es langsam Leid.
    Der Link führt nur auf eine CLI seite bzw. wieder auf GDI+.
    Könnte mir nicht irgendwer einen Denkanstoß geben, veröffentliche dann auch meinen Code.



  • Was ist denn nun dein Problem mit GDI+? Alternativ kannst du WIC verwenden. Oder einen eigenen PNG-Encoder schreiben.



  • GDI+ ist doch (seit Windows XP) Teil der WinAPI.
    Was ist dein Problem damit?



  • Th69 schrieb:

    GDI+ ist doch (seit Windows XP) Teil der WinAPI.
    Was ist dein Problem damit?

    So ist es.

    Im MSDN Beispiel "Setting JPEG Compression Level" ist (fast) alles drin, was man braucht um ein BMP als
    JPG zu speichern. Man muss noch die GetEncoderClsid() dazukopieren und die Gdiplus.lib dazulinken.
    Windows GDI+ kann Images als BMP,GIF,JPEG,PNG,TIFF und einiges andere speichern. Als Feature kann
    man im Beispiel sogar noch die quality zwischen 0 .. 100 einstellen!

    http://msdn.microsoft.com/en-us/library/windows/desktop/ms533814.aspx

    Das ganze kompiliert als Win32 Konsolenanwendung mit VS2010 unter XP fehlerfrei.



  • Du gehst das falsch an. Du meinst, du kannst dir aus dem Internet einfach was zusammenkopieren ohne es zu verstehen und das funzt. Das funzt aber leider nicht.
    Das einzige was du brauchst, ist das hier:

    // get the device context of the screen
    HDC hScreenDC = CreateDC("DISPLAY", NULL, NULL, NULL);     
    // and a device context to put it in
    HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
    
    int x = GetDeviceCaps(hScreenDC, HORZRES);
    int y = GetDeviceCaps(hScreenDC, VERTRES);
    
    // maybe worth checking these are positive values
    HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDc, x, y);
    
    // get a new bitmap
    HBITMAP hOldBitmap = SelectObject(hMemoryDC, hBitmap);
    
    BitBlt(hMemoryDC, 0, 0, width, height, hScreenDC, 0, 0, SRCCOPY);
    hBitmap = SelectObject(hMemoryDC, hOldBitmap);
    
    // clean up
    DeleteDC(hMemoryDC);
    DeleteDC(hScreenDC);
    

    http://stackoverflow.com/questions/3291167/how-to-make-screen-screenshot-with-win32-in-c

    Das ist der Code um einen Screenshot vom Desktop zu machen.
    Wenn du das als BMP abspeicherst, hast du natürlich eine riesige Datei.
    Dann der Spruch "ich will das aber nur mit WinAPI machen und ohne Library" entspricht ungefähr dem equivalent von "klar ich laufe gerne über heisse kohlen mit einem Messer im Rücken". Auf Low Level Shit zu bestehen bringt dich auch nicht weiter. Als lass den scheiss und machs richtig. Benutz ne image lib wie freeimage oder libpng und speichers als PNG, JPG oder was auch immer um die Zielgröße zu erreichen. Oder benutz halt GDI+.
    Aber hör auf dir Code zusammenzukopieren ohne ihn im Ansatz zu verstehen.
    Vor allem sowas schreckliches wie dein erster Code Teil mit den Haufen fake keyboard inputs.
    Rechtschreibfehler sind mir grade wurscht, is spät. Gute Nacht.



  • Scorcher24 schrieb:

    Das einzige was du brauchst, ist das hier:

    HWND DesktopHwnd = GetDesktopWindow(); 
        RECT DesktopParams; 
        HDC DevC = GetDC(DesktopHwnd); 
        GetWindowRect(DesktopHwnd,&DesktopParams); 
        DWORD Width = DesktopParams.right - DesktopParams.left; 
        DWORD Height = DesktopParams.bottom - DesktopParams.top;
    

    Das ist der Code um einen Screenshot vom Desktop zu machen.

    Der Code macht wohl noch keinen Screenshot, aber es ist der richtige Weg als Basis des "gefundenen" Code aus

    void ScreenShot(char* BmpName)
    

    zu verwenden und die Bitmap platzsparend in einem effizienten Format wie JPG zu speichern.

    Alle dafür notwendigen Quellen wurden hier bereits angesprochen.

    Scorcher24 schrieb:

    Vor allem sowas schreckliches wie dein erster Code Teil mit den Haufen fake keyboard inputs.

    Der Code ist so schrecklich, das ich ganz schnell drüber wegscrollen musste. Das man sowas überhaupt
    versucht und es tatsächlich zu einer Lösung kommt - wenn auch einer eher schlechten - ist auf jeden Fall
    mal ein Lösungsansatz.

    Viel schlimmer finde ich Leute, die garnichts recherchiert haben und die "gebratenen Tauben" erwarten.

    Den Code mit den keyboard inputs bitte schnell abhaken und den anderen Code
    verwenden.



  • Hab den Code ersetzt :P.
    Sorry, meine 4 Uhr morgens Antworten sind nicht meine besten haha.
    Zudem war ich grad angepisst, aber das is ne andere Geschichte.



  • Scorcher24 schrieb:

    Hab den Code ersetzt :P.
    Sorry, meine 4 Uhr morgens Antworten sind nicht meine besten haha.
    Zudem war ich grad angepisst, aber das is ne andere Geschichte.

    Kann ja mal passieren ...

    Leider scheint mittags auch der Wurm drin zu sein.

    1. width, height und x, y durcheinander
    2. SelectObject() muss auf (HBITMAP) gecastet werden

    // get a new bitmap
    HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);
    

    So hat es vermutlich nie gelaufen 😕

    Mit den (minimalen) Änderungen passt es jetzt fast. Wenn man es jetzt noch etwas nett einpackt ist es auch
    schon in dem Format das benötigt wird ...

    Bitmap* GetScreenDump()
    {
        // get the device context of the screen
    
        ...
    
        Bitmap *pbmp = Bitmap::FromHBITMAP((HBITMAP)hBitmap, NULL); 
        DeleteObject(hBitmap); 
    
        return pbmp;
    }
    

    Und noch eben eingesetzt:

    // Get an image from the disk.
       // Image* image = new Image(L"Shapes.bmp");
    
       Image* image = GetScreenDump(); // The Bitmap class inherits from Image
    

    Ein JPG mit quality=100 ist bei 1920x1080 dann etwas über 600kB gross.



  • Danke für die vielen Antworten, ich habe jetzt eingesehen das ich die GDI+ verwenden muss, war ein bisschen durch den Wind 😉
    Jetzt mal mein Code der hoffentlich nicht so schrecklich ist wie der mit dem Paint-Versuch 😃

    BOOL GetEncoderClsid(wchar_t *wchMimeType, CLSID& clsidEncoder)
    {
    	UINT uiNum   = 0;
    	UINT uiSize  = 0;
    	BOOL bOk     = FALSE;
    
    	Gdiplus::ImageCodecInfo* pImageCodecInfo = NULL;
    	Gdiplus::GetImageEncodersSize(&uiNum, &uiSize);
    
    	if( uiSize > 0 )
    	{
    		pImageCodecInfo = (Gdiplus::ImageCodecInfo *)new char[uiSize];
    
    		if( pImageCodecInfo )
    		{
    			Gdiplus::GetImageEncoders(uiNum, uiSize, pImageCodecInfo);
    
    			for( UINT i = 0; i < uiNum; i++ )
    			{
    				if( wcscmp(pImageCodecInfo[i].MimeType, wchMimeType) == 0 )
    				{
    					clsidEncoder = pImageCodecInfo[i].Clsid;
    					bOk = TRUE;
    				}
    			}
    		}
    
    		delete pImageCodecInfo;
    	}        
    
    	return bOk;
    }
    
    void BMPtoPNG(const char* filenamebmp,const wchar_t* filenamepng){
    
    	Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    	ULONG_PTR                    gdiplusToken;
    	Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    
    	HBITMAP hbm = (HBITMAP)LoadImage( NULL,
    		convertCharArrayToLPCWSTR(filenamebmp),
    		IMAGE_BITMAP,
    		0,
    		0,
    		LR_LOADFROMFILE );
    
    	if( hbm )
    	{
    		Gdiplus::Bitmap *pBitmap = Gdiplus::Bitmap::FromHBITMAP(
    			hbm, (HPALETTE)GetStockObject(DEFAULT_PALETTE) );
    
    		if( pBitmap )
    		{
    			CLSID clsidEncoder;
    
    			if( GetEncoderClsid(L"image/png", clsidEncoder) )
    			{
    
    				pBitmap->Save(filenamepng, &clsidEncoder, NULL);
    			}
    
    			delete pBitmap;
    		}
    
    		DeleteObject(hbm);
    	}
    
    	Gdiplus::GdiplusShutdown(gdiplusToken);
    }
    
    void ScreenBMP(char*BmpName)
    {
    	HWND DesktopHwnd = GetDesktopWindow();
    	RECT DesktopParams;
    	HDC DevC = GetDC(DesktopHwnd);
    	GetWindowRect(DesktopHwnd,&DesktopParams);
    	DWORD Width = DesktopParams.right - DesktopParams.left;
    	DWORD Height = DesktopParams.bottom - DesktopParams.top;
    
    	DWORD FileSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+(sizeof(RGBTRIPLE)+1*(Width*Height*3));
    	char *BmpFileData = (char*)GlobalAlloc(0x0040,FileSize);
    
    	PBITMAPFILEHEADER BFileHeader = (PBITMAPFILEHEADER)BmpFileData;
    	PBITMAPINFOHEADER BInfoHeader = (PBITMAPINFOHEADER)&BmpFileData[sizeof(BITMAPFILEHEADER)];
    
    	BFileHeader->bfType = 0x4D42; // BM
    	BFileHeader->bfSize = sizeof(BITMAPFILEHEADER);
    	BFileHeader->bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
    
    	BInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
    	BInfoHeader->biPlanes = 1;
    	BInfoHeader->biBitCount = 24;
    	BInfoHeader->biCompression = BI_RGB;
    	BInfoHeader->biHeight = Height;
    	BInfoHeader->biWidth = Width;
    
    	RGBTRIPLE *Image = (RGBTRIPLE*)&BmpFileData[sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)];
    	RGBTRIPLE color;
    
    	HDC CaptureDC = CreateCompatibleDC(DevC);
    	HBITMAP CaptureBitmap = CreateCompatibleBitmap(DevC,Width,Height);
    	SelectObject(CaptureDC,CaptureBitmap);
    	BitBlt(CaptureDC,0,0,Width,Height,DevC,0,0,SRCCOPY|CAPTUREBLT);
    	GetDIBits(CaptureDC,CaptureBitmap,0,Height,Image,(LPBITMAPINFO)BInfoHeader, DIB_RGB_COLORS);
    
    	DWORD Junk;
    	HANDLE FH = CreateFileA(BmpName,GENERIC_WRITE,FILE_SHARE_WRITE,0,CREATE_ALWAYS,0,0);
    	WriteFile(FH,BmpFileData,FileSize,&Junk,0);
    	CloseHandle(FH);
    	GlobalFree(BmpFileData); 
    }
    

    Aufrufen tuh ich das ganze dann einfach hiermit :

    ScreenBMP("test.bmp");	
    BMPtoPNG("test.bmp","test.png");             
    DeleteFile("test.bmp");
    

    Hoffentlich ist der Code soweit inordnung 🙂

    Was mich allerdings wundert, der Screenshot ist manchmal nur 200KB groß und manchmal ganze 1.12MB. Woran liegt das ? 😕


Anmelden zum Antworten