1 /*****************************************************************************/ 2 // ImageView 3 // Written by Michael Wilber, OBOS Translation Kit Team 4 // 5 // ImageView.cpp 6 // 7 // BView class for showing images. Images can be dropped on this view 8 // from the tracker and images viewed in this view can be dragged 9 // to the tracker to be saved. 10 // 11 // 12 // Copyright (c) 2003 OpenBeOS Project 13 // 14 // Permission is hereby granted, free of charge, to any person obtaining a 15 // copy of this software and associated documentation files (the "Software"), 16 // to deal in the Software without restriction, including without limitation 17 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 18 // and/or sell copies of the Software, and to permit persons to whom the 19 // Software is furnished to do so, subject to the following conditions: 20 // 21 // The above copyright notice and this permission notice shall be included 22 // in all copies or substantial portions of the Software. 23 // 24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 30 // DEALINGS IN THE SOFTWARE. 31 /*****************************************************************************/ 32 33 34 #include "ImageView.h" 35 #include "Constants.h" 36 #include "StatusCheck.h" 37 #include "InspectorApp.h" 38 #include "TranslatorItem.h" 39 #include <Application.h> 40 #include <Message.h> 41 #include <List.h> 42 #include <String.h> 43 #include <TranslationUtils.h> 44 #include <TranslatorRoster.h> 45 #include <BitmapStream.h> 46 #include <Entry.h> 47 #include <Path.h> 48 #include <Directory.h> 49 #include <File.h> 50 #include <MenuBar.h> 51 #include <Screen.h> 52 #include <ScrollBar.h> 53 #include <Alert.h> 54 #include <stdlib.h> 55 #include <stdio.h> 56 #include <string.h> 57 58 #define BORDER_WIDTH 16 59 #define BORDER_HEIGHT 16 60 #define PEN_SIZE 1.0f 61 62 ImageView::ImageView(BRect rect, const char *name) 63 : BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS) 64 { 65 fpbitmap = NULL; 66 67 SetViewColor(192, 192, 192); 68 SetHighColor(0, 0, 0); 69 SetPenSize(PEN_SIZE); 70 } 71 72 ImageView::~ImageView() 73 { 74 delete fpbitmap; 75 fpbitmap = NULL; 76 } 77 78 void 79 ImageView::AttachedToWindow() 80 { 81 AdjustScrollBars(); 82 } 83 84 void 85 ImageView::Draw(BRect rect) 86 { 87 if (HasImage()) { 88 // Draw black rectangle around image 89 StrokeRect( 90 BRect(BORDER_WIDTH - PEN_SIZE, 91 BORDER_HEIGHT - PEN_SIZE, 92 fpbitmap->Bounds().Width() + BORDER_WIDTH + PEN_SIZE, 93 fpbitmap->Bounds().Height() + BORDER_HEIGHT + PEN_SIZE)); 94 95 DrawBitmap(fpbitmap, BPoint(BORDER_WIDTH, BORDER_HEIGHT)); 96 } 97 } 98 99 void 100 ImageView::ReDraw() 101 { 102 Draw(Bounds()); 103 } 104 105 void 106 ImageView::FrameResized(float width, float height) 107 { 108 AdjustScrollBars(); 109 110 if (!HasImage()) 111 Invalidate(); 112 } 113 114 void 115 ImageView::MouseDown(BPoint point) 116 { 117 if (!HasImage()) 118 return; 119 120 // Only accept left button clicks 121 BMessage *pmsg = Window()->CurrentMessage(); 122 int32 button = pmsg->FindInt32("buttons"); 123 if (button != B_PRIMARY_MOUSE_BUTTON) 124 return; 125 126 // Tell BeOS to setup a Drag/Drop operation 127 // 128 // (When the image is dropped, BeOS sends 129 // the following message to ImageWindow, 130 // which causes it to call ImageView::SetImage()) 131 BMessage msg(B_SIMPLE_DATA); 132 msg.AddInt32("be:actions", B_COPY_TARGET); 133 msg.AddString("be:filetypes", "application/octet-stream"); 134 msg.AddString("be:types", "application/octet-stream"); 135 msg.AddString("be:clip_name", "Bitmap"); 136 137 DragMessage(&msg, Bounds()); 138 } 139 140 void 141 ImageView::MouseMoved(BPoint point, uint32 state, const BMessage *pmsg) 142 { 143 } 144 145 void 146 ImageView::MouseUp(BPoint point) 147 { 148 } 149 150 void 151 ImageView::MessageReceived(BMessage *pmsg) 152 { 153 switch (pmsg->what) { 154 case B_COPY_TARGET: 155 SaveImageAtDropLocation(pmsg); 156 break; 157 158 default: 159 BView::MessageReceived(pmsg); 160 break; 161 } 162 } 163 164 void 165 ImageView::SaveImageAtDropLocation(BMessage *pmsg) 166 { 167 // Find the location and name of the drop and 168 // write the image file there 169 170 BBitmapStream stream(fpbitmap); 171 172 StatusCheck chk; 173 // throw an exception if this is assigned 174 // anything other than B_OK 175 try { 176 entry_ref dirref; 177 chk = pmsg->FindRef("directory", &dirref); 178 const char *filename; 179 chk = pmsg->FindString("name", &filename); 180 181 BDirectory dir(&dirref); 182 BFile file(&dir, filename, B_WRITE_ONLY | B_CREATE_FILE); 183 chk = file.InitCheck(); 184 185 BTranslatorRoster *proster = BTranslatorRoster::Default(); 186 chk = proster->Translate(&stream, NULL, NULL, &file, B_TGA_FORMAT); 187 188 } catch (StatusNotOKException) { 189 BAlert *palert = new BAlert(NULL, 190 "Sorry, unable to write the image file.", "OK"); 191 palert->Go(); 192 } 193 194 stream.DetachBitmap(&fpbitmap); 195 } 196 197 void 198 ImageView::AdjustScrollBars() 199 { 200 BRect rctview = Bounds(), rctbitmap(0, 0, 0, 0); 201 if (HasImage()) 202 rctbitmap = fpbitmap->Bounds(); 203 204 float prop, range; 205 BScrollBar *psb = ScrollBar(B_HORIZONTAL); 206 if (psb) { 207 range = rctbitmap.Width() + (BORDER_WIDTH * 2) - rctview.Width(); 208 if (range < 0) range = 0; 209 prop = rctview.Width() / (rctbitmap.Width() + (BORDER_WIDTH * 2)); 210 if (prop > 1.0f) prop = 1.0f; 211 psb->SetRange(0, range); 212 psb->SetProportion(prop); 213 psb->SetSteps(10, 100); 214 } 215 216 psb = ScrollBar(B_VERTICAL); 217 if (psb) { 218 range = rctbitmap.Height() + (BORDER_HEIGHT * 2) - rctview.Height(); 219 if (range < 0) range = 0; 220 prop = rctview.Height() / (rctbitmap.Height() + (BORDER_HEIGHT * 2)); 221 if (prop > 1.0f) prop = 1.0f; 222 psb->SetRange(0, range); 223 psb->SetProportion(prop); 224 psb->SetSteps(10, 100); 225 } 226 } 227 228 struct ColorSpaceName { 229 color_space id; 230 const char *name; 231 }; 232 #define COLORSPACENAME(id) {id, #id} 233 234 // convert colorspace numerical value to 235 // a string value 236 const char * 237 get_color_space_name(color_space colors) 238 { 239 // print out colorspace if it matches an item in the list 240 const ColorSpaceName kcolorspaces[] = { 241 COLORSPACENAME(B_NO_COLOR_SPACE), 242 COLORSPACENAME(B_RGB32), 243 COLORSPACENAME(B_RGBA32), 244 COLORSPACENAME(B_RGB24), 245 COLORSPACENAME(B_RGB16), 246 COLORSPACENAME(B_RGB15), 247 COLORSPACENAME(B_RGBA15), 248 COLORSPACENAME(B_CMAP8), 249 COLORSPACENAME(B_GRAY8), 250 COLORSPACENAME(B_GRAY1), 251 COLORSPACENAME(B_RGB32_BIG), 252 COLORSPACENAME(B_RGBA32_BIG), 253 COLORSPACENAME(B_RGB24_BIG), 254 COLORSPACENAME(B_RGB16_BIG), 255 COLORSPACENAME(B_RGB15_BIG), 256 COLORSPACENAME(B_RGBA15_BIG), 257 COLORSPACENAME(B_YCbCr422), 258 COLORSPACENAME(B_YCbCr411), 259 COLORSPACENAME(B_YCbCr444), 260 COLORSPACENAME(B_YCbCr420), 261 COLORSPACENAME(B_YUV422), 262 COLORSPACENAME(B_YUV411), 263 COLORSPACENAME(B_YUV444), 264 COLORSPACENAME(B_YUV420), 265 COLORSPACENAME(B_YUV9), 266 COLORSPACENAME(B_YUV12), 267 COLORSPACENAME(B_UVL24), 268 COLORSPACENAME(B_UVL32), 269 COLORSPACENAME(B_UVLA32), 270 COLORSPACENAME(B_LAB24), 271 COLORSPACENAME(B_LAB32), 272 COLORSPACENAME(B_LABA32), 273 COLORSPACENAME(B_HSI24), 274 COLORSPACENAME(B_HSI32), 275 COLORSPACENAME(B_HSIA32), 276 COLORSPACENAME(B_HSV24), 277 COLORSPACENAME(B_HSV32), 278 COLORSPACENAME(B_HSVA32), 279 COLORSPACENAME(B_HLS24), 280 COLORSPACENAME(B_HLS32), 281 COLORSPACENAME(B_HLSA32), 282 COLORSPACENAME(B_CMY24), 283 COLORSPACENAME(B_CMY32), 284 COLORSPACENAME(B_CMYA32), 285 COLORSPACENAME(B_CMYK32) 286 }; 287 const int32 kncolorspaces = sizeof(kcolorspaces) / 288 sizeof(ColorSpaceName); 289 for (int32 i = 0; i < kncolorspaces; i++) { 290 if (colors == kcolorspaces[i].id) 291 return kcolorspaces[i].name; 292 } 293 294 return "Unknown"; 295 } 296 297 // return a string of the passed number formated 298 // as a hexadecimal number in lowercase with a leading "0x" 299 const char * 300 hex_format(uint32 num) 301 { 302 static char str[11] = { 0 }; 303 sprintf(str, "0x%.8lx", num); 304 305 return str; 306 } 307 308 // convert passed number to a string of 4 characters 309 // and return that string 310 const char * 311 char_format(uint32 num) 312 { 313 static char str[5] = { 0 }; 314 uint32 bnum = B_HOST_TO_BENDIAN_INT32(num); 315 memcpy(str, &bnum, 4); 316 317 return str; 318 } 319 320 // Send information about the currently open image to the 321 // BApplication object so it can send it to the InfoWindow 322 void 323 ImageView::UpdateInfoWindow(const BPath &path, const translator_info &tinfo, 324 const char *tranname, const char *traninfo, int32 tranversion) 325 { 326 BMessage msg(M_INFO_WINDOW_TEXT); 327 BString bstr; 328 329 // Bitmap Info 330 bstr << "Image: " << path.Path() << "\n"; 331 color_space cs = fpbitmap->ColorSpace(); 332 bstr << "Color Space: " << get_color_space_name(cs) << " (" << 333 hex_format(static_cast<uint32>(cs)) << ")\n"; 334 bstr << "Dimensions: " << fpbitmap->Bounds().IntegerWidth() + 1 << " x " << 335 fpbitmap->Bounds().IntegerHeight() + 1 << "\n"; 336 bstr << "Bytes per Row: " << fpbitmap->BytesPerRow() << "\n"; 337 bstr << "Total Bytes: " << fpbitmap->BitsLength() << "\n"; 338 339 // Identify Info 340 bstr << "\nIdentify Info:\n"; 341 bstr << "ID String: " << tinfo.name << "\n"; 342 bstr << "MIME Type: " << tinfo.MIME << "\n"; 343 bstr << "Type: '" << char_format(tinfo.type) << "' (" << 344 hex_format(tinfo.type) <<")\n"; 345 bstr << "Translator ID: " << tinfo.translator << "\n"; 346 bstr << "Group: '" << char_format(tinfo.group) << "' (" << 347 hex_format(tinfo.group) << ")\n"; 348 bstr << "Quality: " << tinfo.quality << "\n"; 349 bstr << "Capability: " << tinfo.capability << "\n"; 350 351 // Translator Info 352 bstr << "\nTranslator Used:\n"; 353 bstr << "Name: " << tranname << "\n"; 354 bstr << "Info: " << traninfo << "\n"; 355 bstr << "Version: " << tranversion << "\n"; 356 357 msg.AddString("text", bstr); 358 be_app->PostMessage(&msg); 359 } 360 361 BTranslatorRoster * 362 ImageView::SelectTranslatorRoster(BTranslatorRoster &roster) 363 { 364 bool bNoneSelected = true; 365 366 InspectorApp *papp; 367 papp = static_cast<InspectorApp *>(be_app); 368 if (papp) { 369 BList *plist = papp->GetTranslatorsList(); 370 if (plist) { 371 for (int32 i = 0; i < plist->CountItems(); i++) { 372 BTranslatorItem *pitem = 373 static_cast<BTranslatorItem *>(plist->ItemAt(i)); 374 if (pitem->IsSelected()) { 375 bNoneSelected = false; 376 roster.AddTranslators(pitem->Path()); 377 } 378 } 379 } 380 } 381 382 if (bNoneSelected) 383 return BTranslatorRoster::Default(); 384 else 385 return &roster; 386 } 387 388 void 389 ImageView::SetImage(BMessage *pmsg) 390 { 391 // Replace current image with the image 392 // specified in the given BMessage 393 394 StatusCheck chk; 395 396 try { 397 entry_ref ref; 398 chk = pmsg->FindRef("refs", &ref); 399 400 BFile file(&ref, B_READ_ONLY); 401 chk = file.InitCheck(); 402 403 BTranslatorRoster roster, *proster; 404 proster = SelectTranslatorRoster(roster); 405 if (!proster) 406 // throw exception 407 chk = B_ERROR; 408 409 // determine what type the image is 410 translator_info tinfo; 411 chk = proster->Identify(&file, NULL, &tinfo, 0, NULL, 412 B_TRANSLATOR_BITMAP); 413 414 // get the name and info about the translator 415 const char *tranname = NULL, *traninfo = NULL; 416 int32 tranversion = 0; 417 chk = proster->GetTranslatorInfo(tinfo.translator, &tranname, 418 &traninfo, &tranversion); 419 420 // perform the actual translation 421 BBitmapStream outstream; 422 chk = proster->Translate(&file, &tinfo, NULL, &outstream, 423 B_TRANSLATOR_BITMAP); 424 BBitmap *pbitmap = NULL; 425 chk = outstream.DetachBitmap(&pbitmap); 426 fpbitmap = pbitmap; 427 pbitmap = NULL; 428 429 // Set the name of the Window to reflect the file name 430 BWindow *pwin = Window(); 431 BEntry entry(&ref); 432 BPath path; 433 if (entry.InitCheck() == B_OK) { 434 if (path.SetTo(&entry) == B_OK) 435 pwin->SetTitle(path.Leaf()); 436 else 437 pwin->SetTitle(IMAGEWINDOW_TITLE); 438 } else 439 pwin->SetTitle(IMAGEWINDOW_TITLE); 440 441 UpdateInfoWindow(path, tinfo, tranname, traninfo, tranversion); 442 443 // Resize parent window and set size limits to 444 // reflect the size of the new bitmap 445 float width, height; 446 BMenuBar *pbar = pwin->KeyMenuBar(); 447 width = fpbitmap->Bounds().Width() + B_V_SCROLL_BAR_WIDTH + (BORDER_WIDTH * 2); 448 height = fpbitmap->Bounds().Height() + 449 pbar->Bounds().Height() + B_H_SCROLL_BAR_HEIGHT + (BORDER_HEIGHT * 2) + 1; 450 451 BScreen *pscreen = new BScreen(pwin); 452 BRect rctscreen = pscreen->Frame(); 453 if (width > rctscreen.Width()) 454 width = rctscreen.Width(); 455 if (height > rctscreen.Height()) 456 height = rctscreen.Height(); 457 pwin->SetSizeLimits(B_V_SCROLL_BAR_WIDTH * 4, width, 458 pbar->Bounds().Height() + (B_H_SCROLL_BAR_HEIGHT * 4) + 1, height); 459 pwin->SetZoomLimits(width, height); 460 461 AdjustScrollBars(); 462 463 //pwin->Zoom(); 464 // Perform all of the hard work of resizing the 465 // window while taking into account the size of 466 // the screen, the tab and borders of the window 467 // 468 // HACK: Need to fix case where window un-zooms 469 // when the window is already the correct size 470 // for the current image 471 472 // repaint view 473 Invalidate(); 474 475 } catch (StatusNotOKException) { 476 BAlert *palert = new BAlert(NULL, 477 "Sorry, unable to load the image.", "OK"); 478 palert->Go(); 479 } 480 } 481 482