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 <Application.h> 38 #include <Message.h> 39 #include <String.h> 40 #include <TranslationUtils.h> 41 #include <TranslatorRoster.h> 42 #include <BitmapStream.h> 43 #include <Entry.h> 44 #include <Path.h> 45 #include <Directory.h> 46 #include <File.h> 47 #include <MenuBar.h> 48 #include <Screen.h> 49 #include <ScrollBar.h> 50 #include <Alert.h> 51 #include <stdlib.h> 52 #include <stdio.h> 53 #include <string.h> 54 55 ImageView::ImageView(BRect rect, const char *name) 56 : BView(rect, name, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS) 57 { 58 fpbitmap = NULL; 59 60 SetViewColor(255, 255, 255); 61 } 62 63 ImageView::~ImageView() 64 { 65 delete fpbitmap; 66 fpbitmap = NULL; 67 } 68 69 void 70 ImageView::AttachedToWindow() 71 { 72 AdjustScrollBars(); 73 } 74 75 void 76 ImageView::Draw(BRect rect) 77 { 78 if (HasImage()) 79 DrawBitmap(fpbitmap, BPoint(0, 0)); 80 } 81 82 void 83 ImageView::FrameResized(float width, float height) 84 { 85 AdjustScrollBars(); 86 87 // If there is a bitmap, draw it. 88 // If not, invalidate the entire view so that 89 // the advice text will be displayed 90 if (HasImage()) 91 ReDraw(); 92 else 93 Invalidate(); 94 } 95 96 void 97 ImageView::MouseDown(BPoint point) 98 { 99 if (!HasImage()) 100 return; 101 102 // Only accept left button clicks 103 BMessage *pmsg = Window()->CurrentMessage(); 104 int32 button = pmsg->FindInt32("buttons"); 105 if (button != B_PRIMARY_MOUSE_BUTTON) 106 return; 107 108 // Tell BeOS to setup a Drag/Drop operation 109 // 110 // (When the image is dropped, BeOS sends 111 // the following message to ImageWindow, 112 // which causes it to call ImageView::SetImage()) 113 BMessage msg(B_SIMPLE_DATA); 114 msg.AddInt32("be:actions", B_COPY_TARGET); 115 msg.AddString("be:filetypes", "application/octet-stream"); 116 msg.AddString("be:types", "application/octet-stream"); 117 msg.AddString("be:clip_name", "Bitmap"); 118 119 DragMessage(&msg, Bounds()); 120 } 121 122 void 123 ImageView::MouseMoved(BPoint point, uint32 state, const BMessage *pmsg) 124 { 125 } 126 127 void 128 ImageView::MouseUp(BPoint point) 129 { 130 } 131 132 void 133 ImageView::MessageReceived(BMessage *pmsg) 134 { 135 switch (pmsg->what) { 136 case B_COPY_TARGET: 137 SaveImageAtDropLocation(pmsg); 138 break; 139 140 default: 141 BView::MessageReceived(pmsg); 142 break; 143 } 144 } 145 146 void 147 ImageView::SaveImageAtDropLocation(BMessage *pmsg) 148 { 149 // Find the location and name of the drop and 150 // write the image file there 151 152 BBitmapStream stream(fpbitmap); 153 154 StatusCheck chk; 155 // throw an exception if this is assigned 156 // anything other than B_OK 157 try { 158 entry_ref dirref; 159 chk = pmsg->FindRef("directory", &dirref); 160 const char *filename; 161 chk = pmsg->FindString("name", &filename); 162 163 BDirectory dir(&dirref); 164 BFile file(&dir, filename, B_WRITE_ONLY | B_CREATE_FILE); 165 chk = file.InitCheck(); 166 167 BTranslatorRoster *proster = BTranslatorRoster::Default(); 168 chk = proster->Translate(&stream, NULL, NULL, &file, B_TGA_FORMAT); 169 170 } catch (StatusNotOKException) { 171 BAlert *palert = new BAlert(NULL, 172 "Sorry, unable to write the image file.", "OK"); 173 palert->Go(); 174 } 175 176 stream.DetachBitmap(&fpbitmap); 177 } 178 179 void 180 ImageView::AdjustScrollBars() 181 { 182 BRect rctview = Bounds(), rctbitmap(0, 0, 0, 0); 183 if (HasImage()) 184 rctbitmap = fpbitmap->Bounds(); 185 186 float prop, range; 187 BScrollBar *psb = ScrollBar(B_HORIZONTAL); 188 if (psb) { 189 range = rctbitmap.Width() - rctview.Width(); 190 if (range < 0) range = 0; 191 prop = rctview.Width() / rctbitmap.Width(); 192 if (prop > 1.0f) prop = 1.0f; 193 psb->SetRange(0, range); 194 psb->SetProportion(prop); 195 psb->SetSteps(10, 100); 196 } 197 198 psb = ScrollBar(B_VERTICAL); 199 if (psb) { 200 range = rctbitmap.Height() - rctview.Height(); 201 if (range < 0) range = 0; 202 prop = rctview.Height() / rctbitmap.Height(); 203 if (prop > 1.0f) prop = 1.0f; 204 psb->SetRange(0, range); 205 psb->SetProportion(prop); 206 psb->SetSteps(10, 100); 207 } 208 } 209 210 struct ColorSpaceName { 211 color_space id; 212 const char *name; 213 }; 214 #define COLORSPACENAME(id) {id, #id} 215 216 // convert colorspace numerical value to 217 // a string value 218 const char * 219 get_color_space_name(color_space colors) 220 { 221 // print out colorspace if it matches an item in the list 222 const ColorSpaceName kcolorspaces[] = { 223 COLORSPACENAME(B_NO_COLOR_SPACE), 224 COLORSPACENAME(B_RGB32), 225 COLORSPACENAME(B_RGBA32), 226 COLORSPACENAME(B_RGB24), 227 COLORSPACENAME(B_RGB16), 228 COLORSPACENAME(B_RGB15), 229 COLORSPACENAME(B_RGBA15), 230 COLORSPACENAME(B_CMAP8), 231 COLORSPACENAME(B_GRAY8), 232 COLORSPACENAME(B_GRAY1), 233 COLORSPACENAME(B_RGB32_BIG), 234 COLORSPACENAME(B_RGBA32_BIG), 235 COLORSPACENAME(B_RGB24_BIG), 236 COLORSPACENAME(B_RGB16_BIG), 237 COLORSPACENAME(B_RGB15_BIG), 238 COLORSPACENAME(B_RGBA15_BIG), 239 COLORSPACENAME(B_YCbCr422), 240 COLORSPACENAME(B_YCbCr411), 241 COLORSPACENAME(B_YCbCr444), 242 COLORSPACENAME(B_YCbCr420), 243 COLORSPACENAME(B_YUV422), 244 COLORSPACENAME(B_YUV411), 245 COLORSPACENAME(B_YUV444), 246 COLORSPACENAME(B_YUV420), 247 COLORSPACENAME(B_YUV9), 248 COLORSPACENAME(B_YUV12), 249 COLORSPACENAME(B_UVL24), 250 COLORSPACENAME(B_UVL32), 251 COLORSPACENAME(B_UVLA32), 252 COLORSPACENAME(B_LAB24), 253 COLORSPACENAME(B_LAB32), 254 COLORSPACENAME(B_LABA32), 255 COLORSPACENAME(B_HSI24), 256 COLORSPACENAME(B_HSI32), 257 COLORSPACENAME(B_HSIA32), 258 COLORSPACENAME(B_HSV24), 259 COLORSPACENAME(B_HSV32), 260 COLORSPACENAME(B_HSVA32), 261 COLORSPACENAME(B_HLS24), 262 COLORSPACENAME(B_HLS32), 263 COLORSPACENAME(B_HLSA32), 264 COLORSPACENAME(B_CMY24), 265 COLORSPACENAME(B_CMY32), 266 COLORSPACENAME(B_CMYA32), 267 COLORSPACENAME(B_CMYK32) 268 }; 269 const int32 kncolorspaces = sizeof(kcolorspaces) / 270 sizeof(ColorSpaceName); 271 for (int32 i = 0; i < kncolorspaces; i++) { 272 if (colors == kcolorspaces[i].id) 273 return kcolorspaces[i].name; 274 } 275 276 return "Unknown"; 277 } 278 279 // return a string of the passed number formated 280 // as a hexadecimal number in lowercase with a leading "0x" 281 const char * 282 hex_format(uint32 num) 283 { 284 static char str[11] = { 0 }; 285 sprintf(str, "0x%.8lx", num); 286 287 return str; 288 } 289 290 // convert passed number to a string of 4 characters 291 // and return that string 292 const char * 293 char_format(uint32 num) 294 { 295 static char str[5] = { 0 }; 296 uint32 bnum = B_HOST_TO_BENDIAN_INT32(num); 297 memcpy(str, &bnum, 4); 298 299 return str; 300 } 301 302 // Send information about the currently open image to the 303 // BApplication object so it can send it to the InfoWindow 304 void 305 ImageView::UpdateInfoWindow(const BPath &path, const translator_info &tinfo, 306 const char *tranname, const char *traninfo, int32 tranversion) 307 { 308 BMessage msg(M_INFO_WINDOW_TEXT); 309 BString bstr; 310 311 // Bitmap Info 312 bstr << "Image: " << path.Path() << "\n"; 313 color_space cs = fpbitmap->ColorSpace(); 314 bstr << "Color Space: " << get_color_space_name(cs) << " (" << 315 hex_format(static_cast<uint32>(cs)) << ")\n"; 316 bstr << "Dimensions: " << fpbitmap->Bounds().IntegerWidth() + 1 << " x " << 317 fpbitmap->Bounds().IntegerHeight() + 1 << "\n"; 318 bstr << "Bytes per Row: " << fpbitmap->BytesPerRow() << "\n"; 319 bstr << "Total Bytes: " << fpbitmap->BitsLength() << "\n"; 320 321 // Identify Info 322 bstr << "\nIdentify Info:\n"; 323 bstr << "ID String: " << tinfo.name << "\n"; 324 bstr << "MIME Type: " << tinfo.MIME << "\n"; 325 bstr << "Type: '" << char_format(tinfo.type) << "' (" << 326 hex_format(tinfo.type) <<")\n"; 327 bstr << "Translator ID: " << tinfo.translator << "\n"; 328 bstr << "Group: '" << char_format(tinfo.group) << "' (" << 329 hex_format(tinfo.group) << ")\n"; 330 bstr << "Quality: " << tinfo.quality << "\n"; 331 bstr << "Capability: " << tinfo.capability << "\n"; 332 333 // Translator Info 334 bstr << "\nTranslator Used:\n"; 335 bstr << "Name: " << tranname << "\n"; 336 bstr << "Info: " << traninfo << "\n"; 337 bstr << "Version: " << tranversion << "\n"; 338 339 msg.AddString("text", bstr); 340 be_app->PostMessage(&msg); 341 } 342 343 void 344 ImageView::SetImage(BMessage *pmsg) 345 { 346 // Replace current image with the image 347 // specified in the given BMessage 348 349 StatusCheck chk; 350 351 try { 352 entry_ref ref; 353 chk = pmsg->FindRef("refs", &ref); 354 355 BFile file(&ref, B_READ_ONLY); 356 chk = file.InitCheck(); 357 358 BTranslatorRoster *proster = BTranslatorRoster::Default(); 359 if (!proster) 360 // throw exception 361 chk = B_ERROR; 362 363 // determine what type the image is 364 translator_info tinfo; 365 chk = proster->Identify(&file, NULL, &tinfo, 0, NULL, 366 B_TRANSLATOR_BITMAP); 367 368 // get the name and info about the translator 369 const char *tranname = NULL, *traninfo = NULL; 370 int32 tranversion = 0; 371 chk = proster->GetTranslatorInfo(tinfo.translator, &tranname, 372 &traninfo, &tranversion); 373 374 // perform the actual translation 375 BBitmapStream outstream; 376 chk = proster->Translate(&file, &tinfo, NULL, &outstream, 377 B_TRANSLATOR_BITMAP); 378 BBitmap *pbitmap = NULL; 379 chk = outstream.DetachBitmap(&pbitmap); 380 fpbitmap = pbitmap; 381 pbitmap = NULL; 382 383 // Set the name of the Window to reflect the file name 384 BWindow *pwin = Window(); 385 BEntry entry(&ref); 386 BPath path; 387 if (entry.InitCheck() == B_OK) { 388 if (path.SetTo(&entry) == B_OK) 389 pwin->SetTitle(path.Leaf()); 390 else 391 pwin->SetTitle(IMAGEWINDOW_TITLE); 392 } else 393 pwin->SetTitle(IMAGEWINDOW_TITLE); 394 395 UpdateInfoWindow(path, tinfo, tranname, traninfo, tranversion); 396 397 // Resize parent window and set size limits to 398 // reflect the size of the new bitmap 399 float width, height; 400 BMenuBar *pbar = pwin->KeyMenuBar(); 401 width = fpbitmap->Bounds().Width() + B_V_SCROLL_BAR_WIDTH; 402 height = fpbitmap->Bounds().Height() + 403 pbar->Bounds().Height() + B_H_SCROLL_BAR_HEIGHT + 1; 404 405 BScreen *pscreen = new BScreen(pwin); 406 BRect rctscreen = pscreen->Frame(); 407 if (width > rctscreen.Width()) 408 width = rctscreen.Width(); 409 if (height > rctscreen.Height()) 410 height = rctscreen.Height(); 411 pwin->SetSizeLimits(B_V_SCROLL_BAR_WIDTH * 4, width, 412 pbar->Bounds().Height() + (B_H_SCROLL_BAR_HEIGHT * 4) + 1, height); 413 pwin->SetZoomLimits(width, height); 414 415 AdjustScrollBars(); 416 417 //pwin->Zoom(); 418 // Perform all of the hard work of resizing the 419 // window while taking into account the size of 420 // the screen, the tab and borders of the window 421 // 422 // HACK: Need to fix case where window un-zooms 423 // when the window is already the correct size 424 // for the current image 425 426 // repaint view 427 FillRect(Bounds()); 428 ReDraw(); 429 } catch (StatusNotOKException) { 430 BAlert *palert = new BAlert(NULL, 431 "Sorry, unable to load the image.", "OK"); 432 palert->Go(); 433 } 434 } 435 436