repository_infos: Enable automatic updates on the main Haiku repostiory.
[haiku.git] / src / apps / screenshot / Utility.cpp
blobdd7f624127783278dfcf3e602bb8cfd61d76fcd8
1 /*
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.
7 * Authors:
8 * Axel Dörfler
9 * Karsten Heimrich
10 * Fredrik Modéen
11 * Christophe Huriaux
12 * Wim van der Meer
16 #include "Utility.h"
18 #include <Bitmap.h>
19 #include <BitmapStream.h>
20 #include <Catalog.h>
21 #include <Clipboard.h>
22 #include <Entry.h>
23 #include <File.h>
24 #include <FindDirectory.h>
25 #include <Locale.h>
26 #include <Looper.h>
27 #include <MimeType.h>
28 #include <NodeInfo.h>
29 #include <Path.h>
30 #include <Region.h>
31 #include <Screen.h>
32 #include <String.h>
33 #include <Translator.h>
34 #include <View.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");
47 Utility::Utility()
49 wholeScreen(NULL),
50 cursorBitmap(NULL),
51 cursorAreaBitmap(NULL)
56 Utility::~Utility()
58 delete wholeScreen;
59 delete cursorBitmap;
60 delete cursorAreaBitmap;
64 void
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
83 without warning.
85 status_t
86 Utility::Save(BBitmap* screenshot, const char* fileName, uint32 imageType)
87 const
89 BString fileNameString(fileName);
91 // Generate a default filename when none is given
92 if (fileNameString.Compare("") == 0) {
93 BPath homePath;
94 if (find_directory(B_USER_DIRECTORY, &homePath) != B_OK)
95 return B_ERROR;
97 BEntry entry;
98 int32 index = 1;
99 BString extension = FileNameExtension(imageType);
100 do {
101 fileNameString.SetTo(homePath.Path());
102 fileNameString << "/" << B_TRANSLATE_NOCOLLECT(sDefaultFileNameBase)
103 << index++ << extension;
104 entry.SetTo(fileNameString);
105 } while (entry.Exists());
108 // Create the file
109 BFile file(fileNameString, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
110 if (file.InitCheck() != B_OK)
111 return B_ERROR;
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);
119 BBitmap* bitmap;
120 stream.DetachBitmap(&bitmap);
121 // The stream takes over ownership of the bitmap
123 if (status != B_OK)
124 return status;
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));
131 return B_OK;
135 BBitmap*
136 Utility::MakeScreenshot(bool includeMouse, bool activeWindow,
137 bool includeBorder) const
139 if (wholeScreen == NULL)
140 return NULL;
142 int cursorWidth = 0;
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);
170 if (includeBorder) {
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) {
183 delete screenshot;
184 return NULL;
187 if (includeBorder)
188 _MakeTabSpaceTransparent(screenshot, frame);
189 } else
190 screenshot = new BBitmap(wholeScreen);
192 return screenshot;
196 BString
197 Utility::FileNameExtension(uint32 imageType) const
199 BMimeType mimeType(_MimeType(imageType));
201 BMessage message;
202 if (mimeType.GetFileExtensions(&message) == B_OK) {
203 BString extension;
204 if (message.FindString("extensions", 0, &extension) == B_OK) {
205 extension.Prepend(".");
206 return extension;
210 return "";
214 status_t
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);
223 if (status != B_OK)
224 return status;
226 ArrayDeleter<translator_id> deleter(translators);
228 for (int32 x = 0; x < numTranslators; x++) {
229 const translation_format* formats = NULL;
230 int32 numFormats;
232 if (roster->GetOutputFormats(translators[x], &formats, &numFormats)
233 == B_OK) {
234 for (int32 i = 0; i < numFormats; ++i) {
235 if (formats[i].type == imageType) {
236 id = translators[x];
237 if (_mimeType != NULL)
238 *_mimeType = formats[i].MIME;
239 return B_OK;
245 return B_ERROR;
249 BString
250 Utility::_MimeType(uint32 imageType) const
252 translator_id id;
253 BString type;
254 FindTranslator(imageType, id, &type);
255 return 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.
262 void
263 Utility::_MakeTabSpaceTransparent(BBitmap* screenshot, BRect frame) const
265 if (!frame.IsValid() || screenshot->ColorSpace() != B_RGBA32)
266 return;
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) {
272 pixel[i + 3] = 255;
275 // Then make the space around the tab transparent
276 if (!frame.Contains(tabFrame))
277 return;
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);
287 BScreen screen;
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));
300 view.Sync();
301 view.Looper()->Unlock();
303 screenshot->RemoveChild(&view);