Comment puis-je prendre une capture d'écran et l'enregistrer au format JPEG sous Windows?
J'essaie de trouver une (un peu) moyen facile de prendre une capture d'écran de la fenêtre et enregistrer le résultat HBITMAP au format JPEG. La partie la plus délicate ici, c'est que depuis que le code est en C, je ne peux pas utiliser GDI+ et depuis le code est un module pour un plus grand programme je ne peux pas ne pas utiliser une lib externe (comme libjpeg).
Ce code prend une capture d'écran et retourne un HBITMAP. Enregistrer l'image bitmap dans un fichier, c'est facile. le problème est que l'image est de 2 ou 3 mo.
HDC hDCMem = CreateCompatibleDC(NULL);
HBITMAP hBmp;
RECT rect;
HDC hDC;
HGDIOBJ hOld;
GetWindowRect(hWnd, & rect);
hBmp = NULL;
{
hDC = GetDC(hWnd);
hBmp = CreateCompatibleBitmap(hDC, rect.right - rect.left, rect.bottom - rect.top);
ReleaseDC(hWnd, hDC);
}
hOld = SelectObject(hDCMem, hBmp);
SendMessage(hWnd, WM_PRINT, (WPARAM) hDCMem, PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT | PRF_OWNED);
SelectObject(hDCMem, hOld);
DeleteObject(hDCMem);
return hBmp;
des idées sur comment faire cela?
merci beaucoup, toute aide est appréciée
EDIT:
Depuis, nous sommes allés dans la direction de GDI+, je pensais que je poste le code iv C++ qui peut prendre une capture d'écran et de le convertir en JPEG à l'aide de GDI+. Si quelqu'un sait comment réaliser cela à l'aide de la PLATE GDI+ je te remercie de l'aide.
Code:
#include <windows.h>
#include <stdio.h>
#include <gdiplus.h>
using namespace Gdiplus;
int GetEncoderClsid(WCHAR *format, CLSID *pClsid)
{
unsigned int num = 0, size = 0;
GetImageEncodersSize(&num, &size);
if(size == 0) return -1;
ImageCodecInfo *pImageCodecInfo = (ImageCodecInfo *)(malloc(size));
if(pImageCodecInfo == NULL) return -1;
GetImageEncoders(num, size, pImageCodecInfo);
for(unsigned int j = 0; j < num; ++j)
{
if(wcscmp(pImageCodecInfo[j].MimeType, format) == 0){
*pClsid = pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;
}
}
free(pImageCodecInfo);
return -1;
}
int GetScreeny(LPWSTR lpszFilename, ULONG uQuality) //by Napalm
{
ULONG_PTR gdiplusToken;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
HWND hMyWnd = GetForegroundWindow(); //get my own window
RECT r; //the area we are going to capture
int w, h; //the width and height of the area
HDC dc; //the container for the area
int nBPP;
HDC hdcCapture;
LPBYTE lpCapture;
int nCapture;
int iRes;
CLSID imageCLSID;
Bitmap *pScreenShot;
HGLOBAL hMem;
int result;
//get the area of my application's window
//GetClientRect(hMyWnd, &r);
GetWindowRect(hMyWnd, &r);
dc = GetWindowDC(hMyWnd);// GetDC(hMyWnd) ;
w = r.right - r.left;
h = r.bottom - r.top;
nBPP = GetDeviceCaps(dc, BITSPIXEL);
hdcCapture = CreateCompatibleDC(dc);
//create the buffer for the screenshot
BITMAPINFO bmiCapture = {
sizeof(BITMAPINFOHEADER), w, -h, 1, nBPP, BI_RGB, 0, 0, 0, 0, 0,
};
//create a container and take the screenshot
HBITMAP hbmCapture = CreateDIBSection(dc, &bmiCapture,
DIB_PAL_COLORS, (LPVOID *)&lpCapture, NULL, 0);
//failed to take it
if(!hbmCapture)
{
DeleteDC(hdcCapture);
DeleteDC(dc);
GdiplusShutdown(gdiplusToken);
printf("failed to take the screenshot. err: %d\n", GetLastError());
return 0;
}
//copy the screenshot buffer
nCapture = SaveDC(hdcCapture);
SelectObject(hdcCapture, hbmCapture);
BitBlt(hdcCapture, 0, 0, w, h, dc, 0, 0, SRCCOPY);
RestoreDC(hdcCapture, nCapture);
DeleteDC(hdcCapture);
DeleteDC(dc);
//save the buffer to a file
pScreenShot = new Bitmap(hbmCapture, (HPALETTE)NULL);
EncoderParameters encoderParams;
encoderParams.Count = 1;
encoderParams.Parameter[0].NumberOfValues = 1;
encoderParams.Parameter[0].Guid = EncoderQuality;
encoderParams.Parameter[0].Type = EncoderParameterValueTypeLong;
encoderParams.Parameter[0].Value = &uQuality;
GetEncoderClsid(L"image/jpeg", &imageCLSID);
iRes = (pScreenShot->Save(lpszFilename, &imageCLSID, &encoderParams) == Ok);
delete pScreenShot;
DeleteObject(hbmCapture);
GdiplusShutdown(gdiplusToken);
return iRes;
}
source d'informationauteur wonderer
Vous devez vous connecter pour publier un commentaire.
OK, après beaucoup d'efforts, voici la réponse:
qu'est-ce que hModuleThread? Regarder dans ici. Vous pouvez le remplacer avec
GetModuleHandle()
qu'est-ce que GetEncoderClsid? Regarder ici.
Maintenant, la question est, comment puis-je enregistrer le codées pBitmap (au format jpeg) dans un tampon d'OCTETS?
La traduction à la télévision GDI+ API est assez simple:
La seule chose qui n'était pas évident a été le nettoyage de la GpBitmap créé par GdipCreateBitmapFromHBITMAP(). Le Gdiplus::classe Bitmap ne semble pas avoir un destructeur, et donc ne pas faire n'importe quoi avec interne GpBitmap. Aussi, il n'y a pas de GdipDeleteBitmap(), comme il y en a pour d'autres GDI+ objets. Donc, il est clair pour moi ce qui doit être fait afin d'éviter les fuites.
Edit:
Ce code ne tient pas compte du fait que l'fournie par Microsoft GDI+ fichiers d'en-tête de déclarer toutes les fonctions nécessaires en C++ espaces de noms. Une solution consiste à copier les déclarations nécessaires (et les convertir en tant que de besoin à C code) de votre propre en-tête. Une autre possibilité est d'utiliser les en-têtes fournis par le Vin ou Mono projets. Ils semblent tous deux être beaucoup mieux comportés pour la compilation du code C.
Qu'une seule possibilité: Si vous ne pouvez pas modifier ce programme pour enregistrer en Jpeg, ecrire un deuxième programme, à l'aide de C# /GDI+ /fantaisie technologies pour surveiller le répertoire de sauvegarde et de processus a permis Bmp en jpeg.
Si vous ne pouvez pas le faire, l'Independent Jpeg group a fait de la pure-C Jpeg code disponible depuis la fin du 20e siècle: Une très minime de la page web est disponible ici.
Vous aurez probablement à utiliser une bibliothèque externe pour créer un fichier JPEG dans le code C,--il n'y aura pas une fonction de la bibliothèque standard de le faire. Bien sûr, vous pouvez également étudier le format de fichier et écrire une fonction pour générer votre propre, sur la base des critères. Vous pourriez commencer sur wikipedia. Si vraiment vous ne pouvez pas simplement utiliser une bibliothèque externe, vous avez pu lire dans les fonctions de la bibliothèque pour apprendre comment générer vos propres images au format Jpeg. Mais cela ressemble à beaucoup plus de travail que de simplement en utilisant la bibliothèque.
Aussi, je ne crois pas que la taille d'une bibliothèque vraiment entre en jeu à la C -- je crois que vous obtenez seulement la taille des fonctions que vous appelez à partir de la bibliothèque (je pense que, de toute façon). Bien sûr, si toutes les fonctions sont étroitement couplés que ce serait énorme de toute façon.
Bonne compression d'image est dur. Il y a une raison bibliothèque de code existe pour les formats courants. Il nécessite beaucoup de code pour le faire. Vos contraintes sur le problème de ne pas le faire sonner comme il y est une solution pratique.
Il ya un couple de choses à faire.
Utiliser un 8 bits par pixel BMP plutôt que d'un véritable couleur BMP. Cela suppose que la perte d'information dans un mappage de couleur est acceptable, bien sûr. Il va acheter de vous un facteur de trois dans la taille de fichier de plus de 24-bit BMP.
Essayez en utilisant le run length encoding dans le BMP que vous écrivez. RLE est un format documenté pour BMP, et il devrait y avoir beaucoup d'exemples de code pour les mettre en œuvre. Il fonctionne mieux sur les images qui ont beaucoup de pistes longues de couleur identique. Un écran classique, sans trop de dégradés et remplit correspond à cette description.
Si ceux-là ne sont pas suffisants, alors vous pourriez avoir besoin de recourir à une plus forte compression. Le code source de libjpeg est facilement disponible, et il est possible de lier statiquement plutôt que d'utiliser la DLL. Il faudra un certain effort pour configurer uniquement les éléments dont vous avez besoin, mais la compression et de décompression de code sont presque complètement indépendants les uns des autres et qui divise la bibliothèque de presque la moitié.
Avez-vous eu un coup d'oeil à la FreeImage Projet? Oui, c'est une bibliothèque externe, mais il est assez petit (~1 mo). N'juste au sujet de tout ce que vous voulez, avec des images, aussi. Certainement en valeur le savoir, même si ce n'est pour ce projet.
libjpeg est gratuit, open source, codé en C. Vous pouvez copier le code dans le vôtre.
http://sourceforge.net/project/showfiles.php?group_id=159521
Essayez ceci au début de votre code
Et GdipSaveImageToFile() peut compiler en c++ je crois.
En pur C, probablement le mieux c'est d'essayer de faire simple. Regardez pour les fonctions les déclarations dans "gdiplus.h" et d'ajouter minimal comprend pour chacune des fonctions qui ne comprennent pas les espaces de noms, tels que
#include "Gdiplusflat.h"
pour laGdipSaveImageToFile()
J'ai eu le même problème et résolu avec ce code.
Vous devez également inclure les gdiplus.lib dans le Entrées pour l'éditeur de liens.
Ce code peut être amélioré par l'ajout d'une valeur de qualité pour le format jpg, fichier de sortie, le code pour le faire est plus haut dans ce fil.
Si vous êtes vraiment préoccupé par l'espace, vous pouvez probablement vous délester de la C runtime des bibliothèques. Si vous n'utilisez que quelques fonctions, il suffit d'écrire votre propre version (par exemple, la fonction strcpy). Il est possible d'écrire des applications Windows qui sont seulement quelques-uns K octets. Je peux vous envoyer un petit exemple d'application qui le fait.
Si je prends mon C imagerie code et la bande vers le bas pour que le codeur JPEG, il sera probablement produire environ 20K de code (moins si vous n'avez pas besoin de soutenir les images en niveaux de gris).
Ne pas réinventer la roue.
Si ce que vous avez besoin est un programme qui prend une capture d'écran et l'enregistre au format jpeg, vous pouvez simplement utiliser ImageMagick's l'importation.
La commande shell serait tout simplement:
Bien sûr, vous pourriez économiser de l'-dessus comme takeScreenshot.chauve-souris et vous en aurez un programme qui correspond à vos besoins.