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(sDefaultFileNameBase) << index++ 101 << 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 BRect bounds = cursorBitmap->Bounds(); 137 int cursorWidth = bounds.IntegerWidth() + 1; 138 int cursorHeight = bounds.IntegerHeight() + 1; 139 140 if (includeMouse && cursorBitmap != NULL) { 141 // Import the cursor bitmap into wholeScreen 142 wholeScreen->ImportBits(cursorBitmap->Bits(), 143 cursorBitmap->BitsLength(), cursorBitmap->BytesPerRow(), 144 cursorBitmap->ColorSpace(), BPoint(0, 0), cursorPosition, 145 cursorWidth, cursorHeight); 146 147 } else if (cursorAreaBitmap != NULL) { 148 // Import the cursor area bitmap into wholeScreen 149 wholeScreen->ImportBits(cursorAreaBitmap->Bits(), 150 cursorAreaBitmap->BitsLength(), cursorAreaBitmap->BytesPerRow(), 151 cursorAreaBitmap->ColorSpace(), BPoint(0, 0), cursorPosition, 152 cursorWidth, cursorHeight); 153 } 154 155 BBitmap* screenshot = NULL; 156 157 if (activeWindow && activeWindowFrame.IsValid()) { 158 159 BRect frame(activeWindowFrame); 160 if (includeBorder) { 161 frame.InsetBy(-borderSize, -borderSize); 162 frame.top -= tabFrame.bottom - tabFrame.top; 163 } 164 165 screenshot = new BBitmap(frame.OffsetToCopy(B_ORIGIN), B_RGBA32, true); 166 167 if (screenshot->ImportBits(wholeScreen->Bits(), 168 wholeScreen->BitsLength(), wholeScreen->BytesPerRow(), 169 wholeScreen->ColorSpace(), frame.LeftTop(), 170 BPoint(0, 0), frame.IntegerWidth() + 1, 171 frame.IntegerHeight() + 1) != B_OK) { 172 delete screenshot; 173 return NULL; 174 } 175 176 if (includeBorder) 177 _MakeTabSpaceTransparent(screenshot, frame); 178 } else 179 screenshot = new BBitmap(wholeScreen); 180 181 return screenshot; 182 } 183 184 185 const char* 186 Utility::GetFileNameExtension(uint32 imageType) const 187 { 188 BMimeType mimeType(_GetMimeString(imageType)); 189 BString extension(""); 190 191 BMessage message; 192 if (mimeType.GetFileExtensions(&message) == B_OK) { 193 const char* ext; 194 if (message.FindString("extensions", 0, &ext) == B_OK) { 195 extension.SetTo(ext); 196 extension.Prepend("."); 197 } else 198 extension.SetTo(""); 199 } 200 201 return extension.String(); 202 } 203 204 205 const char* 206 Utility::_GetMimeString(uint32 imageType) const 207 { 208 const char *dummy = ""; 209 translator_id* translators = NULL; 210 int32 numTranslators = 0; 211 BTranslatorRoster* roster = BTranslatorRoster::Default(); 212 status_t status = roster->GetAllTranslators(&translators, &numTranslators); 213 if (status != B_OK) 214 return dummy; 215 216 for (int32 x = 0; x < numTranslators; x++) { 217 const translation_format* formats = NULL; 218 int32 numFormats; 219 220 if (roster->GetOutputFormats(x, &formats, &numFormats) == B_OK) { 221 for (int32 i = 0; i < numFormats; ++i) { 222 if (formats[i].type == imageType) { 223 delete [] translators; 224 return formats[i].MIME; 225 } 226 } 227 } 228 } 229 delete [] translators; 230 return dummy; 231 } 232 233 234 void 235 Utility::_MakeTabSpaceTransparent(BBitmap* screenshot, BRect frame) const 236 { 237 if (!frame.IsValid() || screenshot->ColorSpace() != B_RGBA32) 238 return; 239 240 if (!frame.Contains(tabFrame)) 241 return; 242 243 float tabHeight = tabFrame.bottom - tabFrame.top; 244 245 BRegion tabSpace(frame); 246 frame.OffsetBy(0, tabHeight); 247 tabSpace.Exclude(frame); 248 tabSpace.Exclude(tabFrame); 249 frame.OffsetBy(0, -tabHeight); 250 tabSpace.OffsetBy(-frame.left, -frame.top); 251 BScreen screen; 252 BRect screenFrame = screen.Frame(); 253 tabSpace.OffsetBy(-screenFrame.left, -screenFrame.top); 254 255 BView view(screenshot->Bounds(), "bitmap", B_FOLLOW_ALL_SIDES, 0); 256 screenshot->AddChild(&view); 257 if (view.Looper() && view.Looper()->Lock()) { 258 view.SetDrawingMode(B_OP_COPY); 259 view.SetHighColor(B_TRANSPARENT_32_BIT); 260 261 for (int i = 0; i < tabSpace.CountRects(); i++) 262 view.FillRect(tabSpace.RectAt(i)); 263 264 view.Sync(); 265 view.Looper()->Unlock(); 266 } 267 screenshot->RemoveChild(&view); 268 } 269