/*
* Copyright 2010-2014, Haiku Inc. All rights reserved.
* Copyright 2010 Wim van der Meer <WPJvanderMeer@gmail.com>
* Copyright Karsten Heimrich, host.haiku@gmx.de. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler
* Karsten Heimrich
* Fredrik Modéen
* Christophe Huriaux
* Wim van der Meer
*/
#include "Utility.h"
#include <Bitmap.h>
#include <BitmapStream.h>
#include <Catalog.h>
#include <Clipboard.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <Locale.h>
#include <Looper.h>
#include <MimeType.h>
#include <NodeInfo.h>
#include <Path.h>
#include <Region.h>
#include <Screen.h>
#include <String.h>
#include <Translator.h>
#include <View.h>
#include <AutoDeleter.h>
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Screenshot"
const char* Utility::sDefaultFileNameBase = B_TRANSLATE_MARK_COMMENT(
"screenshot", "Base filename of screenshot files");
Utility::Utility()
:
wholeScreen(NULL),
cursorBitmap(NULL),
cursorAreaBitmap(NULL)
{
}
Utility::~Utility()
{
delete wholeScreen;
delete cursorBitmap;
delete cursorAreaBitmap;
}
void
Utility::CopyToClipboard(const BBitmap& screenshot) const
{
if (be_clipboard->Lock()) {
be_clipboard->Clear();
BMessage* clipboard = be_clipboard->Data();
if (clipboard != NULL) {
BMessage* bitmap = new BMessage();
screenshot.Archive(bitmap);
clipboard->AddMessage("image/bitmap", bitmap);
be_clipboard->Commit();
}
be_clipboard->Unlock();
}
}
/*! Save the screenshot to the file with the specified filename and type.
Note that any existing file with the same filename will be overwritten
without warning.
*/
status_t
Utility::Save(BBitmap* screenshot, const char* fileName, uint32 imageType)
const
{
BString fileNameString(fileName);
// Generate a default filename when none is given
if (fileNameString.Compare("") == 0) {
BPath homePath;
if (find_directory(B_USER_DIRECTORY, &homePath) != B_OK)
return B_ERROR;
BEntry entry;
int32 index = 1;
BString extension = FileNameExtension(imageType);
do {
fileNameString.SetTo(homePath.Path());
fileNameString << "/" << B_TRANSLATE_NOCOLLECT(sDefaultFileNameBase)
<< index++ << extension;
entry.SetTo(fileNameString);
} while (entry.Exists());
}
// Create the file
BFile file(fileNameString, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
if (file.InitCheck() != B_OK)
return B_ERROR;
// Write the screenshot bitmap to the file
BBitmapStream stream(screenshot);
BTranslatorRoster* roster = BTranslatorRoster::Default();
status_t status = roster->Translate(&stream, NULL, NULL, &file, imageType,
B_TRANSLATOR_BITMAP);
BBitmap* bitmap;
stream.DetachBitmap(&bitmap);
// The stream takes over ownership of the bitmap
if (status != B_OK)
return status;
// Set the file MIME attribute (don't mind too much if this fails)
BNodeInfo nodeInfo(&file);
if (nodeInfo.InitCheck() == B_OK)
nodeInfo.SetType(_MimeType(imageType));
return B_OK;
}
BBitmap*
Utility::MakeScreenshot(bool includeMouse, bool activeWindow,
bool includeBorder) const
{
if (wholeScreen == NULL)
return NULL;
int cursorWidth = 0;
int cursorHeight = 0;
if (cursorBitmap != NULL) {
BRect bounds = cursorBitmap->Bounds();
cursorWidth = bounds.IntegerWidth() + 1;
cursorHeight = bounds.IntegerHeight() + 1;
}
if (includeMouse && cursorBitmap != NULL) {
// Import the cursor bitmap into wholeScreen
wholeScreen->ImportBits(cursorBitmap->Bits(),
cursorBitmap->BitsLength(), cursorBitmap->BytesPerRow(),
cursorBitmap->ColorSpace(), BPoint(0, 0), cursorPosition,
cursorWidth, cursorHeight);
} else if (cursorAreaBitmap != NULL) {
// Import the cursor area bitmap into wholeScreen
wholeScreen->ImportBits(cursorAreaBitmap->Bits(),
cursorAreaBitmap->BitsLength(), cursorAreaBitmap->BytesPerRow(),
cursorAreaBitmap->ColorSpace(), BPoint(0, 0), cursorPosition,
cursorWidth, cursorHeight);
}
BBitmap* screenshot = NULL;
if (activeWindow && activeWindowFrame.IsValid()) {
BRect frame(activeWindowFrame);
if (includeBorder) {
frame.InsetBy(-borderSize, -borderSize);
frame.top -= tabFrame.bottom - tabFrame.top;
}
screenshot = new BBitmap(frame.OffsetToCopy(B_ORIGIN),
includeBorder ? B_RGBA32 : B_RGB32, true);
if (screenshot->ImportBits(wholeScreen->Bits(),
wholeScreen->BitsLength(), wholeScreen->BytesPerRow(),
wholeScreen->ColorSpace(), frame.LeftTop(),
BPoint(0, 0), frame.IntegerWidth() + 1,
frame.IntegerHeight() + 1) != B_OK) {
delete screenshot;
return NULL;
}
if (includeBorder)
_MakeTabSpaceTransparent(screenshot, frame);
} else
screenshot = new BBitmap(wholeScreen);
return screenshot;
}
BString
Utility::FileNameExtension(uint32 imageType) const
{
BMimeType mimeType(_MimeType(imageType));
BMessage message;
if (mimeType.GetFileExtensions(&message) == B_OK) {
BString extension;
if (message.FindString("extensions", 0, &extension) == B_OK) {
extension.Prepend(".");
return extension;
}
}
return "";
}
status_t
Utility::FindTranslator(uint32 imageType, translator_id& id,
BString* _mimeType) const
{
translator_id* translators = NULL;
int32 numTranslators = 0;
BTranslatorRoster* roster = BTranslatorRoster::Default();
status_t status = roster->GetAllTranslators(&translators, &numTranslators);
if (status != B_OK)
return status;
ArrayDeleter<translator_id> deleter(translators);
for (int32 x = 0; x < numTranslators; x++) {
const translation_format* formats = NULL;
int32 numFormats;
if (roster->GetOutputFormats(translators[x], &formats, &numFormats)
== B_OK) {
for (int32 i = 0; i < numFormats; ++i) {
if (formats[i].type == imageType) {
id = translators[x];
if (_mimeType != NULL)
*_mimeType = formats[i].MIME;
return B_OK;
}
}
}
}
return B_ERROR;
}
BString
Utility::_MimeType(uint32 imageType) const
{
translator_id id;
BString type;
FindTranslator(imageType, id, &type);
return type;
}
/*! Makes the space around the tab transparent, and also makes sure that the
contents of the window aren't, as the screen does not have an alpha channel.
*/
void
Utility::_MakeTabSpaceTransparent(BBitmap* screenshot, BRect frame) const
{
if (!frame.IsValid() || screenshot->ColorSpace() != B_RGBA32)
return;
// Set the transparency to opaque on the complete bitmap
uint8* pixel = (uint8*)screenshot->Bits();
uint32 count = screenshot->BitsLength();
for (uint32 i = 0; i < count; i += 4) {
pixel[i + 3] = 255;
}
// Then make the space around the tab transparent
if (!frame.Contains(tabFrame))
return;
float tabHeight = tabFrame.bottom - tabFrame.top;
BRegion tabSpace(frame);
frame.OffsetBy(0, tabHeight);
tabSpace.Exclude(frame);
tabSpace.Exclude(tabFrame);
frame.OffsetBy(0, -tabHeight);
tabSpace.OffsetBy(-frame.left, -frame.top);
BScreen screen;
BRect screenFrame = screen.Frame();
tabSpace.OffsetBy(-screenFrame.left, -screenFrame.top);
BView view(screenshot->Bounds(), "bitmap", B_FOLLOW_ALL_SIDES, 0);
screenshot->AddChild(&view);
if (view.Looper() && view.Looper()->Lock()) {
view.SetDrawingMode(B_OP_COPY);
view.SetHighColor(B_TRANSPARENT_32_BIT);
for (int i = 0; i < tabSpace.CountRects(); i++)
view.FillRect(tabSpace.RectAt(i));
view.Sync();
view.Looper()->Unlock();
}
screenshot->RemoveChild(&view);
}
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: borderSize.