From f0a37e7c3146bead64bca2caff1caa332ab13349 Mon Sep 17 00:00:00 2001 From: darealshinji Date: Sat, 20 Aug 2016 23:21:15 +0200 Subject: [PATCH] win32: save screenshots to .bmp file (#28) --- .gitignore | 1 + LICENSE | 52 ++++++++++- Makefile | 1 + src/plat/win32/bitmap.c | 191 ++++++++++++++++++++++++++++++++++++++++ src/plat/win32/bitmap.h | 20 +++++ src/util.c | 29 +++--- 6 files changed, 281 insertions(+), 13 deletions(-) create mode 100644 src/plat/win32/bitmap.c create mode 100644 src/plat/win32/bitmap.h diff --git a/.gitignore b/.gitignore index 85a2785..269d1a2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ bin/ #ignore objects *.o #ignore other binaries created by make +*.exe screenfetch-c x11test gltest diff --git a/LICENSE b/LICENSE index 270d0a8..6b1be2c 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,54 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. + + + +Microsoft Limited Public License + +This license governs use of code marked as "sample" or "example" available on +this web site without a license agreement, as provided under the section above +titled "NOTICE SPECIFIC TO SOFTWARE AVAILABLE ON THIS WEB SITE." If you use +such code (the "software"), you accept this license. If you do not accept the +license, do not use the software. + +1. Definitions +The terms "reproduce," "reproduction," "derivative works," and "distribution" +have the same meaning here as under U.S. copyright law. +A "contribution" is the original software, or any additions or changes to the software. +A "contributor" is any person that distributes its contribution under this license. +"Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights +(A) Copyright Grant - Subject to the terms of this license, including the license +conditions and limitations in section 3, each contributor grants you a non-exclusive, +worldwide, royalty-free copyright license to reproduce its contribution, prepare +derivative works of its contribution, and distribute its contribution or any derivative +works that you create. +(B) Patent Grant - Subject to the terms of this license, including the license conditions +and limitations in section 3, each contributor grants you a non-exclusive, worldwide, +royalty-free license under its licensed patents to make, have made, use, sell, offer +for sale, import, and/or otherwise dispose of its contribution in the software or +derivative works of the contribution in the software. + +3. Conditions and Limitations +(A) No Trademark License- This license does not grant you rights to use any contributors' +name, logo, or trademarks. +(B) If you bring a patent claim against any contributor over patents that you claim +are infringed by the software, your patent license from such contributor to the +software ends automatically. +(C) If you distribute any portion of the software, you must retain all copyright, +patent, trademark, and attribution notices that are present in the software. +(D) If you distribute any portion of the software in source code form, you may do +so only under this license by including a complete copy of this license with your +distribution. If you distribute any portion of the software in compiled or object +code form, you may only do so under a license that complies with this license. +(E) The software is licensed "as-is." You bear the risk of using it. The contributors +give no express warranties, guarantees or conditions. You may have additional +consumer rights under your local laws which this license cannot change. To the +extent permitted under your local laws, the contributors exclude the implied +warranties of merchantability, fitness for a particular purpose and non-infringement. +(F) Platform Limitation - The licenses granted in sections 2(A) and 2(B) extend +only to the software or derivative works that you create that run on a Microsoft +Windows operating system product. diff --git a/Makefile b/Makefile index d1809a7..86965f2 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,7 @@ OLDTARGETS = linux win bsd osx sun ifeq ($(OS),Windows_NT) SOURCES += $(wildcard ./src/plat/win32/*.c) CPPFLAGS += -DWIN32_LEAN_AND_MEAN + LDFLAGS += -lgdi32 else UNAME_S := $(shell uname -s) diff --git a/src/plat/win32/bitmap.c b/src/plat/win32/bitmap.c new file mode 100644 index 0000000..65f7d77 --- /dev/null +++ b/src/plat/win32/bitmap.c @@ -0,0 +1,191 @@ +/* bitmap.c +** +** Copyright (c) 2016 Microsoft +** Source: https://msdn.microsoft.com/de-de/library/windows/desktop/dd145119(v=vs.85).aspx +** +** The bitmap saving functions used by screenfetch-c on Windows are implemented here. +** +** According to section 2b of the Microsoft Developer Services Agreement +** this code is released under the Microsoft Limited Public License. +** +** Usage: +** HBITMAP hBitmap; +** HDC hdc; +** PBITMAPINFO pBitmapInfo = createBitmapInfoStruct(hBitmap); +** createBmpFile("picture.bmp"), pBitmapInfo, hBitmap, hdc); +*/ + +#include + +PBITMAPINFO createBitmapInfoStruct(HBITMAP hBmp) +{ + BITMAP bmp; + PBITMAPINFO pbmi; + WORD cClrBits; + /* retrieve the bitmap color format, width, and height */ + if (!GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp)) + { + return NULL; + } + + /* convert the color format to a count of bits */ + cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel); + if (cClrBits == 1) + { + cClrBits = 1; + } + else if (cClrBits <= 4) + { + cClrBits = 4; + } + else if (cClrBits <= 8) + { + cClrBits = 8; + } + else if (cClrBits <= 16) + { + cClrBits = 16; + } + else if (cClrBits <= 24) + { + cClrBits = 24; + } + else + { + cClrBits = 32; + } + + /* Allocate memory for the BITMAPINFO structure. (This structure + contains a BITMAPINFOHEADER structure and an array of RGBQUAD + data structures.) + */ + if (cClrBits != 24) + { + pbmi = (PBITMAPINFO)LocalAlloc(LPTR, + sizeof(BITMAPINFOHEADER) + + sizeof(RGBQUAD) * (1 << cClrBits)); + } + else + { + /* there is no RGBQUAD array for the 24-bit-per-pixel format */ + pbmi = (PBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER)); + } + + /* initialize the fields in the BITMAPINFO structure */ + pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pbmi->bmiHeader.biWidth = bmp.bmWidth; + pbmi->bmiHeader.biHeight = bmp.bmHeight; + pbmi->bmiHeader.biPlanes = bmp.bmPlanes; + pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel; + if (cClrBits < 24) + { + pbmi->bmiHeader.biClrUsed = (1 << cClrBits); + } + + /* if the bitmap is not compressed, set the BI_RGB flag */ + pbmi->bmiHeader.biCompression = BI_RGB; + + /* Compute the number of bytes in the array of color + indices and store the result in biSizeImage. + For Windows NT, the width must be DWORD aligned unless + the bitmap is RLE compressed. This example shows this. + For Windows 95/98/Me, the width must be WORD aligned unless the + bitmap is RLE compressed. + */ + pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits + 31) & ~31) / 8 + * pbmi->bmiHeader.biHeight; + + /* set biClrImportant to 0, indicating that all of the + device colors are important + */ + pbmi->bmiHeader.biClrImportant = 0; + return pbmi; +} + +int createBmpFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC) +{ + HANDLE hf; /* file handle */ + BITMAPFILEHEADER hdr; /* bitmap file-header */ + PBITMAPINFOHEADER pbih; /* bitmap info-header */ + LPBYTE lpBits; /* memory pointer */ + DWORD cb; /* incremental count of bytes */ + BYTE *hp; /* byte pointer */ + DWORD dwTmp; + + pbih = (PBITMAPINFOHEADER)pbi; + lpBits = (LPBYTE)GlobalAlloc(GMEM_FIXED, pbih->biSizeImage); + + if (!lpBits) + { + return -1; + } + + /* retrieve the color table (RGBQUAD array) and the bits + (array of palette indices) from the DIB + */ + if (!GetDIBits(hDC, hBMP, 0, (WORD)pbih->biHeight, lpBits, + pbi, DIB_RGB_COLORS)) + { + return -1; + } + + /* create the .BMP file */ + hf = CreateFile(pszFile, + GENERIC_READ | GENERIC_WRITE, + (DWORD)0, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + (HANDLE)NULL); + if (hf == INVALID_HANDLE_VALUE) + { + return -1; + } + hdr.bfType = 0x4d42; /* 0x42 = "B" 0x4d = "M" */ + + /* compute the size of the entire file */ + hdr.bfSize = (DWORD)(sizeof(BITMAPFILEHEADER) + + pbih->biSize + pbih->biClrUsed + * sizeof(RGBQUAD) + pbih->biSizeImage); + hdr.bfReserved1 = 0; + hdr.bfReserved2 = 0; + + /* compute the offset to the array of color indices */ + hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + + pbih->biSize + pbih->biClrUsed + * sizeof(RGBQUAD); + + /* copy the BITMAPFILEHEADER into the .BMP file */ + if (!WriteFile(hf, (LPVOID)&hdr, sizeof(BITMAPFILEHEADER), + (LPDWORD)&dwTmp, NULL)) + { + return -1; + } + + /* copy the BITMAPINFOHEADER and RGBQUAD array into the file */ + if (!WriteFile(hf, (LPVOID)pbih, sizeof(BITMAPINFOHEADER) + + pbih->biClrUsed * sizeof(RGBQUAD), + (LPDWORD)&dwTmp, (NULL))) + { + return -1; + } + + /* copy the array of color indices into the .BMP file */ + cb = pbih->biSizeImage; + hp = lpBits; + if (!WriteFile(hf, (LPSTR)hp, (int)cb, (LPDWORD)&dwTmp, NULL)) + { + return -1; + } + + /* close the .BMP file */ + if (!CloseHandle(hf)) + { + return -1; + } + + /* free memory */ + GlobalFree((HGLOBAL)lpBits); + + return 0; +} diff --git a/src/plat/win32/bitmap.h b/src/plat/win32/bitmap.h new file mode 100644 index 0000000..3fce00a --- /dev/null +++ b/src/plat/win32/bitmap.h @@ -0,0 +1,20 @@ +/* bitmap.h +** +** Copyright (c) 2016 Microsoft +** Source: https://msdn.microsoft.com/de-de/library/windows/desktop/dd145119(v=vs.85).aspx +** +** Function prototypes for bitmap.c. +** +** According to section 2b of the Microsoft Developer Services Agreement +** this code is released under the Microsoft Limited Public License. +*/ + +#ifndef SCREENFETCH_C_BITMAP_H +#define SCREENFETCH_C_BITMAP_H + +#include + +PBITMAPINFO createBitmapInfoStruct(HBITMAP hBmp); +int createBmpFile(LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC); + +#endif /* SCREENFETCH_C_BITMAP_H */ diff --git a/src/util.c b/src/util.c index f144538..3ef3ca8 100644 --- a/src/util.c +++ b/src/util.c @@ -18,8 +18,9 @@ #include "misc.h" #include "error_flag.h" -#if defined(__CYGWIN__) +#if defined(__CYGWIN__) || defined(__MSYS__) #include + #include "plat/win32/bitmap.h" #endif /* safe_strncpy @@ -57,7 +58,7 @@ void split_uptime(long uptime, unsigned int *secs, unsigned int *mins, */ void take_screenshot(bool verbose) { -#if !defined(__CYGWIN__) +#if !defined(__CYGWIN__) && !defined(__MSYS__) int call_status = 1; char file_loc[MAX_STRLEN]; #endif @@ -73,14 +74,7 @@ void take_screenshot(bool verbose) sleep(1); printf("%s\n", "0"); -#if defined(__CYGWIN__) - /* terrible hack, the printscreen key is simulated */ - keybd_event(VK_SNAPSHOT, 0, 0, 0); - - if (verbose) - VERBOSE_OUT("Screenshot has been saved to the clipboard.", ""); - - /* NOT FINSISHED - HBITMAP needs to be saved +#if defined(__CYGWIN__) || defined(__MSYS__) HDC screen_dc = GetDC(NULL); HDC mem_dc = CreateCompatibleDC(screen_dc); @@ -93,16 +87,27 @@ void take_screenshot(bool verbose) BitBlt(mem_dc, 0, 0, horiz, vert, screen_dc, 0, 0, SRCCOPY); bitmap = SelectObject(mem_dc, old_bitmap); + PBITMAPINFO pBitmapInfo = createBitmapInfoStruct(bitmap); + + if (createBmpFile("screenfetch_screenshot.bmp", pBitmapInfo, bitmap, mem_dc) == 0) + { + VERBOSE_OUT("Screenshot successfully saved.", ""); + } + else + { + ERR_REPORT("Problem saving screenshot."); + } + DeleteDC(screen_dc); DeleteDC(mem_dc); - */ + #elif defined(__APPLE__) && defined(__MACH__) call_status = system("screencapture -x ~/screenfetch_screenshot.png 2> /dev/null"); #else call_status = system("scrot ~/screenfetch_screenshot.png 2> /dev/null"); #endif -#if !defined(__CYGWIN__) +#if !defined(__CYGWIN__) && !defined(__MSYS__) safe_strncpy(file_loc, getenv("HOME"), MAX_STRLEN); strncat(file_loc, "/screenfetch_screenshot.png", MAX_STRLEN);