2 * Copyright 2010-2014, Haiku Inc. All rights reserved.
3 * Copyright 2010 Wim van der Meer <WPJvanderMeer@gmail.com>
4 * Copyright Karsten Heimrich, host.haiku@gmx.de. All rights reserved.
5 * Distributed under the terms of the MIT License.
19 #include <BitmapStream.h>
21 #include <Clipboard.h>
24 #include <FindDirectory.h>
33 #include <Translator.h>
36 #include <AutoDeleter.h>
39 #undef B_TRANSLATION_CONTEXT
40 #define B_TRANSLATION_CONTEXT "Screenshot"
43 const char* Utility::sDefaultFileNameBase
= B_TRANSLATE_MARK_COMMENT(
44 "screenshot", "Base filename of screenshot files");
51 cursorAreaBitmap(NULL
)
60 delete cursorAreaBitmap
;
65 Utility::CopyToClipboard(const BBitmap
& screenshot
) const
67 if (be_clipboard
->Lock()) {
68 be_clipboard
->Clear();
69 BMessage
* clipboard
= be_clipboard
->Data();
70 if (clipboard
!= NULL
) {
71 BMessage
* bitmap
= new BMessage();
72 screenshot
.Archive(bitmap
);
73 clipboard
->AddMessage("image/bitmap", bitmap
);
74 be_clipboard
->Commit();
76 be_clipboard
->Unlock();
81 /*! Save the screenshot to the file with the specified filename and type.
82 Note that any existing file with the same filename will be overwritten
86 Utility::Save(BBitmap
* screenshot
, const char* fileName
, uint32 imageType
)
89 BString
fileNameString(fileName
);
91 // Generate a default filename when none is given
92 if (fileNameString
.Compare("") == 0) {
94 if (find_directory(B_USER_DIRECTORY
, &homePath
) != B_OK
)
99 BString extension
= FileNameExtension(imageType
);
101 fileNameString
.SetTo(homePath
.Path());
102 fileNameString
<< "/" << B_TRANSLATE_NOCOLLECT(sDefaultFileNameBase
)
103 << index
++ << extension
;
104 entry
.SetTo(fileNameString
);
105 } while (entry
.Exists());
109 BFile
file(fileNameString
, B_CREATE_FILE
| B_ERASE_FILE
| B_WRITE_ONLY
);
110 if (file
.InitCheck() != B_OK
)
113 // Write the screenshot bitmap to the file
114 BBitmapStream
stream(screenshot
);
115 BTranslatorRoster
* roster
= BTranslatorRoster::Default();
116 status_t status
= roster
->Translate(&stream
, NULL
, NULL
, &file
, imageType
,
117 B_TRANSLATOR_BITMAP
);
120 stream
.DetachBitmap(&bitmap
);
121 // The stream takes over ownership of the bitmap
126 // Set the file MIME attribute (don't mind too much if this fails)
127 BNodeInfo
nodeInfo(&file
);
128 if (nodeInfo
.InitCheck() == B_OK
)
129 nodeInfo
.SetType(_MimeType(imageType
));
136 Utility::MakeScreenshot(bool includeMouse
, bool activeWindow
,
137 bool includeBorder
) const
139 if (wholeScreen
== NULL
)
143 int cursorHeight
= 0;
145 if (cursorBitmap
!= NULL
) {
146 BRect bounds
= cursorBitmap
->Bounds();
147 cursorWidth
= bounds
.IntegerWidth() + 1;
148 cursorHeight
= bounds
.IntegerHeight() + 1;
151 if (includeMouse
&& cursorBitmap
!= NULL
) {
152 // Import the cursor bitmap into wholeScreen
153 wholeScreen
->ImportBits(cursorBitmap
->Bits(),
154 cursorBitmap
->BitsLength(), cursorBitmap
->BytesPerRow(),
155 cursorBitmap
->ColorSpace(), BPoint(0, 0), cursorPosition
,
156 cursorWidth
, cursorHeight
);
158 } else if (cursorAreaBitmap
!= NULL
) {
159 // Import the cursor area bitmap into wholeScreen
160 wholeScreen
->ImportBits(cursorAreaBitmap
->Bits(),
161 cursorAreaBitmap
->BitsLength(), cursorAreaBitmap
->BytesPerRow(),
162 cursorAreaBitmap
->ColorSpace(), BPoint(0, 0), cursorPosition
,
163 cursorWidth
, cursorHeight
);
166 BBitmap
* screenshot
= NULL
;
168 if (activeWindow
&& activeWindowFrame
.IsValid()) {
169 BRect
frame(activeWindowFrame
);
171 frame
.InsetBy(-borderSize
, -borderSize
);
172 frame
.top
-= tabFrame
.bottom
- tabFrame
.top
;
175 screenshot
= new BBitmap(frame
.OffsetToCopy(B_ORIGIN
),
176 includeBorder
? B_RGBA32
: B_RGB32
, true);
178 if (screenshot
->ImportBits(wholeScreen
->Bits(),
179 wholeScreen
->BitsLength(), wholeScreen
->BytesPerRow(),
180 wholeScreen
->ColorSpace(), frame
.LeftTop(),
181 BPoint(0, 0), frame
.IntegerWidth() + 1,
182 frame
.IntegerHeight() + 1) != B_OK
) {
188 _MakeTabSpaceTransparent(screenshot
, frame
);
190 screenshot
= new BBitmap(wholeScreen
);
197 Utility::FileNameExtension(uint32 imageType
) const
199 BMimeType
mimeType(_MimeType(imageType
));
202 if (mimeType
.GetFileExtensions(&message
) == B_OK
) {
204 if (message
.FindString("extensions", 0, &extension
) == B_OK
) {
205 extension
.Prepend(".");
215 Utility::FindTranslator(uint32 imageType
, translator_id
& id
,
216 BString
* _mimeType
) const
218 translator_id
* translators
= NULL
;
219 int32 numTranslators
= 0;
221 BTranslatorRoster
* roster
= BTranslatorRoster::Default();
222 status_t status
= roster
->GetAllTranslators(&translators
, &numTranslators
);
226 ArrayDeleter
<translator_id
> deleter(translators
);
228 for (int32 x
= 0; x
< numTranslators
; x
++) {
229 const translation_format
* formats
= NULL
;
232 if (roster
->GetOutputFormats(translators
[x
], &formats
, &numFormats
)
234 for (int32 i
= 0; i
< numFormats
; ++i
) {
235 if (formats
[i
].type
== imageType
) {
237 if (_mimeType
!= NULL
)
238 *_mimeType
= formats
[i
].MIME
;
250 Utility::_MimeType(uint32 imageType
) const
254 FindTranslator(imageType
, id
, &type
);
259 /*! Makes the space around the tab transparent, and also makes sure that the
260 contents of the window aren't, as the screen does not have an alpha channel.
263 Utility::_MakeTabSpaceTransparent(BBitmap
* screenshot
, BRect frame
) const
265 if (!frame
.IsValid() || screenshot
->ColorSpace() != B_RGBA32
)
268 // Set the transparency to opaque on the complete bitmap
269 uint8
* pixel
= (uint8
*)screenshot
->Bits();
270 uint32 count
= screenshot
->BitsLength();
271 for (uint32 i
= 0; i
< count
; i
+= 4) {
275 // Then make the space around the tab transparent
276 if (!frame
.Contains(tabFrame
))
279 float tabHeight
= tabFrame
.bottom
- tabFrame
.top
;
281 BRegion
tabSpace(frame
);
282 frame
.OffsetBy(0, tabHeight
);
283 tabSpace
.Exclude(frame
);
284 tabSpace
.Exclude(tabFrame
);
285 frame
.OffsetBy(0, -tabHeight
);
286 tabSpace
.OffsetBy(-frame
.left
, -frame
.top
);
288 BRect screenFrame
= screen
.Frame();
289 tabSpace
.OffsetBy(-screenFrame
.left
, -screenFrame
.top
);
291 BView
view(screenshot
->Bounds(), "bitmap", B_FOLLOW_ALL_SIDES
, 0);
292 screenshot
->AddChild(&view
);
293 if (view
.Looper() && view
.Looper()->Lock()) {
294 view
.SetDrawingMode(B_OP_COPY
);
295 view
.SetHighColor(B_TRANSPARENT_32_BIT
);
297 for (int i
= 0; i
< tabSpace
.CountRects(); i
++)
298 view
.FillRect(tabSpace
.RectAt(i
));
301 view
.Looper()->Unlock();
303 screenshot
->RemoveChild(&view
);