diff --git a/src/kits/Jamfile b/src/kits/Jamfile index 345f636ccf..946a3b0e93 100644 --- a/src/kits/Jamfile +++ b/src/kits/Jamfile @@ -35,6 +35,7 @@ SharedLibrary libbe.so : libagg.a libroot.so # make sure it links against our libroot.so + libpng.so libz.so # For dumping the screen to PNG in the Interface Kit $(TARGET_LIBSTDC++) ; diff --git a/src/kits/interface/Jamfile b/src/kits/interface/Jamfile index e03e89157d..ac7900c211 100644 --- a/src/kits/interface/Jamfile +++ b/src/kits/interface/Jamfile @@ -26,7 +26,7 @@ if ! $(TARGET_PLATFORM_HAIKU_COMPATIBLE) { SetSubDirSupportedPlatforms haiku libbe_test ; UsePrivateHeaders app input interface shared tracker ; -UseLibraryHeaders icon ; +UseLibraryHeaders icon png zlib ; SEARCH_SOURCE += [ FDirName $(SUBDIR) textview_support ] ; @@ -78,6 +78,7 @@ MergeObject interface_kit.o : PictureButton.cpp PictureDataWriter.cpp PicturePlayer.cpp + PNGDump.cpp Point.cpp Polygon.cpp PopUpMenu.cpp diff --git a/src/kits/interface/PNGDump.cpp b/src/kits/interface/PNGDump.cpp new file mode 100644 index 0000000000..7745cfdb4a --- /dev/null +++ b/src/kits/interface/PNGDump.cpp @@ -0,0 +1,125 @@ +/* + * Copyright 2001-2006, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * DarkWyrm + * Stephan Aßmus + */ + +/** Function for saving a generic framebuffer to a PNG file */ + +#include "PNGDump.h" + +#include +#include + +#include + +#include +#include +#include +#include + + +#define TRACE_PNGDUMP +#ifdef TRACE_PNGDUMP +# define TRACE(x) printf x +#else +# define TRACE(x) ; +#endif + + +status_t +SaveToPNG(const char* filename, const BRect& bounds, color_space space, + const void* bits, int32 bitsLength, int32 bytesPerRow) +{ + int32 width = bounds.IntegerWidth() + 1; + int32 height = bounds.IntegerHeight() + 1; + + TRACE(("SaveToPNG: %s (%ldx%ld)\n", filename, width, height)); + + FILE *file = fopen(filename, "wb"); + if (file == NULL) { + TRACE(("Couldn't open file: %s\n", strerror(errno))); + return errno; + } + + png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + if (png == NULL) { + TRACE(("Couldn't create write struct\n")); + fclose(file); + return B_NO_MEMORY; + } + + png_infop info = png_create_info_struct(png); + if (info == NULL) { + TRACE(("Couldn't create info struct\n")); + png_destroy_write_struct(&png, NULL); + fclose(file); + return B_NO_MEMORY; + } + + if (setjmp(png->jmpbuf)) { + png_destroy_write_struct(&png, NULL); + fclose(file); + return B_ERROR; + } + + png_init_io(png, file); + png_set_bgr(png); + + // TODO: support other color spaces if needed + + switch (space) { + case B_RGB32: + case B_RGBA32: + { + // create file without alpha channel + png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + png_write_info(png, info); + + // convert from 32 bit RGB to 24 bit RGB while saving + png_byte* src = (png_byte*)bits; + int srcRowBytes = width * 4; + int dstRowBytes = width * 3; + int srcRowOffset = bytesPerRow - srcRowBytes; + png_byte tempRow[dstRowBytes]; + for (int row = 0; row < height; row++) { + for (int i = 0; i < dstRowBytes; i += 3, src += 4) { + tempRow[i] = src[0]; + tempRow[i + 1] = src[1]; + tempRow[i + 2] = src[2]; + } + src += srcRowOffset; + png_write_row(png, tempRow); + } + break; + } + + default: + { + TRACE(("Unsupported color space\n")); + png_destroy_write_struct(&png, NULL); + fclose(file); + return B_ERROR; + } + } + + png_write_end(png, info); + png_destroy_write_struct(&png, NULL); + + fclose(file); + + // Set the file type manually, so that it doesn't have to be + // picked up by the registrar or Tracker, first + BNode node(filename); + BNodeInfo nodeInfo(&node); + if (nodeInfo.InitCheck() == B_OK) + nodeInfo.SetType("image/png"); + + return B_OK; +} diff --git a/src/kits/interface/PNGDump.h b/src/kits/interface/PNGDump.h new file mode 100644 index 0000000000..6c4b2f4fd7 --- /dev/null +++ b/src/kits/interface/PNGDump.h @@ -0,0 +1,20 @@ +/* + * Copyright 2001-2005, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * DarkWyrm + */ +#ifndef PNGDUMP_H +#define PNGDUMP_H + + +#include + +class BRect; + + +status_t SaveToPNG(const char* filename, const BRect& bounds, color_space space, + const void* bits, int32 bitsLength, int32 bytesPerRow); + +#endif diff --git a/src/kits/interface/Window.cpp b/src/kits/interface/Window.cpp index be3af1e702..d08fd8e975 100644 --- a/src/kits/interface/Window.cpp +++ b/src/kits/interface/Window.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -41,6 +42,8 @@ #include #include +#include "PNGDump.h" + //#define DEBUG_WIN #ifdef DEBUG_WIN @@ -3239,6 +3242,39 @@ BWindow::_HandleKeyDown(BMessage* event) PostMessage(&message); return true; } + + if (key == B_FUNCTION_KEY) { + // Check for Print Screen + int32 rawKey; + if (event->FindInt32("key", &rawKey) == B_OK && rawKey == B_PRINT_KEY) { + // Get filename + char filename[128]; + BEntry entry; + + int32 index = 1; + do { + // TODO: Use find_directory(B_USER_DIRECTORY, ...) + sprintf(filename, "/boot/home/screen%ld.png", index++); + entry.SetTo(filename); + } while(entry.Exists()); + + // Get the screen bitmap + BScreen screen(this); + BBitmap* screenDump; + screen.GetBitmap(&screenDump, false); + + // Dump to PNG + SaveToPNG(filename, screen.Frame(), screenDump->ColorSpace(), + screenDump->Bits(), + screenDump->BitsLength(), + screenDump->BytesPerRow()); + + // Free the bitmap allocated by BScreen.GetBitmap + delete screenDump; + + return true; + } + } // Handle shortcuts if ((modifiers & B_COMMAND_KEY) != 0) { diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index 1ee6e9b084..eebaa77673 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -173,25 +173,6 @@ KeyboardFilter::Filter(BMessage* message, EventTarget** _target, return B_SKIP_MESSAGE; } } - - // TODO: this should be moved client side! - // (that's how it is done in BeOS, clients could need this key for - // different purposes - also, it's preferrable to let the client - // write the dump within his own environment) - if (key == 0xe) { - // screen dump, PrintScreen - char filename[128]; - BEntry entry; - - int32 index = 1; - do { - sprintf(filename, "/boot/home/screen%ld.png", index++); - entry.SetTo(filename); - } while(entry.Exists()); - - fDesktop->GetDrawingEngine()->DumpToFile(filename); - return B_SKIP_MESSAGE; - } } if (message->what == B_KEY_DOWN