1 /* 2 * Copyright 2010 Wim van der Meer <WPJvanderMeer@gmail.com> 3 * Copyright Karsten Heimrich, host.haiku@gmx.de. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 * 6 * Authors: 7 * Karsten Heimrich 8 * Fredrik Modéen 9 * Christophe Huriaux 10 * Wim van der Meer 11 */ 12 13 14 #include "Utility.h" 15 16 #include <Bitmap.h> 17 #include <BitmapStream.h> 18 #include <Catalog.h> 19 #include <Clipboard.h> 20 #include <Entry.h> 21 #include <File.h> 22 #include <FindDirectory.h> 23 #include <Locale.h> 24 #include <Looper.h> 25 #include <MimeType.h> 26 #include <NodeInfo.h> 27 #include <Path.h> 28 #include <Region.h> 29 #include <Screen.h> 30 #include <String.h> 31 #include <Translator.h> 32 #include <View.h> 33 34 35 #undef B_TRANSLATE_CONTEXT 36 #define B_TRANSLATE_CONTEXT "Screenshot" 37 38 39 const char* Utility::sDefaultFileNameBase = 40 B_TRANSLATE_MARK_COMMENT("screenshot", 41 "Base filename of screenshot files"); 42 43 44 Utility::Utility() 45 : 46 wholeScreen(NULL), 47 cursorBitmap(NULL), 48 cursorAreaBitmap(NULL) 49 { 50 } 51 52 53 Utility::~Utility() 54 { 55 delete wholeScreen; 56 delete cursorBitmap; 57 delete cursorAreaBitmap; 58 } 59 60 61 void 62 Utility::CopyToClipboard(const BBitmap& screenshot) const 63 { 64 if (be_clipboard->Lock()) { 65 be_clipboard->Clear(); 66 BMessage* clipboard = be_clipboard->Data(); 67 if (clipboard) { 68 BMessage* bitmap = new BMessage(); 69 screenshot.Archive(bitmap); 70 clipboard->AddMessage("image/bitmap", bitmap); 71 be_clipboard->Commit(); 72 } 73 be_clipboard->Unlock(); 74 } 75 } 76 77 78 /*! 79 Save the screenshot to the file with the specified filename and type. 80 Note that any existing file with the same filename will be overwritten 81 without warning. 82 */ 83 status_t 84 Utility::Save(BBitmap** screenshot, const char* fileName, uint32 imageType) 85 const 86 { 87 BString fileNameString(fileName); 88 89 // Generate a default filename when none is given 90 if (fileNameString.Compare("") == 0) { 91 BPath homePath; 92 if (find_directory(B_USER_DIRECTORY, &homePath) != B_OK) 93 return B_ERROR; 94 95 BEntry entry; 96 int32 index = 1; 97 BString extension = GetFileNameExtension(imageType); 98 do { 99 fileNameString.SetTo(homePath.Path()); 100 fileNameString << "/" << B_TRANSLATE_NOCOLLECT(sDefaultFileNameBase) 101 << index++ << extension; 102 entry.SetTo(fileNameString.String()); 103 } while (entry.Exists()); 104 } 105 106 // Create the file 107 BFile file(fileNameString, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY); 108 if (file.InitCheck() != B_OK) 109 return B_ERROR; 110 111 // Write the screenshot bitmap to the file 112 BBitmapStream stream(*screenshot); 113 BTranslatorRoster* roster = BTranslatorRoster::Default(); 114 roster->Translate(&stream, NULL, NULL, &file, imageType, 115 B_TRANSLATOR_BITMAP); 116 *screenshot = NULL; 117 118 // Set the file MIME attribute 119 BNodeInfo nodeInfo(&file); 120 if (nodeInfo.InitCheck() != B_OK) 121 return B_ERROR; 122 123 nodeInfo.SetType(_GetMimeString(imageType)); 124 125 return B_OK; 126 } 127 128 129 BBitmap* 130 Utility::MakeScreenshot(bool includeMouse, bool activeWindow, 131 bool includeBorder) const 132 { 133 if (wholeScreen == NULL) 134 return NULL; 135 136 int cursorWidth = 0; 137 int cursorHeight = 0; 138 139 if (cursorBitmap != NULL) { 140 BRect bounds = cursorBitmap->Bounds(); 141 cursorWidth = bounds.IntegerWidth() + 1; 142 cursorHeight = bounds.IntegerHeight() + 1; 143 } 144 145 if (includeMouse && cursorBitmap != NULL) { 146 // Import the cursor bitmap into wholeScreen 147 wholeScreen->ImportBits(cursorBitmap->Bits(), 148 cursorBitmap->BitsLength(), cursorBitmap->BytesPerRow(), 149 cursorBitmap->ColorSpace(), BPoint(0, 0), cursorPosition, 150 cursorWidth, cursorHeight); 151 152 } else if (cursorAreaBitmap != NULL) { 153 // Import the cursor area bitmap into wholeScreen 154 wholeScreen->ImportBits(cursorAreaBitmap->Bits(), 155 cursorAreaBitmap->BitsLength(), cursorAreaBitmap->BytesPerRow(), 156 cursorAreaBitmap->ColorSpace(), BPoint(0, 0), cursorPosition, 157 cursorWidth, cursorHeight); 158 } 159 160 BBitmap* screenshot = NULL; 161 162 if (activeWindow && activeWindowFrame.IsValid()) { 163 164 BRect frame(activeWindowFrame); 165 if (includeBorder) { 166 frame.InsetBy(-borderSize, -borderSize); 167 frame.top -= tabFrame.bottom - tabFrame.top; 168 } 169 170 screenshot = new BBitmap(frame.OffsetToCopy(B_ORIGIN), B_RGBA32, true); 171 172 if (screenshot->ImportBits(wholeScreen->Bits(), 173 wholeScreen->BitsLength(), wholeScreen->BytesPerRow(), 174 wholeScreen->ColorSpace(), frame.LeftTop(), 175 BPoint(0, 0), frame.IntegerWidth() + 1, 176 frame.IntegerHeight() + 1) != B_OK) { 177 delete screenshot; 178 return NULL; 179 } 180 181 if (includeBorder) 182 _MakeTabSpaceTransparent(screenshot, frame); 183 } else 184 screenshot = new BBitmap(wholeScreen); 185 186 return screenshot; 187 } 188 189 190 const char* 191 Utility::GetFileNameExtension(uint32 imageType) const 192 { 193 BMimeType mimeType(_GetMimeString(imageType)); 194 BString extension(""); 195 196 BMessage message; 197 if (mimeType.GetFileExtensions(&message) == B_OK) { 198 const char* ext; 199 if (message.FindString("extensions", 0, &ext) == B_OK) { 200 extension.SetTo(ext); 201 extension.Prepend("."); 202 } else 203 extension.SetTo(""); 204 } 205 206 return extension.String(); 207 } 208 209 210 const char* 211 Utility::_GetMimeString(uint32 imageType) const 212 { 213 const char *dummy = ""; 214 translator_id* translators = NULL; 215 int32 numTranslators = 0; 216 BTranslatorRoster* roster = BTranslatorRoster::Default(); 217 status_t status = roster->GetAllTranslators(&translators, &numTranslators); 218 if (status != B_OK) 219 return dummy; 220 221 for (int32 x = 0; x < numTranslators; x++) { 222 const translation_format* formats = NULL; 223 int32 numFormats; 224 225 if (roster->GetOutputFormats(x, &formats, &numFormats) == B_OK) { 226 for (int32 i = 0; i < numFormats; ++i) { 227 if (formats[i].type == imageType) { 228 delete [] translators; 229 return formats[i].MIME; 230 } 231 } 232 } 233 } 234 delete [] translators; 235 return dummy; 236 } 237 238 239 void 240 Utility::_MakeTabSpaceTransparent(BBitmap* screenshot, BRect frame) const 241 { 242 if (!frame.IsValid() || screenshot->ColorSpace() != B_RGBA32) 243 return; 244 245 if (!frame.Contains(tabFrame)) 246 return; 247 248 float tabHeight = tabFrame.bottom - tabFrame.top; 249 250 BRegion tabSpace(frame); 251 frame.OffsetBy(0, tabHeight); 252 tabSpace.Exclude(frame); 253 tabSpace.Exclude(tabFrame); 254 frame.OffsetBy(0, -tabHeight); 255 tabSpace.OffsetBy(-frame.left, -frame.top); 256 BScreen screen; 257 BRect screenFrame = screen.Frame(); 258 tabSpace.OffsetBy(-screenFrame.left, -screenFrame.top); 259 260 BView view(screenshot->Bounds(), "bitmap", B_FOLLOW_ALL_SIDES, 0); 261 screenshot->AddChild(&view); 262 if (view.Looper() && view.Looper()->Lock()) { 263 view.SetDrawingMode(B_OP_COPY); 264 view.SetHighColor(B_TRANSPARENT_32_BIT); 265 266 for (int i = 0; i < tabSpace.CountRects(); i++) 267 view.FillRect(tabSpace.RectAt(i)); 268 269 view.Sync(); 270 view.Looper()->Unlock(); 271 } 272 screenshot->RemoveChild(&view); 273 } 274