Screenshot: fixed alpha channel handling.

* Screenshot always used B_RGBA32 color space, but did not care about the
  alpha channel at all. Now it only uses that space when "includeBorder"
  is used.
* Utility::_MakeTabSpaceTransparent() now also makes sure that the rest
  of the bitmap has the correct alpha channel set. This fixes bug #10491.
* Minor cleanup.
This commit is contained in:
Axel Dörfler
2014-01-31 00:43:31 +01:00
parent 6464f4f659
commit cc94643724
6 changed files with 152 additions and 141 deletions
+1 -1
View File
@@ -2,7 +2,7 @@ SubDir HAIKU_TOP src apps screenshot ;
HAIKU_MULTIPLE_LOCALIZED_TARGETS on $(SUBDIR) = 1 ;
UsePrivateHeaders interface ;
UsePrivateHeaders interface shared ;
Application Screenshot :
ScreenshotApp.cpp
+13 -11
View File
@@ -78,7 +78,7 @@ Screenshot::ArgvReceived(int32 argc, char** argv)
else if (strcmp(argv[i], "-f") == 0
|| strncmp(argv[i], "--format", 6) == 0
|| strncmp(argv[i], "--format=", 7) == 0)
imageFileType = _GetImageType(argv[i + 1]);
imageFileType = _ImageType(argv[i + 1]);
else if (strcmp(argv[i], "-d") == 0
|| strncmp(argv[i], "--delay", 7) == 0
|| strncmp(argv[i], "--delay=", 8) == 0) {
@@ -116,7 +116,7 @@ Screenshot::ArgvReceived(int32 argc, char** argv)
fUtility->CopyToClipboard(*screenshot);
if (saveScreenshotSilent)
fUtility->Save(&screenshot, outputFilename, imageFileType);
fUtility->Save(screenshot, outputFilename, imageFileType);
delete screenshot;
}
@@ -363,26 +363,28 @@ Screenshot::_GetActiveWindowFrame()
int32
Screenshot::_GetImageType(const char* name) const
Screenshot::_ImageType(const char* name) const
{
if (strcmp(name, "bmp") == 0)
if (strcasecmp(name, "bmp") == 0)
return B_BMP_FORMAT;
else if (strcmp(name, "gif") == 0)
if (strcasecmp(name, "gif") == 0)
return B_GIF_FORMAT;
else if (strcmp(name, "jpg") == 0 || strcmp(name, "jpeg") == 0)
if (strcasecmp(name, "jpg") == 0 || strcmp(name, "jpeg") == 0)
return B_JPEG_FORMAT;
else if (strcmp(name, "ppm") == 0)
if (strcasecmp(name, "ppm") == 0)
return B_PPM_FORMAT;
else if (strcmp(name, "tga") == 0 || strcmp(name, "targa") == 0)
if (strcasecmp(name, "tga") == 0 || strcmp(name, "targa") == 0)
return B_TGA_FORMAT;
else if (strcmp(name, "tif") == 0 || strcmp(name, "tiff") == 0)
if (strcasecmp(name, "tif") == 0 || strcmp(name, "tiff") == 0)
return B_TIFF_FORMAT;
else {
return B_PNG_FORMAT;
}
}
// #pragma mark -
int
main()
{
+2 -2
View File
@@ -26,10 +26,10 @@ private:
void _ShowHelp();
void _New(bigtime_t delay);
status_t _GetActiveWindowFrame();
int32 _GetImageType(const char* name) const;
int32 _ImageType(const char* name) const;
private:
Utility* fUtility;
bool fLaunchGui;
};
+27 -49
View File
@@ -1,4 +1,5 @@
/*
* Copyright 2010-2014, Haiku Inc. All rights reserved.
* Copyright 2010 Wim van der Meer <[email protected]>
* Copyright Karsten Heimrich, [email protected].
* All rights reserved. Distributed under the terms of the MIT License.
@@ -181,9 +182,10 @@ ScreenshotWindow::ScreenshotWindow(const Utility& utility, bool silent,
fTranslatorMenu);
menuFormat->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
BButton* showSettings = new BButton("", B_TRANSLATE("Settings"B_UTF8_ELLIPSIS),
new BMessage(kSettings));
showSettings->SetExplicitAlignment(BAlignment(B_ALIGN_RIGHT, B_ALIGN_BOTTOM));
BButton* showSettings = new BButton("",
B_TRANSLATE("Settings" B_UTF8_ELLIPSIS), new BMessage(kSettings));
showSettings->SetExplicitAlignment(
BAlignment(B_ALIGN_RIGHT, B_ALIGN_BOTTOM));
BBox* divider = new BBox(B_FANCY_BORDER, NULL);
divider->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, 1));
@@ -195,7 +197,7 @@ ScreenshotWindow::ScreenshotWindow(const Utility& utility, bool silent,
const float kLabelSpacing = be_control_look->DefaultLabelSpacing();
fPreview = new BView("preview", B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE);
BBox *previewBox = new BBox(B_FANCY_BORDER, fPreview);
BBox* previewBox = new BBox(B_FANCY_BORDER, fPreview);
BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
.SetInsets(kSpacing)
@@ -219,6 +221,7 @@ ScreenshotWindow::ScreenshotWindow(const Utility& utility, bool silent,
.Add(menuFormat->CreateLabelLayoutItem(), 0, 3)
.Add(menuFormat->CreateMenuBarLayoutItem(), 1, 3, 3, 1)
.End()
.AddStrut(kSpacing / 2)
.Add(showSettings)
.AddGlue()
.End()
@@ -337,7 +340,6 @@ ScreenshotWindow::MessageReceived(BMessage* message)
BEntry entry(&ref, true);
if (entry.InitCheck() == B_OK) {
BPath path;
// Could return B_BUSY
if (entry.GetPath(&path) == B_OK) {
BString label(path.Path());
_AddItemToPathMenu(path.Path(), label, 3, true);
@@ -438,7 +440,6 @@ void
ScreenshotWindow::_UpdatePreviewPanel()
{
float height = 150.0f;
float width = (fScreenshot->Bounds().Width()
/ fScreenshot->Bounds().Height()) * height;
@@ -481,35 +482,36 @@ ScreenshotWindow::_SetupOutputPathMenu(const BMessage& settings)
BString label(B_TRANSLATE("Home folder"));
_AddItemToPathMenu(path.Path(), label, 0,
(path.Path() == lastSelectedPath), 'H');
path.Path() == lastSelectedPath, 'H');
path.Append("Desktop");
label.SetTo(B_TRANSLATE("Desktop"));
_AddItemToPathMenu(path.Path(), label, 0, (
path.Path() == lastSelectedPath), 'D');
_AddItemToPathMenu(path.Path(), label, 0,
path.Path() == lastSelectedPath, 'D');
find_directory(B_BEOS_ETC_DIRECTORY, &path);
path.Append("artwork");
label.SetTo(B_TRANSLATE("Artwork folder"));
_AddItemToPathMenu(path.Path(), label, 2,
(path.Path() == lastSelectedPath), 'A');
path.Path() == lastSelectedPath, 'A');
int32 i = 0;
BString userPath;
while (settings.FindString("path", ++i, &userPath) == B_OK) {
_AddItemToPathMenu(userPath.String(), userPath, 3,
(userPath == lastSelectedPath));
userPath == lastSelectedPath);
}
if (!fLastSelectedPath) {
if (settings.IsEmpty() || lastSelectedPath.Length() == 0) {
fOutputPathMenu->ItemAt(1)->SetMarked(true);
fLastSelectedPath = fOutputPathMenu->ItemAt(1);
} else
} else {
_AddItemToPathMenu(lastSelectedPath.String(), lastSelectedPath, 3,
true);
}
}
fOutputPathMenu->AddItem(new BSeparatorItem());
fOutputPathMenu->AddItem(new BMenuItem(B_TRANSLATE("Choose folder..."),
@@ -581,7 +583,7 @@ ScreenshotWindow::_SetupTranslatorMenu()
int32 imageFileType;
for (int32 i = 0; i < fTranslatorMenu->CountItems(); ++i) {
BMenuItem* item = fTranslatorMenu->ItemAt(i);
if (item && item->Message()) {
if (item != NULL && item->Message()) {
item->Message()->FindInt32("be:type", &imageFileType);
if (fImageFileType == imageFileType) {
item->SetMarked(true);
@@ -624,7 +626,7 @@ ScreenshotWindow::_SaveScreenshot()
return B_CANCELED;
}
return fUtility.Save(&fScreenshot, path.Path(), fImageFileType);
return fUtility.Save(fScreenshot, path.Path(), fImageFileType);
}
@@ -635,45 +637,22 @@ ScreenshotWindow::_ShowSettings(bool activate)
return;
// Find a translator
translator_id translator = 0;
BTranslatorRoster *roster = BTranslatorRoster::Default();
translator_id* translators = NULL;
int32 numTranslators = 0;
if (roster->GetAllTranslators(&translators, &numTranslators) != B_OK)
return;
bool foundTranslator = false;
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 == static_cast<uint32>(fImageFileType)) {
translator = translators[x];
foundTranslator = true;
break;
}
}
}
if (foundTranslator)
break;
}
delete [] translators;
if (!foundTranslator)
translator_id translator;
if (fUtility.FindTranslator(fImageFileType, translator) != B_OK)
return;
// Create a window with a configuration view
BView *view;
BView* view;
BRect rect(0, 0, 239, 239);
status_t err = roster->MakeConfigurationView(translator, NULL, &view,
&rect);
if (err < B_OK || view == NULL) {
BAlert *alert = new BAlert(NULL, strerror(err), "OK");
status_t status = BTranslatorRoster::Default()->MakeConfigurationView(
translator, NULL, &view, &rect);
if (status != B_OK || view == NULL) {
// TODO: proper translation, better error dialog
BAlert* alert = new BAlert(NULL, strerror(status), "OK");
alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
alert->Go();
} else {
if (fSettingsWindow) {
} else if (fSettingsWindow != NULL) {
fSettingsWindow->RemoveChild(fSettingsWindow->ChildAt(0));
float width, height;
view->GetPreferredSize(&width, &height);
@@ -691,7 +670,6 @@ ScreenshotWindow::_ShowSettings(bool activate)
fSettingsWindow->CenterOnScreen();
fSettingsWindow->Show();
}
}
}
@@ -700,7 +678,7 @@ ScreenshotWindow::_FindValidFileName(const char* name)
{
BString baseName(name);
if (fExtension.Compare(""))
if (!fExtension.IsEmpty())
baseName.RemoveLast(fExtension);
if (!fLastSelectedPath)
@@ -710,7 +688,7 @@ ScreenshotWindow::_FindValidFileName(const char* name)
if (orgPath == NULL)
return baseName;
fExtension = fUtility.GetFileNameExtension(fImageFileType);
fExtension = fUtility.FileNameExtension(fImageFileType);
BPath outputPath = orgPath;
BString fileName;
+65 -35
View File
@@ -1,9 +1,11 @@
/*
* Copyright 2010-2014, Haiku Inc. All rights reserved.
* Copyright 2010 Wim van der Meer <[email protected]>
* Copyright Karsten Heimrich, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler
* Karsten Heimrich
* Fredrik Modéen
* Christophe Huriaux
@@ -31,14 +33,15 @@
#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");
const char* Utility::sDefaultFileNameBase = B_TRANSLATE_MARK_COMMENT(
"screenshot", "Base filename of screenshot files");
Utility::Utility()
@@ -64,7 +67,7 @@ Utility::CopyToClipboard(const BBitmap& screenshot) const
if (be_clipboard->Lock()) {
be_clipboard->Clear();
BMessage* clipboard = be_clipboard->Data();
if (clipboard) {
if (clipboard != NULL) {
BMessage* bitmap = new BMessage();
screenshot.Archive(bitmap);
clipboard->AddMessage("image/bitmap", bitmap);
@@ -75,13 +78,12 @@ Utility::CopyToClipboard(const BBitmap& screenshot) const
}
/*!
Save the screenshot to the file with the specified filename and type.
/*! 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)
Utility::Save(BBitmap* screenshot, const char* fileName, uint32 imageType)
const
{
BString fileNameString(fileName);
@@ -94,7 +96,7 @@ Utility::Save(BBitmap** screenshot, const char* fileName, uint32 imageType)
BEntry entry;
int32 index = 1;
BString extension = GetFileNameExtension(imageType);
BString extension = FileNameExtension(imageType);
do {
fileNameString.SetTo(homePath.Path());
fileNameString << "/" << B_TRANSLATE_NOCOLLECT(sDefaultFileNameBase)
@@ -109,18 +111,22 @@ Utility::Save(BBitmap** screenshot, const char* fileName, uint32 imageType)
return B_ERROR;
// Write the screenshot bitmap to the file
BBitmapStream stream(*screenshot);
BBitmapStream stream(screenshot);
BTranslatorRoster* roster = BTranslatorRoster::Default();
roster->Translate(&stream, NULL, NULL, &file, imageType,
status_t status = roster->Translate(&stream, NULL, NULL, &file, imageType,
B_TRANSLATOR_BITMAP);
*screenshot = NULL;
// Set the file MIME attribute
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)
return B_ERROR;
nodeInfo.SetType(_GetMimeString(imageType));
if (nodeInfo.InitCheck() == B_OK)
nodeInfo.SetType(_MimeType(imageType));
return B_OK;
}
@@ -160,14 +166,14 @@ Utility::MakeScreenshot(bool includeMouse, bool activeWindow,
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), B_RGBA32, true);
screenshot = new BBitmap(frame.OffsetToCopy(B_ORIGIN),
includeBorder ? B_RGBA32 : B_RGB32, true);
if (screenshot->ImportBits(wholeScreen->Bits(),
wholeScreen->BitsLength(), wholeScreen->BytesPerRow(),
@@ -188,35 +194,36 @@ Utility::MakeScreenshot(bool includeMouse, bool activeWindow,
BString
Utility::GetFileNameExtension(uint32 imageType) const
Utility::FileNameExtension(uint32 imageType) const
{
BMimeType mimeType(_GetMimeString(imageType));
BString extension("");
BMimeType mimeType(_MimeType(imageType));
BMessage message;
if (mimeType.GetFileExtensions(&message) == B_OK) {
const char* ext;
if (message.FindString("extensions", 0, &ext) == B_OK) {
extension.SetTo(ext);
BString extension;
if (message.FindString("extensions", 0, &extension) == B_OK) {
extension.Prepend(".");
} else
extension.SetTo("");
return extension;
}
}
return extension;
return "";
}
BString
Utility::_GetMimeString(uint32 imageType) const
status_t
Utility::FindTranslator(uint32 imageType, translator_id& id,
BString* _mimeType) const
{
const char *dummy = "";
translator_id* translators = NULL;
int32 numTranslators = 0;
BTranslatorRoster* roster = BTranslatorRoster::Default();
status_t status = roster->GetAllTranslators(&translators, &numTranslators);
if (status != B_OK)
return dummy;
return status;
ArrayDeleter<translator_id> deleter(translators);
for (int32 x = 0; x < numTranslators; x++) {
const translation_format* formats = NULL;
@@ -226,23 +233,46 @@ Utility::_GetMimeString(uint32 imageType) const
== B_OK) {
for (int32 i = 0; i < numFormats; ++i) {
if (formats[i].type == imageType) {
delete [] translators;
return formats[i].MIME;
id = translators[x];
if (_mimeType != NULL)
*_mimeType = formats[i].MIME;
return B_OK;
}
}
}
}
delete [] translators;
return dummy;
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;
+7 -6
View File
@@ -1,4 +1,5 @@
/*
* Copyright 2010-2014, Haiku Inc. All rights reserved.
* Copyright 2010 Wim van der Meer <[email protected]>
* Distributed under the terms of the MIT License.
*/
@@ -9,9 +10,7 @@
#include <Point.h>
#include <Rect.h>
#include <String.h>
class BBitmap;
#include <TranslatorRoster.h>
// Command constant for sending utility data to the GUI app
@@ -24,11 +23,13 @@ public:
~Utility();
void CopyToClipboard(const BBitmap& screenshot) const;
status_t Save(BBitmap** screenshot, const char* fileName,
status_t Save(BBitmap* screenshot, const char* fileName,
uint32 imageType) const;
BBitmap* MakeScreenshot(bool includeCursor, bool activeWindow,
bool includeBorder) const;
BString GetFileNameExtension(uint32 imageType) const;
BString FileNameExtension(uint32 imageType) const;
status_t FindTranslator(uint32 imageType, translator_id& id,
BString* _mimeType = NULL) const;
BBitmap* wholeScreen;
BBitmap* cursorBitmap;
@@ -43,7 +44,7 @@ public:
private:
void _MakeTabSpaceTransparent(BBitmap* screenshot,
BRect frame) const;
BString _GetMimeString(uint32 imageType) const;
BString _MimeType(uint32 imageType) const;
};