19949213aSStephan Aßmus /* 29949213aSStephan Aßmus Copyright 1999, Be Incorporated. All Rights Reserved. 39949213aSStephan Aßmus This file may be used under the terms of the Be Sample Code License. 49949213aSStephan Aßmus */ 59949213aSStephan Aßmus 69949213aSStephan Aßmus /* Parse the ASCII and raw versions of PPM. */ 79949213aSStephan Aßmus /* Note that the parsing of ASCII is very inefficient, because BFile */ 89949213aSStephan Aßmus /* does not buffer data. We should wrap a buffering thing around */ 99949213aSStephan Aßmus /* the input or output when they are in ASCII mode. */ 109949213aSStephan Aßmus 119949213aSStephan Aßmus #include <Bitmap.h> 1270d59669SSiarzhuk Zharski #include <ByteOrder.h> 1370d59669SSiarzhuk Zharski #include <Catalog.h> 1470d59669SSiarzhuk Zharski #include <CheckBox.h> 1570d59669SSiarzhuk Zharski #include <FindDirectory.h> 167d48219bSHannah Boneß #include <LayoutBuilder.h> 1770d59669SSiarzhuk Zharski #include <Locker.h> 1870d59669SSiarzhuk Zharski #include <MenuField.h> 1970d59669SSiarzhuk Zharski #include <MenuItem.h> 2070d59669SSiarzhuk Zharski #include <Message.h> 2170d59669SSiarzhuk Zharski #include <Path.h> 2270d59669SSiarzhuk Zharski #include <PopUpMenu.h> 2370d59669SSiarzhuk Zharski #include <Screen.h> 2470d59669SSiarzhuk Zharski #include <StringView.h> 2570d59669SSiarzhuk Zharski #include <TranslatorAddOn.h> 2670d59669SSiarzhuk Zharski #include <TranslationKit.h> 279949213aSStephan Aßmus 289949213aSStephan Aßmus #include <ctype.h> 299949213aSStephan Aßmus #include <string.h> 309949213aSStephan Aßmus #include <stdlib.h> 319949213aSStephan Aßmus #include <stdio.h> 3270d59669SSiarzhuk Zharski #include <syslog.h> 339949213aSStephan Aßmus 349949213aSStephan Aßmus #include "colorspace.h" 359949213aSStephan Aßmus 36546208a5SOliver Tappe #undef B_TRANSLATION_CONTEXT 37546208a5SOliver Tappe #define B_TRANSLATION_CONTEXT "PPMTranslator" 389949213aSStephan Aßmus 399949213aSStephan Aßmus #if DEBUG 409949213aSStephan Aßmus #define dprintf(x) printf x 419949213aSStephan Aßmus #else 429949213aSStephan Aßmus #define dprintf(x) 439949213aSStephan Aßmus #endif 449949213aSStephan Aßmus 459949213aSStephan Aßmus 469949213aSStephan Aßmus #if !defined(_PR3_COMPATIBLE_) /* R4 headers? Else we need to define these constants. */ 479949213aSStephan Aßmus #define B_CMY24 ((color_space)0xC001) /* C[7:0] M[7:0] Y[7:0] No gray removal done */ 489949213aSStephan Aßmus #define B_CMY32 ((color_space)0xC002) /* C[7:0] M[7:0] Y[7:0] X[7:0] No gray removal done */ 499949213aSStephan Aßmus #define B_CMYA32 ((color_space)0xE002) /* C[7:0] M[7:0] Y[7:0] A[7:0] No gray removal done */ 509949213aSStephan Aßmus #define B_CMYK32 ((color_space)0xC003) /* C[7:0] M[7:0] Y[7:0] K[7:0] */ 519949213aSStephan Aßmus #endif 529949213aSStephan Aßmus 539949213aSStephan Aßmus #define PPM_TRANSLATOR_VERSION 0x100 549949213aSStephan Aßmus 559949213aSStephan Aßmus /* These three data items are exported by every translator. */ 56fcc3e627SStephan Aßmus char translatorName[] = "PPM images"; 579949213aSStephan Aßmus char translatorInfo[] = "PPM image translator v1.0.0, " __DATE__; 589949213aSStephan Aßmus int32 translatorVersion = PPM_TRANSLATOR_VERSION; 599949213aSStephan Aßmus // Revision: lowest 4 bits 609949213aSStephan Aßmus // Minor: next 4 bits 619949213aSStephan Aßmus // Major: highest 24 bits 629949213aSStephan Aßmus 6370d59669SSiarzhuk Zharski /* Be reserves all codes with non-lowercase letters in them. */ 649949213aSStephan Aßmus /* Luckily, there is already a reserved code for PPM. If you */ 659949213aSStephan Aßmus /* make up your own for a new type, use lower-case letters. */ 669949213aSStephan Aßmus #define PPM_TYPE 'PPM ' 679949213aSStephan Aßmus 689949213aSStephan Aßmus 699949213aSStephan Aßmus /* These two data arrays are a really good idea to export from Translators, but not required. */ 709949213aSStephan Aßmus translation_format inputFormats[] = { 71c095606eSRyan Leavengood { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.4, 0.8, "image/x-be-bitmap", "Be Bitmap Format (PPMTranslator)" }, 729949213aSStephan Aßmus { PPM_TYPE, B_TRANSLATOR_BITMAP, 0.3, 0.8, "image/x-portable-pixmap", "PPM image" }, 739949213aSStephan Aßmus { 0, 0, 0, 0, "\0", "\0" } 749949213aSStephan Aßmus }; /* optional (else Identify is always called) */ 759949213aSStephan Aßmus 769949213aSStephan Aßmus translation_format outputFormats[] = { 77c095606eSRyan Leavengood { B_TRANSLATOR_BITMAP, B_TRANSLATOR_BITMAP, 0.4, 0.8, "image/x-be-bitmap", "Be Bitmap Format (PPMTranslator)" }, 789949213aSStephan Aßmus { PPM_TYPE, B_TRANSLATOR_BITMAP, 0.3, 0.8, "image/x-portable-pixmap", "PPM image" }, 799949213aSStephan Aßmus { 0, 0, 0, 0, "\0", "\0" } 809949213aSStephan Aßmus }; /* optional (else Translate is called anyway) */ 819949213aSStephan Aßmus 829949213aSStephan Aßmus /* Translators that don't export outputFormats */ 839949213aSStephan Aßmus /* will not be considered by files looking for */ 849949213aSStephan Aßmus /* specific output formats. */ 859949213aSStephan Aßmus 869949213aSStephan Aßmus 879949213aSStephan Aßmus /* We keep our settings in a global struct, and wrap a lock around them. */ 889949213aSStephan Aßmus struct ppm_settings { 899949213aSStephan Aßmus color_space out_space; 909949213aSStephan Aßmus BPoint window_pos; 919949213aSStephan Aßmus bool write_ascii; 929949213aSStephan Aßmus bool settings_touched; 939949213aSStephan Aßmus }; 94bf243977SPhilippe Houdoin static BLocker g_settings_lock("PPM settings lock"); 95bf243977SPhilippe Houdoin static ppm_settings g_settings; 969949213aSStephan Aßmus 979949213aSStephan Aßmus BPoint get_window_origin(); 989949213aSStephan Aßmus void set_window_origin(BPoint pos); 999949213aSStephan Aßmus BPoint get_window_origin() 1009949213aSStephan Aßmus { 1019949213aSStephan Aßmus BPoint ret; 1029949213aSStephan Aßmus g_settings_lock.Lock(); 1039949213aSStephan Aßmus ret = g_settings.window_pos; 1049949213aSStephan Aßmus g_settings_lock.Unlock(); 1059949213aSStephan Aßmus return ret; 1069949213aSStephan Aßmus } 1079949213aSStephan Aßmus 1089949213aSStephan Aßmus void set_window_origin(BPoint pos) 1099949213aSStephan Aßmus { 1109949213aSStephan Aßmus g_settings_lock.Lock(); 1119949213aSStephan Aßmus g_settings.window_pos = pos; 1129949213aSStephan Aßmus g_settings.settings_touched = true; 1139949213aSStephan Aßmus g_settings_lock.Unlock(); 1149949213aSStephan Aßmus } 1159949213aSStephan Aßmus 1169949213aSStephan Aßmus 1179949213aSStephan Aßmus class PrefsLoader { 1189949213aSStephan Aßmus public: 1199949213aSStephan Aßmus PrefsLoader( 1209949213aSStephan Aßmus const char * str) 1219949213aSStephan Aßmus { 1229949213aSStephan Aßmus dprintf(("PPMTranslator: PrefsLoader()\n")); 1239949213aSStephan Aßmus /* defaults */ 1249949213aSStephan Aßmus g_settings.out_space = B_NO_COLOR_SPACE; 1259949213aSStephan Aßmus g_settings.window_pos = B_ORIGIN; 1269949213aSStephan Aßmus g_settings.write_ascii = false; 1279949213aSStephan Aßmus g_settings.settings_touched = false; 1289949213aSStephan Aßmus BPath path; 1299949213aSStephan Aßmus if (find_directory(B_USER_SETTINGS_DIRECTORY, &path)) { 1309949213aSStephan Aßmus path.SetTo("/tmp"); 1319949213aSStephan Aßmus } 1329949213aSStephan Aßmus path.Append(str); 1339949213aSStephan Aßmus FILE * f = fopen(path.Path(), "r"); 1349949213aSStephan Aßmus /* parse text settings file -- this should be a library... */ 1359949213aSStephan Aßmus if (f) { 1369949213aSStephan Aßmus char line[1024]; 1379949213aSStephan Aßmus char name[32]; 1389949213aSStephan Aßmus char * ptr; 1399949213aSStephan Aßmus while (true) { 1409949213aSStephan Aßmus line[0] = 0; 1419949213aSStephan Aßmus fgets(line, 1024, f); 1429949213aSStephan Aßmus if (!line[0]) { 1439949213aSStephan Aßmus break; 1449949213aSStephan Aßmus } 1459949213aSStephan Aßmus /* remember: line ends with \n, so printf()s don't have to */ 1469949213aSStephan Aßmus ptr = line; 1479949213aSStephan Aßmus while (isspace(*ptr)) { 1489949213aSStephan Aßmus ptr++; 1499949213aSStephan Aßmus } 1509949213aSStephan Aßmus if (*ptr == '#' || !*ptr) { /* comment or blank */ 1519949213aSStephan Aßmus continue; 1529949213aSStephan Aßmus } 1539949213aSStephan Aßmus if (sscanf(ptr, "%31[a-zA-Z_0-9] =", name) != 1) { 15470d59669SSiarzhuk Zharski syslog(LOG_ERR, "unknown PPMTranslator " 15570d59669SSiarzhuk Zharski "settings line: %s", line); 1569949213aSStephan Aßmus } 1579949213aSStephan Aßmus else { 1589949213aSStephan Aßmus if (!strcmp(name, "color_space")) { 1599949213aSStephan Aßmus while (*ptr != '=') { 1609949213aSStephan Aßmus ptr++; 1619949213aSStephan Aßmus } 1629949213aSStephan Aßmus ptr++; 16370d59669SSiarzhuk Zharski if (sscanf(ptr, "%d", 16470d59669SSiarzhuk Zharski (int*)&g_settings.out_space) != 1) { 16570d59669SSiarzhuk Zharski syslog(LOG_ERR, "illegal color space " 16670d59669SSiarzhuk Zharski "in PPMTranslator settings: %s", ptr); 1679949213aSStephan Aßmus } 1689949213aSStephan Aßmus } 1699949213aSStephan Aßmus else if (!strcmp(name, "window_pos")) { 1709949213aSStephan Aßmus while (*ptr != '=') { 1719949213aSStephan Aßmus ptr++; 1729949213aSStephan Aßmus } 1739949213aSStephan Aßmus ptr++; 17470d59669SSiarzhuk Zharski if (sscanf(ptr, "%f,%f", 17570d59669SSiarzhuk Zharski &g_settings.window_pos.x, 17670d59669SSiarzhuk Zharski &g_settings.window_pos.y) != 2) { 17770d59669SSiarzhuk Zharski syslog(LOG_ERR, "illegal window position " 17870d59669SSiarzhuk Zharski "in PPMTranslator settings: %s", ptr); 1799949213aSStephan Aßmus } 1809949213aSStephan Aßmus } 1819949213aSStephan Aßmus else if (!strcmp(name, "write_ascii")) { 1829949213aSStephan Aßmus while (*ptr != '=') { 1839949213aSStephan Aßmus ptr++; 1849949213aSStephan Aßmus } 1859949213aSStephan Aßmus ptr++; 1869949213aSStephan Aßmus int ascii = g_settings.write_ascii; 1879949213aSStephan Aßmus if (sscanf(ptr, "%d", &ascii) != 1) { 18870d59669SSiarzhuk Zharski syslog(LOG_ERR, "illegal write_ascii value " 18970d59669SSiarzhuk Zharski "in PPMTranslator settings: %s", ptr); 1909949213aSStephan Aßmus } 1919949213aSStephan Aßmus else { 1929949213aSStephan Aßmus g_settings.write_ascii = ascii; 1939949213aSStephan Aßmus } 1949949213aSStephan Aßmus } 1959949213aSStephan Aßmus else { 19670d59669SSiarzhuk Zharski syslog(LOG_ERR, 19770d59669SSiarzhuk Zharski "unknown PPMTranslator setting: %s", line); 1989949213aSStephan Aßmus } 1999949213aSStephan Aßmus } 2009949213aSStephan Aßmus } 2019949213aSStephan Aßmus fclose(f); 2029949213aSStephan Aßmus } 2039949213aSStephan Aßmus } 2049949213aSStephan Aßmus ~PrefsLoader() 2059949213aSStephan Aßmus { 2069949213aSStephan Aßmus /* No need writing settings if there aren't any */ 2079949213aSStephan Aßmus if (g_settings.settings_touched) { 2089949213aSStephan Aßmus BPath path; 2099949213aSStephan Aßmus if (find_directory(B_USER_SETTINGS_DIRECTORY, &path)) { 2109949213aSStephan Aßmus path.SetTo("/tmp"); 2119949213aSStephan Aßmus } 2129949213aSStephan Aßmus path.Append("PPMTranslator_Settings"); 2139949213aSStephan Aßmus FILE * f = fopen(path.Path(), "w"); 2149949213aSStephan Aßmus if (f) { 2159949213aSStephan Aßmus fprintf(f, "# PPMTranslator settings version %d.%d.%d\n", 2169949213aSStephan Aßmus static_cast<int>(translatorVersion >> 8), 2179949213aSStephan Aßmus static_cast<int>((translatorVersion >> 4) & 0xf), 2189949213aSStephan Aßmus static_cast<int>(translatorVersion & 0xf)); 2199949213aSStephan Aßmus fprintf(f, "color_space = %d\n", g_settings.out_space); 22070d59669SSiarzhuk Zharski fprintf(f, "window_pos = %g,%g\n", g_settings.window_pos.x, 22170d59669SSiarzhuk Zharski g_settings.window_pos.y); 2229949213aSStephan Aßmus fprintf(f, "write_ascii = %d\n", g_settings.write_ascii ? 1 : 0); 2239949213aSStephan Aßmus fclose(f); 2249949213aSStephan Aßmus } 2259949213aSStephan Aßmus } 2269949213aSStephan Aßmus } 2279949213aSStephan Aßmus }; 2289949213aSStephan Aßmus 2299949213aSStephan Aßmus PrefsLoader g_prefs_loader("PPMTranslator_Settings"); 2309949213aSStephan Aßmus 2319949213aSStephan Aßmus /* Some prototypes for functions we use. */ 2329949213aSStephan Aßmus status_t read_ppm_header(BDataIO * io, int * width, int * rowbytes, int * height, 2339949213aSStephan Aßmus int * max, bool * ascii, color_space * space, bool * is_ppm, char ** comment); 2349949213aSStephan Aßmus status_t read_bits_header(BDataIO * io, int skipped, int * width, int * rowbytes, 2359949213aSStephan Aßmus int * height, int * max, bool * ascii, color_space * space); 2369949213aSStephan Aßmus status_t write_comment(const char * str, BDataIO * io); 2379949213aSStephan Aßmus status_t copy_data(BDataIO * in, BDataIO * out, int rowbytes, int out_rowbytes, 2389949213aSStephan Aßmus int height, int max, bool in_ascii, bool out_ascii, color_space in_space, 2399949213aSStephan Aßmus color_space out_space); 2409949213aSStephan Aßmus 2419949213aSStephan Aßmus /* Return B_NO_TRANSLATOR if not handling this data. */ 2429949213aSStephan Aßmus /* Even if inputFormats exists, may be called for data without hints */ 2439949213aSStephan Aßmus /* If outType is not 0, must be able to export in wanted format */ 2449949213aSStephan Aßmus 2459949213aSStephan Aßmus status_t 2469949213aSStephan Aßmus Identify( /* required */ 2479949213aSStephan Aßmus BPositionIO * inSource, 2489949213aSStephan Aßmus const translation_format * inFormat, /* can beNULL */ 2499949213aSStephan Aßmus BMessage * ioExtension, /* can be NULL */ 2509949213aSStephan Aßmus translator_info * outInfo, 2519949213aSStephan Aßmus uint32 outType) 2529949213aSStephan Aßmus { 2539949213aSStephan Aßmus dprintf(("PPMTranslator: Identify()\n")); 2549949213aSStephan Aßmus /* Silence compiler warnings. */ 2559949213aSStephan Aßmus inFormat = inFormat; 2569949213aSStephan Aßmus ioExtension = ioExtension; 2579949213aSStephan Aßmus 2589949213aSStephan Aßmus /* Check that requested format is something we can deal with. */ 2599949213aSStephan Aßmus if (outType == 0) { 2609949213aSStephan Aßmus outType = B_TRANSLATOR_BITMAP; 2619949213aSStephan Aßmus } 2629949213aSStephan Aßmus if (outType != B_TRANSLATOR_BITMAP && outType != PPM_TYPE) { 2639949213aSStephan Aßmus return B_NO_TRANSLATOR; 2649949213aSStephan Aßmus } 2659949213aSStephan Aßmus 2669949213aSStephan Aßmus /* Check header. */ 2679949213aSStephan Aßmus int width, rowbytes, height, max; 2689949213aSStephan Aßmus bool ascii, is_ppm; 2699949213aSStephan Aßmus color_space space; 2709949213aSStephan Aßmus status_t err = read_ppm_header(inSource, &width, &rowbytes, &height, &max, &ascii, &space, &is_ppm, NULL); 2719949213aSStephan Aßmus if (err != B_OK) { 2729949213aSStephan Aßmus return err; 2739949213aSStephan Aßmus } 2749949213aSStephan Aßmus /* Stuff info into info struct -- Translation Kit will do "translator" for us. */ 2759949213aSStephan Aßmus outInfo->group = B_TRANSLATOR_BITMAP; 2769949213aSStephan Aßmus if (is_ppm) { 2779949213aSStephan Aßmus outInfo->type = PPM_TYPE; 2789949213aSStephan Aßmus outInfo->quality = 0.3; /* no alpha, etc */ 2799949213aSStephan Aßmus outInfo->capability = 0.8; /* we're pretty good at PPM reading, though */ 280aec33db1SPhilippe Saint-Pierre strlcpy(outInfo->name, B_TRANSLATE("PPM image"), sizeof(outInfo->name)); 2819949213aSStephan Aßmus strcpy(outInfo->MIME, "image/x-portable-pixmap"); 2829949213aSStephan Aßmus } 2839949213aSStephan Aßmus else { 2849949213aSStephan Aßmus outInfo->type = B_TRANSLATOR_BITMAP; 2859949213aSStephan Aßmus outInfo->quality = 0.4; /* B_TRANSLATOR_BITMAP can do alpha, at least */ 2869949213aSStephan Aßmus outInfo->capability = 0.8; /* and we might not know many variations thereof */ 287aec33db1SPhilippe Saint-Pierre strlcpy(outInfo->name, B_TRANSLATE("Be Bitmap Format (PPMTranslator)"), 2883927bd3cSPhilippe Saint-Pierre sizeof(outInfo->name)); 2899949213aSStephan Aßmus strcpy(outInfo->MIME, "image/x-be-bitmap"); /* this is the MIME type of B_TRANSLATOR_BITMAP */ 2909949213aSStephan Aßmus } 2919949213aSStephan Aßmus return B_OK; 2929949213aSStephan Aßmus } 2939949213aSStephan Aßmus 2949949213aSStephan Aßmus 2959949213aSStephan Aßmus /* Return B_NO_TRANSLATOR if not handling the output format */ 2969949213aSStephan Aßmus /* If outputFormats exists, will only be called for those formats */ 2979949213aSStephan Aßmus 2989949213aSStephan Aßmus status_t 2999949213aSStephan Aßmus Translate( /* required */ 3009949213aSStephan Aßmus BPositionIO * inSource, 3019949213aSStephan Aßmus const translator_info * /* inInfo*/ , /* silence compiler warning */ 3029949213aSStephan Aßmus BMessage * ioExtension, /* can be NULL */ 3039949213aSStephan Aßmus uint32 outType, 3049949213aSStephan Aßmus BPositionIO * outDestination) 3059949213aSStephan Aßmus { 3069949213aSStephan Aßmus dprintf(("PPMTranslator: Translate()\n")); 3079949213aSStephan Aßmus inSource->Seek(0, SEEK_SET); /* paranoia */ 3089949213aSStephan Aßmus // inInfo = inInfo; /* silence compiler warning */ 3099949213aSStephan Aßmus /* Check what we're being asked to produce. */ 3109949213aSStephan Aßmus if (!outType) { 3119949213aSStephan Aßmus outType = B_TRANSLATOR_BITMAP; 3129949213aSStephan Aßmus } 3139949213aSStephan Aßmus dprintf(("PPMTranslator: outType is '%c%c%c%c'\n", char(outType>>24), char(outType>>16), char(outType>>8), char(outType))); 3149949213aSStephan Aßmus if (outType != B_TRANSLATOR_BITMAP && outType != PPM_TYPE) { 3159949213aSStephan Aßmus return B_NO_TRANSLATOR; 3169949213aSStephan Aßmus } 3179949213aSStephan Aßmus 3189949213aSStephan Aßmus /* Figure out what we've been given (again). */ 3199949213aSStephan Aßmus int width, rowbytes, height, max; 3209949213aSStephan Aßmus bool ascii, is_ppm; 3219949213aSStephan Aßmus color_space space; 3229949213aSStephan Aßmus /* Read_ppm_header() will always return with stream at beginning of data */ 3239949213aSStephan Aßmus /* for both B_TRANSLATOR_BITMAP and PPM_TYPE, and indicate what it is. */ 3249949213aSStephan Aßmus char * comment = NULL; 3259949213aSStephan Aßmus status_t err = read_ppm_header(inSource, &width, &rowbytes, &height, &max, &ascii, &space, &is_ppm, &comment); 3269949213aSStephan Aßmus if (comment != NULL) { 3279949213aSStephan Aßmus if (ioExtension != NULL) { 3289949213aSStephan Aßmus #if defined(_PR3_COMPATIBLE_) /* R4 headers? */ 3299949213aSStephan Aßmus ioExtension->AddString(B_TRANSLATOR_EXT_COMMENT, comment); 3309949213aSStephan Aßmus #else 3319949213aSStephan Aßmus ioExtension->AddString("/comment", comment); 3329949213aSStephan Aßmus #endif 3339949213aSStephan Aßmus } 3349949213aSStephan Aßmus free(comment); 3359949213aSStephan Aßmus } 3369949213aSStephan Aßmus if (err < B_OK) { 3371a7bcf69SOliver Tappe dprintf(("read_ppm_header() error %s [%" B_PRIx32 "]\n", strerror(err), 3381a7bcf69SOliver Tappe err)); 3399949213aSStephan Aßmus return err; 3409949213aSStephan Aßmus } 3419949213aSStephan Aßmus /* Check if we're configured to write ASCII format file. */ 3429949213aSStephan Aßmus bool out_ascii = false; 3439949213aSStephan Aßmus if (outType == PPM_TYPE) { 3449949213aSStephan Aßmus out_ascii = g_settings.write_ascii; 3459949213aSStephan Aßmus if (ioExtension != NULL) { 3469949213aSStephan Aßmus ioExtension->FindBool("ppm /ascii", &out_ascii); 3479949213aSStephan Aßmus } 3489949213aSStephan Aßmus } 3499949213aSStephan Aßmus err = B_OK; 3509949213aSStephan Aßmus /* Figure out which color space to convert to */ 3519949213aSStephan Aßmus color_space out_space; 3529949213aSStephan Aßmus int out_rowbytes; 3539949213aSStephan Aßmus g_settings_lock.Lock(); 3549949213aSStephan Aßmus if (outType == PPM_TYPE) { 3559949213aSStephan Aßmus out_space = B_RGB24_BIG; 3569949213aSStephan Aßmus out_rowbytes = 3*width; 3579949213aSStephan Aßmus } 3589949213aSStephan Aßmus else { /* When outputting to B_TRANSLATOR_BITMAP, follow user's wishes. */ 3599949213aSStephan Aßmus #if defined(_PR3_COMPATIBLE_) /* R4 headers? */ 3609949213aSStephan Aßmus if (!ioExtension || ioExtension->FindInt32(B_TRANSLATOR_EXT_BITMAP_COLOR_SPACE, (int32*)&out_space) || 3619949213aSStephan Aßmus #else 3629949213aSStephan Aßmus if (!ioExtension || ioExtension->FindInt32("bits/space", (int32*)&out_space) || 3639949213aSStephan Aßmus #endif 3649949213aSStephan Aßmus (out_space == B_NO_COLOR_SPACE)) { 3659949213aSStephan Aßmus if (g_settings.out_space == B_NO_COLOR_SPACE) { 3669949213aSStephan Aßmus switch (space) { /* The 24-bit versions are pretty silly, use 32 instead. */ 3679949213aSStephan Aßmus case B_RGB24: 3689949213aSStephan Aßmus case B_RGB24_BIG: 3699949213aSStephan Aßmus out_space = B_RGB32; 3709949213aSStephan Aßmus break; 3719949213aSStephan Aßmus default: 3729949213aSStephan Aßmus /* use whatever is there */ 3739949213aSStephan Aßmus out_space = space; 3749949213aSStephan Aßmus break; 3759949213aSStephan Aßmus } 3769949213aSStephan Aßmus } 3779949213aSStephan Aßmus else { 3789949213aSStephan Aßmus out_space = g_settings.out_space; 3799949213aSStephan Aßmus } 3809949213aSStephan Aßmus } 3819949213aSStephan Aßmus out_rowbytes = calc_rowbytes(out_space, width); 3829949213aSStephan Aßmus } 3839949213aSStephan Aßmus g_settings_lock.Unlock(); 3849949213aSStephan Aßmus /* Write file header */ 3859949213aSStephan Aßmus if (outType == PPM_TYPE) { 3869949213aSStephan Aßmus dprintf(("PPMTranslator: write PPM\n")); 3879949213aSStephan Aßmus /* begin PPM header */ 3889949213aSStephan Aßmus const char * magic; 3899949213aSStephan Aßmus if (out_ascii) 3909949213aSStephan Aßmus magic = "P3\n"; 3919949213aSStephan Aßmus else 3929949213aSStephan Aßmus magic = "P6\n"; 3939949213aSStephan Aßmus err = outDestination->Write(magic, strlen(magic)); 3949949213aSStephan Aßmus if (err == (long)strlen(magic)) err = 0; 3959949213aSStephan Aßmus //comment = NULL; 3969949213aSStephan Aßmus const char* fsComment; 3979949213aSStephan Aßmus #if defined(_PR3_COMPATIBLE_) /* R4 headers? */ 3989949213aSStephan Aßmus if ((ioExtension != NULL) && !ioExtension->FindString(B_TRANSLATOR_EXT_COMMENT, &fsComment)) { 3999949213aSStephan Aßmus #else 4009949213aSStephan Aßmus if ((ioExtension != NULL) && !ioExtension->FindString("/comment", &fsComment)) { 4019949213aSStephan Aßmus #endif 4029949213aSStephan Aßmus err = write_comment(fsComment, outDestination); 4039949213aSStephan Aßmus } 4049949213aSStephan Aßmus if (err == B_OK) { 4059949213aSStephan Aßmus char data[40]; 4069949213aSStephan Aßmus sprintf(data, "%d %d %d\n", width, height, max); 4079949213aSStephan Aßmus err = outDestination->Write(data, strlen(data)); 4089949213aSStephan Aßmus if (err == (long)strlen(data)) err = 0; 4099949213aSStephan Aßmus } 4109949213aSStephan Aßmus /* header done */ 4119949213aSStephan Aßmus } 4129949213aSStephan Aßmus else { 4139949213aSStephan Aßmus dprintf(("PPMTranslator: write B_TRANSLATOR_BITMAP\n")); 4149949213aSStephan Aßmus /* B_TRANSLATOR_BITMAP header */ 4159949213aSStephan Aßmus TranslatorBitmap hdr; 4169949213aSStephan Aßmus hdr.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); 4179949213aSStephan Aßmus hdr.bounds.left = B_HOST_TO_BENDIAN_FLOAT(0); 4189949213aSStephan Aßmus hdr.bounds.top = B_HOST_TO_BENDIAN_FLOAT(0); 4199949213aSStephan Aßmus hdr.bounds.right = B_HOST_TO_BENDIAN_FLOAT(width-1); 4209949213aSStephan Aßmus hdr.bounds.bottom = B_HOST_TO_BENDIAN_FLOAT(height-1); 4219949213aSStephan Aßmus hdr.rowBytes = B_HOST_TO_BENDIAN_INT32(out_rowbytes); 4229949213aSStephan Aßmus hdr.colors = (color_space)B_HOST_TO_BENDIAN_INT32(out_space); 4239949213aSStephan Aßmus hdr.dataSize = B_HOST_TO_BENDIAN_INT32(out_rowbytes*height); 4249949213aSStephan Aßmus dprintf(("rowBytes is %d, width %d, out_space %x, space %x\n", out_rowbytes, width, out_space, space)); 4259949213aSStephan Aßmus err = outDestination->Write(&hdr, sizeof(hdr)); 4261a7bcf69SOliver Tappe dprintf(("PPMTranslator: Write() returns %" B_PRIx32 "\n", err)); 4279949213aSStephan Aßmus #if DEBUG 4289949213aSStephan Aßmus { 4299949213aSStephan Aßmus BBitmap * map = new BBitmap(BRect(0,0,width-1,height-1), out_space); 4301a7bcf69SOliver Tappe printf("map rb = %" B_PRId32 "\n", map->BytesPerRow()); 4319949213aSStephan Aßmus delete map; 4329949213aSStephan Aßmus } 4339949213aSStephan Aßmus #endif 4349949213aSStephan Aßmus if (err == sizeof(hdr)) err = 0; 4359949213aSStephan Aßmus /* header done */ 4369949213aSStephan Aßmus } 4379949213aSStephan Aßmus if (err != B_OK) { 4389949213aSStephan Aßmus return err > 0 ? B_IO_ERROR : err; 4399949213aSStephan Aßmus } 4409949213aSStephan Aßmus /* Write data. Luckily, PPM and B_TRANSLATOR_BITMAP both scan from left to right, top to bottom. */ 4419949213aSStephan Aßmus return copy_data(inSource, outDestination, rowbytes, out_rowbytes, height, max, ascii, out_ascii, space, out_space); 4429949213aSStephan Aßmus } 4439949213aSStephan Aßmus 4449949213aSStephan Aßmus 4459949213aSStephan Aßmus class PPMView : 4469949213aSStephan Aßmus public BView 4479949213aSStephan Aßmus { 4489949213aSStephan Aßmus public: 4499949213aSStephan Aßmus PPMView( 4509949213aSStephan Aßmus const char * name, 4519949213aSStephan Aßmus uint32 flags) : 452a76f629eSRyan Leavengood BView(name, flags) 4539949213aSStephan Aßmus { 454*f0650dc9Slooncraz SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 455a76f629eSRyan Leavengood 456037bc75eSJanus fTitle = new BStringView("title", 457e8eb40f7SHumdinger B_TRANSLATE("PPM image translator")); 458037bc75eSJanus fTitle->SetFont(be_bold_font); 459a76f629eSRyan Leavengood 460a76f629eSRyan Leavengood char detail[100]; 461a76f629eSRyan Leavengood int ver = static_cast<int>(translatorVersion); 462037bc75eSJanus sprintf(detail, B_TRANSLATE("Version %d.%d.%d, %s"), ver >> 8, 46370d59669SSiarzhuk Zharski ((ver >> 4) & 0xf), 464a76f629eSRyan Leavengood (ver & 0xf), __DATE__); 465037bc75eSJanus fDetail = new BStringView("detail", detail); 466a76f629eSRyan Leavengood 467037bc75eSJanus fBasedOn = new BStringView("basedOn", 46870d59669SSiarzhuk Zharski B_TRANSLATE("Based on PPMTranslator sample code")); 469a76f629eSRyan Leavengood 470037bc75eSJanus fCopyright = new BStringView("copyright", 47170d59669SSiarzhuk Zharski B_TRANSLATE("Sample code copyright 1999, Be Incorporated")); 472a76f629eSRyan Leavengood 473037bc75eSJanus fMenu = new BPopUpMenu("Color Space"); 474037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("None"), 47570d59669SSiarzhuk Zharski CSMessage(B_NO_COLOR_SPACE))); 476037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("RGB 8:8:8 32 bits"), 47770d59669SSiarzhuk Zharski CSMessage(B_RGB32))); 478037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("RGBA 8:8:8:8 32 " 47970d59669SSiarzhuk Zharski "bits"), CSMessage(B_RGBA32))); 480037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("RGB 5:5:5 16 bits"), 48170d59669SSiarzhuk Zharski CSMessage(B_RGB15))); 482037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("RGBA 5:5:5:1 16 " 48370d59669SSiarzhuk Zharski "bits"), CSMessage(B_RGBA15))); 484037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("RGB 5:6:5 16 bits"), 48570d59669SSiarzhuk Zharski CSMessage(B_RGB16))); 486037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("System palette 8 " 48770d59669SSiarzhuk Zharski "bits"), CSMessage(B_CMAP8))); 488037bc75eSJanus fMenu->AddSeparatorItem(); 489037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("Grayscale 8 bits"), 49070d59669SSiarzhuk Zharski CSMessage(B_GRAY8))); 491037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("Bitmap 1 bit"), 49270d59669SSiarzhuk Zharski CSMessage(B_GRAY1))); 493037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("CMY 8:8:8 32 bits"), 49470d59669SSiarzhuk Zharski CSMessage(B_CMY32))); 495037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("CMYA 8:8:8:8 32 " 49670d59669SSiarzhuk Zharski "bits"), CSMessage(B_CMYA32))); 497037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("CMYK 8:8:8:8 32 " 49870d59669SSiarzhuk Zharski "bits"), CSMessage(B_CMYK32))); 499037bc75eSJanus fMenu->AddSeparatorItem(); 500037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("RGB 8:8:8 32 bits " 50170d59669SSiarzhuk Zharski "big-endian"), CSMessage(B_RGB32_BIG))); 502037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("RGBA 8:8:8:8 32 " 50370d59669SSiarzhuk Zharski "bits big-endian"), CSMessage(B_RGBA32_BIG))); 504037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("RGB 5:5:5 16 bits " 50570d59669SSiarzhuk Zharski "big-endian"), CSMessage(B_RGB15_BIG))); 506037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("RGBA 5:5:5:1 16 " 50770d59669SSiarzhuk Zharski "bits big-endian"), CSMessage(B_RGBA15_BIG))); 508037bc75eSJanus fMenu->AddItem(new BMenuItem(B_TRANSLATE("RGB 5:6:5 16 bits " 50970d59669SSiarzhuk Zharski "big-endian"), CSMessage(B_RGB16))); 5103292b902SHumdinger fField = new BMenuField(B_TRANSLATE("Input color space:"), 511037bc75eSJanus fMenu); 512037bc75eSJanus fField->SetViewColor(ViewColor()); 5139949213aSStephan Aßmus SelectColorSpace(g_settings.out_space); 5149949213aSStephan Aßmus BMessage * msg = new BMessage(CHANGE_ASCII); 515037bc75eSJanus fAscii = new BCheckBox(B_TRANSLATE("Write ASCII"), msg); 516a76f629eSRyan Leavengood if (g_settings.write_ascii) 517037bc75eSJanus fAscii->SetValue(1); 518037bc75eSJanus fAscii->SetViewColor(ViewColor()); 519a76f629eSRyan Leavengood 520a76f629eSRyan Leavengood // Build the layout 521037bc75eSJanus BLayoutBuilder::Group<>(this, B_VERTICAL, 0) 522037bc75eSJanus .SetInsets(B_USE_DEFAULT_SPACING) 523037bc75eSJanus .Add(fTitle) 524037bc75eSJanus .Add(fDetail) 525a76f629eSRyan Leavengood .AddGlue() 5267bfb4a1eSJanus .AddGroup(B_HORIZONTAL) 5277bfb4a1eSJanus .Add(fField) 5287bfb4a1eSJanus .AddGlue() 5297d48219bSHannah Boneß .End() 5307bfb4a1eSJanus .Add(fAscii) 531037bc75eSJanus .AddGlue() 532037bc75eSJanus .Add(fBasedOn) 533037bc75eSJanus .Add(fCopyright); 534a76f629eSRyan Leavengood 535a76f629eSRyan Leavengood BFont font; 536a76f629eSRyan Leavengood GetFont(&font); 5377bfb4a1eSJanus SetExplicitPreferredSize(BSize((font.Size() * 350)/12, 5387bfb4a1eSJanus (font.Size() * 200)/12)); 5399949213aSStephan Aßmus } 5409949213aSStephan Aßmus ~PPMView() 5419949213aSStephan Aßmus { 5429949213aSStephan Aßmus /* nothing here */ 5439949213aSStephan Aßmus } 5449949213aSStephan Aßmus 5459949213aSStephan Aßmus enum { 5469949213aSStephan Aßmus SET_COLOR_SPACE = 'ppm=', 5479949213aSStephan Aßmus CHANGE_ASCII 5489949213aSStephan Aßmus }; 5499949213aSStephan Aßmus 5509949213aSStephan Aßmus virtual void MessageReceived( 5519949213aSStephan Aßmus BMessage * message) 5529949213aSStephan Aßmus { 5539949213aSStephan Aßmus if (message->what == SET_COLOR_SPACE) { 5549949213aSStephan Aßmus SetSettings(message); 5559949213aSStephan Aßmus } 5569949213aSStephan Aßmus else if (message->what == CHANGE_ASCII) { 5579949213aSStephan Aßmus BMessage msg; 558037bc75eSJanus msg.AddBool("ppm /ascii", fAscii->Value()); 5599949213aSStephan Aßmus SetSettings(&msg); 5609949213aSStephan Aßmus } 5619949213aSStephan Aßmus else { 5629949213aSStephan Aßmus BView::MessageReceived(message); 5639949213aSStephan Aßmus } 5649949213aSStephan Aßmus } 5659949213aSStephan Aßmus virtual void AllAttached() 5669949213aSStephan Aßmus { 5679949213aSStephan Aßmus BView::AllAttached(); 5689949213aSStephan Aßmus BMessenger msgr(this); 5699949213aSStephan Aßmus /* Tell all menu items we're the man. */ 570037bc75eSJanus for (int ix=0; ix<fMenu->CountItems(); ix++) { 571037bc75eSJanus BMenuItem * i = fMenu->ItemAt(ix); 5729949213aSStephan Aßmus if (i) { 5739949213aSStephan Aßmus i->SetTarget(msgr); 5749949213aSStephan Aßmus } 5759949213aSStephan Aßmus } 576037bc75eSJanus fAscii->SetTarget(msgr); 5779949213aSStephan Aßmus } 5789949213aSStephan Aßmus 5799949213aSStephan Aßmus void SetSettings( 5809949213aSStephan Aßmus BMessage * message) 5819949213aSStephan Aßmus { 5829949213aSStephan Aßmus g_settings_lock.Lock(); 5839949213aSStephan Aßmus color_space space; 5849949213aSStephan Aßmus if (!message->FindInt32("space", (int32*)&space)) { 5859949213aSStephan Aßmus g_settings.out_space = space; 5869949213aSStephan Aßmus SelectColorSpace(space); 5879949213aSStephan Aßmus g_settings.settings_touched = true; 5889949213aSStephan Aßmus } 5899949213aSStephan Aßmus bool ascii; 5909949213aSStephan Aßmus if (!message->FindBool("ppm /ascii", &ascii)) { 5919949213aSStephan Aßmus g_settings.write_ascii = ascii; 5929949213aSStephan Aßmus g_settings.settings_touched = true; 5939949213aSStephan Aßmus } 5949949213aSStephan Aßmus g_settings_lock.Unlock(); 5959949213aSStephan Aßmus } 5969949213aSStephan Aßmus 5979949213aSStephan Aßmus private: 598037bc75eSJanus BStringView * fTitle; 599037bc75eSJanus BStringView * fDetail; 600037bc75eSJanus BStringView * fBasedOn; 601037bc75eSJanus BStringView * fCopyright; 602037bc75eSJanus BPopUpMenu * fMenu; 603037bc75eSJanus BMenuField * fField; 604037bc75eSJanus BCheckBox * fAscii; 6059949213aSStephan Aßmus 6069949213aSStephan Aßmus BMessage * CSMessage( 6079949213aSStephan Aßmus color_space space) 6089949213aSStephan Aßmus { 6099949213aSStephan Aßmus BMessage * ret = new BMessage(SET_COLOR_SPACE); 6109949213aSStephan Aßmus ret->AddInt32("space", space); 6119949213aSStephan Aßmus return ret; 6129949213aSStephan Aßmus } 6139949213aSStephan Aßmus 6149949213aSStephan Aßmus void SelectColorSpace( 6159949213aSStephan Aßmus color_space space) 6169949213aSStephan Aßmus { 617037bc75eSJanus for (int ix=0; ix<fMenu->CountItems(); ix++) { 6189949213aSStephan Aßmus int32 s; 619037bc75eSJanus BMenuItem * i = fMenu->ItemAt(ix); 6209949213aSStephan Aßmus if (i) { 6219949213aSStephan Aßmus BMessage * m = i->Message(); 6229949213aSStephan Aßmus if (m && !m->FindInt32("space", &s) && (s == space)) { 623037bc75eSJanus fMenu->Superitem()->SetLabel(i->Label()); 6249949213aSStephan Aßmus break; 6259949213aSStephan Aßmus } 6269949213aSStephan Aßmus } 6279949213aSStephan Aßmus } 6289949213aSStephan Aßmus } 6299949213aSStephan Aßmus }; 6309949213aSStephan Aßmus 6319949213aSStephan Aßmus 6329949213aSStephan Aßmus /* The view will get resized to what the parent thinks is */ 6339949213aSStephan Aßmus /* reasonable. However, it will still receive MouseDowns etc. */ 6349949213aSStephan Aßmus /* Your view should change settings in the translator immediately, */ 6359949213aSStephan Aßmus /* taking care not to change parameters for a translation that is */ 6369949213aSStephan Aßmus /* currently running. Typically, you'll have a global struct for */ 6379949213aSStephan Aßmus /* settings that is atomically copied into the translator function */ 6389949213aSStephan Aßmus /* as a local when translation starts. */ 6399949213aSStephan Aßmus /* Store your settings wherever you feel like it. */ 6409949213aSStephan Aßmus 6419949213aSStephan Aßmus status_t 6429949213aSStephan Aßmus MakeConfig( /* optional */ 6439949213aSStephan Aßmus BMessage * ioExtension, /* can be NULL */ 6449949213aSStephan Aßmus BView * * outView, 6459949213aSStephan Aßmus BRect * outExtent) 6469949213aSStephan Aßmus { 64770d59669SSiarzhuk Zharski PPMView * v = new PPMView(B_TRANSLATE("PPMTranslator Settings"), 64870d59669SSiarzhuk Zharski B_WILL_DRAW); 6499949213aSStephan Aßmus *outView = v; 650a76f629eSRyan Leavengood v->ResizeTo(v->ExplicitPreferredSize());; 6519949213aSStephan Aßmus *outExtent = v->Bounds(); 6529949213aSStephan Aßmus if (ioExtension) { 6539949213aSStephan Aßmus v->SetSettings(ioExtension); 6549949213aSStephan Aßmus } 6559949213aSStephan Aßmus return B_OK; 6569949213aSStephan Aßmus } 6579949213aSStephan Aßmus 6589949213aSStephan Aßmus 6599949213aSStephan Aßmus /* Copy your current settings to a BMessage that may be passed */ 6609949213aSStephan Aßmus /* to BTranslators::Translate at some later time when the user wants to */ 6619949213aSStephan Aßmus /* use whatever settings you're using right now. */ 6629949213aSStephan Aßmus 6639949213aSStephan Aßmus status_t 6649949213aSStephan Aßmus GetConfigMessage( /* optional */ 6659949213aSStephan Aßmus BMessage * ioExtension) 6669949213aSStephan Aßmus { 6679949213aSStephan Aßmus status_t err = B_OK; 6689949213aSStephan Aßmus #if defined(_PR3_COMPATIBLE_) 6699949213aSStephan Aßmus const char * name = B_TRANSLATOR_EXT_BITMAP_COLOR_SPACE; 6709949213aSStephan Aßmus #else 67170d59669SSiarzhuk Zharski const char * name = B_TRANSLATE_MARK("bits/space"); 6729949213aSStephan Aßmus #endif 6739949213aSStephan Aßmus g_settings_lock.Lock(); 6749949213aSStephan Aßmus (void)ioExtension->RemoveName(name); 6759949213aSStephan Aßmus err = ioExtension->AddInt32(name, g_settings.out_space); 6769949213aSStephan Aßmus g_settings_lock.Unlock(); 6779949213aSStephan Aßmus return err; 6789949213aSStephan Aßmus } 6799949213aSStephan Aßmus 6809949213aSStephan Aßmus 6819949213aSStephan Aßmus 6829949213aSStephan Aßmus 6839949213aSStephan Aßmus 6849949213aSStephan Aßmus status_t 6859949213aSStephan Aßmus read_ppm_header( 6869949213aSStephan Aßmus BDataIO * inSource, 6879949213aSStephan Aßmus int * width, 6889949213aSStephan Aßmus int * rowbytes, 6899949213aSStephan Aßmus int * height, 6909949213aSStephan Aßmus int * max, 6919949213aSStephan Aßmus bool * ascii, 6929949213aSStephan Aßmus color_space * space, 6939949213aSStephan Aßmus bool * is_ppm, 6949949213aSStephan Aßmus char ** comment) 6959949213aSStephan Aßmus { 6969949213aSStephan Aßmus /* check for PPM magic number */ 6979949213aSStephan Aßmus char ch[2]; 6989949213aSStephan Aßmus if (inSource->Read(ch, 2) != 2) { 6999949213aSStephan Aßmus return B_NO_TRANSLATOR; 7009949213aSStephan Aßmus } 7019949213aSStephan Aßmus /* look for magic number */ 7029949213aSStephan Aßmus if (ch[0] != 'P') { 7039949213aSStephan Aßmus /* B_TRANSLATOR_BITMAP magic? */ 7049949213aSStephan Aßmus if (ch[0] == 'b' && ch[1] == 'i') { 7059949213aSStephan Aßmus *is_ppm = false; 7069949213aSStephan Aßmus return read_bits_header(inSource, 2, width, rowbytes, height, max, ascii, space); 7079949213aSStephan Aßmus } 7089949213aSStephan Aßmus return B_NO_TRANSLATOR; 7099949213aSStephan Aßmus } 7109949213aSStephan Aßmus *is_ppm = true; 7119949213aSStephan Aßmus if (ch[1] == '6') { 7129949213aSStephan Aßmus *ascii = false; 7139949213aSStephan Aßmus } 7149949213aSStephan Aßmus else if (ch[1] == '3') { 7159949213aSStephan Aßmus *ascii = true; 7169949213aSStephan Aßmus } 7179949213aSStephan Aßmus else { 7189949213aSStephan Aßmus return B_NO_TRANSLATOR; 7199949213aSStephan Aßmus } 7209949213aSStephan Aßmus // status_t err = B_NO_TRANSLATOR; 7219949213aSStephan Aßmus enum scan_state { 7229949213aSStephan Aßmus scan_width, 7239949213aSStephan Aßmus scan_height, 7249949213aSStephan Aßmus scan_max, 7259949213aSStephan Aßmus scan_white 7269949213aSStephan Aßmus } state = scan_width; 7279949213aSStephan Aßmus int * scan = NULL; 7289949213aSStephan Aßmus bool in_comment = false; 7299949213aSStephan Aßmus *space = B_RGB24_BIG; 7309949213aSStephan Aßmus /* The description of PPM is slightly ambiguous as far as comments */ 7319949213aSStephan Aßmus /* go. We choose to allow comments anywhere, in the spirit of laxness. */ 7329949213aSStephan Aßmus /* See http://www.dcs.ed.ac.uk/~mxr/gfx/2d/PPM.txt */ 7339949213aSStephan Aßmus int comlen = 0; 7349949213aSStephan Aßmus int comptr = 0; 7359949213aSStephan Aßmus while (inSource->Read(ch, 1) == 1) { 7369949213aSStephan Aßmus if (in_comment && (ch[0] != 10) && (ch[0] != 13)) { 7379949213aSStephan Aßmus if (comment) { /* collect comment(s) into comment string */ 7389949213aSStephan Aßmus if (comptr >= comlen-1) { 7399949213aSStephan Aßmus char * n = (char *)realloc(*comment, comlen+100); 7409949213aSStephan Aßmus if (!n) { 7419949213aSStephan Aßmus free(*comment); 7429949213aSStephan Aßmus *comment = NULL; 7439949213aSStephan Aßmus } 7449949213aSStephan Aßmus *comment = n; 7459949213aSStephan Aßmus comlen += 100; 7469949213aSStephan Aßmus } 7479949213aSStephan Aßmus (*comment)[comptr++] = ch[0]; 7489949213aSStephan Aßmus (*comment)[comptr] = 0; 7499949213aSStephan Aßmus } 7509949213aSStephan Aßmus continue; 7519949213aSStephan Aßmus } 7529949213aSStephan Aßmus in_comment = false; 7539949213aSStephan Aßmus if (ch[0] == '#') { 7549949213aSStephan Aßmus in_comment = true; 7559949213aSStephan Aßmus continue; 7569949213aSStephan Aßmus } 7579949213aSStephan Aßmus /* once we're done with whitespace after max, we're done with header */ 7589949213aSStephan Aßmus if (isdigit(ch[0])) { 7599949213aSStephan Aßmus if (!scan) { /* first digit for this value */ 7609949213aSStephan Aßmus switch(state) { 7619949213aSStephan Aßmus case scan_width: 7629949213aSStephan Aßmus scan = width; 7639949213aSStephan Aßmus break; 7649949213aSStephan Aßmus case scan_height: 7659949213aSStephan Aßmus *rowbytes = *width*3; 7669949213aSStephan Aßmus scan = height; 7679949213aSStephan Aßmus break; 7689949213aSStephan Aßmus case scan_max: 7699949213aSStephan Aßmus scan = max; 7709949213aSStephan Aßmus break; 7719949213aSStephan Aßmus default: 7729949213aSStephan Aßmus return B_OK; /* done with header, all OK */ 7739949213aSStephan Aßmus } 7749949213aSStephan Aßmus *scan = 0; 7759949213aSStephan Aßmus } 7769949213aSStephan Aßmus *scan = (*scan)*10 + (ch[0]-'0'); 7779949213aSStephan Aßmus } 7789949213aSStephan Aßmus else if (isspace(ch[0])) { 7799949213aSStephan Aßmus if (scan) { /* are we done with one value? */ 7809949213aSStephan Aßmus scan = NULL; 7819949213aSStephan Aßmus state = (enum scan_state)(state+1); 7829949213aSStephan Aßmus } 7839949213aSStephan Aßmus if (state == scan_white) { /* we only ever read one whitespace, since we skip space */ 7849949213aSStephan Aßmus return B_OK; /* when reading ASCII, and there is a single whitespace after max in raw mode */ 7859949213aSStephan Aßmus } 7869949213aSStephan Aßmus } 7879949213aSStephan Aßmus else { 7889949213aSStephan Aßmus if (state != scan_white) { 7899949213aSStephan Aßmus return B_NO_TRANSLATOR; 7909949213aSStephan Aßmus } 7919949213aSStephan Aßmus return B_OK; /* header done */ 7929949213aSStephan Aßmus } 7939949213aSStephan Aßmus } 7949949213aSStephan Aßmus return B_NO_TRANSLATOR; 7959949213aSStephan Aßmus } 7969949213aSStephan Aßmus 7979949213aSStephan Aßmus 7989949213aSStephan Aßmus 7999949213aSStephan Aßmus status_t 8009949213aSStephan Aßmus read_bits_header( 8019949213aSStephan Aßmus BDataIO * io, 8029949213aSStephan Aßmus int skipped, 8039949213aSStephan Aßmus int * width, 8049949213aSStephan Aßmus int * rowbytes, 8059949213aSStephan Aßmus int * height, 8069949213aSStephan Aßmus int * max, 8079949213aSStephan Aßmus bool * ascii, 8089949213aSStephan Aßmus color_space * space) 8099949213aSStephan Aßmus { 8109949213aSStephan Aßmus /* read the rest of a possible B_TRANSLATOR_BITMAP header */ 8119949213aSStephan Aßmus if (skipped < 0 || skipped > 4) return B_NO_TRANSLATOR; 8129949213aSStephan Aßmus int rd = sizeof(TranslatorBitmap)-skipped; 8139949213aSStephan Aßmus TranslatorBitmap hdr; 8149949213aSStephan Aßmus /* pre-initialize magic because we might have skipped part of it already */ 8159949213aSStephan Aßmus hdr.magic = B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP); 8169949213aSStephan Aßmus char * ptr = (char *)&hdr; 8179949213aSStephan Aßmus if (io->Read(ptr+skipped, rd) != rd) { 8189949213aSStephan Aßmus return B_NO_TRANSLATOR; 8199949213aSStephan Aßmus } 8209949213aSStephan Aßmus /* swap header values */ 8219949213aSStephan Aßmus hdr.magic = B_BENDIAN_TO_HOST_INT32(hdr.magic); 8229949213aSStephan Aßmus hdr.bounds.left = B_BENDIAN_TO_HOST_FLOAT(hdr.bounds.left); 8239949213aSStephan Aßmus hdr.bounds.right = B_BENDIAN_TO_HOST_FLOAT(hdr.bounds.right); 8249949213aSStephan Aßmus hdr.bounds.top = B_BENDIAN_TO_HOST_FLOAT(hdr.bounds.top); 8259949213aSStephan Aßmus hdr.bounds.bottom = B_BENDIAN_TO_HOST_FLOAT(hdr.bounds.bottom); 8269949213aSStephan Aßmus hdr.rowBytes = B_BENDIAN_TO_HOST_INT32(hdr.rowBytes); 8279949213aSStephan Aßmus hdr.colors = (color_space)B_BENDIAN_TO_HOST_INT32(hdr.colors); 8289949213aSStephan Aßmus hdr.dataSize = B_BENDIAN_TO_HOST_INT32(hdr.dataSize); 8299949213aSStephan Aßmus /* sanity checking */ 8309949213aSStephan Aßmus if (hdr.magic != B_TRANSLATOR_BITMAP) { 8319949213aSStephan Aßmus return B_NO_TRANSLATOR; 8329949213aSStephan Aßmus } 8339949213aSStephan Aßmus if (hdr.colors & 0xffff0000) { /* according to <GraphicsDefs.h> this is a reasonable check. */ 8349949213aSStephan Aßmus return B_NO_TRANSLATOR; 8359949213aSStephan Aßmus } 8369949213aSStephan Aßmus if (hdr.rowBytes * (hdr.bounds.Height()+1) > hdr.dataSize) { 8379949213aSStephan Aßmus return B_NO_TRANSLATOR; 8389949213aSStephan Aßmus } 8399949213aSStephan Aßmus /* return information about the data in the stream */ 8409949213aSStephan Aßmus *width = (int)hdr.bounds.Width()+1; 8419949213aSStephan Aßmus *rowbytes = hdr.rowBytes; 8429949213aSStephan Aßmus *height = (int)hdr.bounds.Height()+1; 8439949213aSStephan Aßmus *max = 255; 8449949213aSStephan Aßmus *ascii = false; 8459949213aSStephan Aßmus *space = hdr.colors; 8469949213aSStephan Aßmus return B_OK; 8479949213aSStephan Aßmus } 8489949213aSStephan Aßmus 8499949213aSStephan Aßmus 8509949213aSStephan Aßmus /* String may contain newlines, after which we need to insert extra hash signs. */ 8519949213aSStephan Aßmus status_t 8529949213aSStephan Aßmus write_comment( 8539949213aSStephan Aßmus const char * str, 8549949213aSStephan Aßmus BDataIO * io) 8559949213aSStephan Aßmus { 8569949213aSStephan Aßmus const char * end = str+strlen(str); 8579949213aSStephan Aßmus const char * ptr = str; 8589949213aSStephan Aßmus status_t err = B_OK; 8599949213aSStephan Aßmus /* write each line as it's found */ 8609949213aSStephan Aßmus while ((ptr < end) && !err) { 8619949213aSStephan Aßmus if ((*ptr == 10) || (*ptr == 13)) { 8629949213aSStephan Aßmus err = io->Write("# ", 2); 8639949213aSStephan Aßmus if (err == 2) { 8649949213aSStephan Aßmus err = io->Write(str, ptr-str); 8659949213aSStephan Aßmus if (err == ptr-str) { 8669949213aSStephan Aßmus if (io->Write("\n", 1) == 1) { 8679949213aSStephan Aßmus err = 0; 8689949213aSStephan Aßmus } 8699949213aSStephan Aßmus } 8709949213aSStephan Aßmus } 8719949213aSStephan Aßmus str = ptr+1; 8729949213aSStephan Aßmus } 8739949213aSStephan Aßmus ptr++; 8749949213aSStephan Aßmus } 8759949213aSStephan Aßmus /* write the last data, if any, as a line */ 8769949213aSStephan Aßmus if (ptr > str) { 8779949213aSStephan Aßmus err = io->Write("# ", 2); 8789949213aSStephan Aßmus if (err == 2) { 8799949213aSStephan Aßmus err = io->Write(str, ptr-str); 8809949213aSStephan Aßmus if (err == ptr-str) { 8819949213aSStephan Aßmus if (io->Write("\n", 1) == 1) { 8829949213aSStephan Aßmus err = 0; 8839949213aSStephan Aßmus } 8849949213aSStephan Aßmus } 8859949213aSStephan Aßmus } 8869949213aSStephan Aßmus } 8879949213aSStephan Aßmus if (err > 0) { 8889949213aSStephan Aßmus err = B_IO_ERROR; 8899949213aSStephan Aßmus } 8909949213aSStephan Aßmus return err; 8919949213aSStephan Aßmus } 8929949213aSStephan Aßmus 8939949213aSStephan Aßmus 8949949213aSStephan Aßmus static status_t 8959949213aSStephan Aßmus read_ascii_line( 8969949213aSStephan Aßmus BDataIO * in, 8979949213aSStephan Aßmus int max, 8989949213aSStephan Aßmus unsigned char * data, 8999949213aSStephan Aßmus int rowbytes) 9009949213aSStephan Aßmus { 9019949213aSStephan Aßmus char ch; 9029949213aSStephan Aßmus status_t err; 9039949213aSStephan Aßmus // int nread = 0; 9049949213aSStephan Aßmus bool comment = false; 9059949213aSStephan Aßmus int val = 0; 9069949213aSStephan Aßmus bool dig = false; 9079949213aSStephan Aßmus while ((err = in->Read(&ch, 1)) == 1) { 9089949213aSStephan Aßmus if (comment) { 9099949213aSStephan Aßmus if ((ch == '\n') || (ch == '\r')) { 9109949213aSStephan Aßmus comment = false; 9119949213aSStephan Aßmus } 9129949213aSStephan Aßmus } 9139949213aSStephan Aßmus if (isdigit(ch)) { 9149949213aSStephan Aßmus dig = true; 9159949213aSStephan Aßmus val = val * 10 + (ch - '0'); 9169949213aSStephan Aßmus } 9179949213aSStephan Aßmus else { 9189949213aSStephan Aßmus if (dig) { 9199949213aSStephan Aßmus *(data++) = val*255/max; 9209949213aSStephan Aßmus val = 0; 9219949213aSStephan Aßmus rowbytes--; 9229949213aSStephan Aßmus dig = false; 9239949213aSStephan Aßmus } 9249949213aSStephan Aßmus if (ch == '#') { 9259949213aSStephan Aßmus comment = true; 9269949213aSStephan Aßmus continue; 9279949213aSStephan Aßmus } 9289949213aSStephan Aßmus } 9299949213aSStephan Aßmus if (rowbytes < 1) { 9309949213aSStephan Aßmus break; 9319949213aSStephan Aßmus } 9329949213aSStephan Aßmus } 9339949213aSStephan Aßmus if (dig) { 9349949213aSStephan Aßmus *(data++) = val*255/max; 9359949213aSStephan Aßmus val = 0; 9369949213aSStephan Aßmus rowbytes--; 9379949213aSStephan Aßmus dig = false; 9389949213aSStephan Aßmus } 9399949213aSStephan Aßmus if (rowbytes < 1) { 9409949213aSStephan Aßmus return B_OK; 9419949213aSStephan Aßmus } 9429949213aSStephan Aßmus return B_IO_ERROR; 9439949213aSStephan Aßmus } 9449949213aSStephan Aßmus 9459949213aSStephan Aßmus 9469949213aSStephan Aßmus static status_t 9479949213aSStephan Aßmus write_ascii_line( 9489949213aSStephan Aßmus BDataIO * out, 9499949213aSStephan Aßmus unsigned char * data, 9509949213aSStephan Aßmus int rowbytes) 9519949213aSStephan Aßmus { 9529949213aSStephan Aßmus char buffer[20]; 9539949213aSStephan Aßmus int linelen = 0; 9549949213aSStephan Aßmus while (rowbytes > 2) { 9559949213aSStephan Aßmus sprintf(buffer, "%d %d %d ", data[0], data[1], data[2]); 9569949213aSStephan Aßmus rowbytes -= 3; 9579949213aSStephan Aßmus int l = strlen(buffer); 9589949213aSStephan Aßmus if (l + linelen > 70) { 9599949213aSStephan Aßmus out->Write("\n", 1); 9609949213aSStephan Aßmus linelen = 0; 9619949213aSStephan Aßmus } 9629949213aSStephan Aßmus if (out->Write(buffer, l) != l) { 9639949213aSStephan Aßmus return B_IO_ERROR; 9649949213aSStephan Aßmus } 9659949213aSStephan Aßmus linelen += l; 9669949213aSStephan Aßmus data += 3; 9679949213aSStephan Aßmus } 9689949213aSStephan Aßmus out->Write("\n", 1); /* terminate each scanline */ 9699949213aSStephan Aßmus return B_OK; 9709949213aSStephan Aßmus } 9719949213aSStephan Aßmus 9729949213aSStephan Aßmus 9739949213aSStephan Aßmus static unsigned char * 9749949213aSStephan Aßmus make_scale_data( 9759949213aSStephan Aßmus int max) 9769949213aSStephan Aßmus { 9779949213aSStephan Aßmus unsigned char * ptr = (unsigned char *)malloc(max); 9789949213aSStephan Aßmus for (int ix=0; ix<max; ix++) { 9799949213aSStephan Aßmus ptr[ix] = ix*255/max; 9809949213aSStephan Aßmus } 9819949213aSStephan Aßmus return ptr; 9829949213aSStephan Aßmus } 9839949213aSStephan Aßmus 9849949213aSStephan Aßmus 9859949213aSStephan Aßmus static void 9869949213aSStephan Aßmus scale_data( 9879949213aSStephan Aßmus unsigned char * scale, 9889949213aSStephan Aßmus unsigned char * data, 9899949213aSStephan Aßmus int bytes) 9909949213aSStephan Aßmus { 9919949213aSStephan Aßmus for (int ix=0; ix<bytes; ix++) { 9929949213aSStephan Aßmus data[ix] = scale[data[ix]]; 9939949213aSStephan Aßmus } 9949949213aSStephan Aßmus } 9959949213aSStephan Aßmus 9969949213aSStephan Aßmus 9979949213aSStephan Aßmus status_t 9989949213aSStephan Aßmus copy_data( 9999949213aSStephan Aßmus BDataIO * in, 10009949213aSStephan Aßmus BDataIO * out, 10019949213aSStephan Aßmus int rowbytes, 10029949213aSStephan Aßmus int out_rowbytes, 10039949213aSStephan Aßmus int height, 10049949213aSStephan Aßmus int max, 10059949213aSStephan Aßmus bool in_ascii, 10069949213aSStephan Aßmus bool out_ascii, 10079949213aSStephan Aßmus color_space in_space, 10089949213aSStephan Aßmus color_space out_space) 10099949213aSStephan Aßmus { 10109949213aSStephan Aßmus dprintf(("copy_data(%x, %x, %x, %x, %x, %x)\n", rowbytes, out_rowbytes, height, max, in_space, out_space)); 10119949213aSStephan Aßmus /* We read/write one scanline at a time. */ 10129949213aSStephan Aßmus unsigned char * data = (unsigned char *)malloc(rowbytes); 10139949213aSStephan Aßmus unsigned char * out_data = (unsigned char *)malloc(out_rowbytes); 10149949213aSStephan Aßmus if (data == NULL || out_data == NULL) { 10159949213aSStephan Aßmus free(data); 10169949213aSStephan Aßmus free(out_data); 10179949213aSStephan Aßmus return B_NO_MEMORY; 10189949213aSStephan Aßmus } 10199949213aSStephan Aßmus unsigned char * scale = NULL; 10209949213aSStephan Aßmus if (max != 255) { 10219949213aSStephan Aßmus scale = make_scale_data(max); 10229949213aSStephan Aßmus } 10239949213aSStephan Aßmus status_t err = B_OK; 10249949213aSStephan Aßmus /* There is no data format conversion, so we can just copy data. */ 10259949213aSStephan Aßmus while ((height-- > 0) && !err) { 10269949213aSStephan Aßmus if (in_ascii) { 10279949213aSStephan Aßmus err = read_ascii_line(in, max, data, rowbytes); 10289949213aSStephan Aßmus } 10299949213aSStephan Aßmus else { 10309949213aSStephan Aßmus err = in->Read(data, rowbytes); 10319949213aSStephan Aßmus if (err == rowbytes) { 10329949213aSStephan Aßmus err = B_OK; 10339949213aSStephan Aßmus } 10349949213aSStephan Aßmus if (scale) { /* for reading PPM that is smaller than 8 bit */ 10359949213aSStephan Aßmus scale_data(scale, data, rowbytes); 10369949213aSStephan Aßmus } 10379949213aSStephan Aßmus } 10389949213aSStephan Aßmus if (err == B_OK) { 10399949213aSStephan Aßmus unsigned char * wbuf = data; 10409949213aSStephan Aßmus if (in_space != out_space) { 10419949213aSStephan Aßmus err = convert_space(in_space, out_space, data, rowbytes, out_data); 10429949213aSStephan Aßmus wbuf = out_data; 10439949213aSStephan Aßmus } 10449949213aSStephan Aßmus if (!err && out_ascii) { 10459949213aSStephan Aßmus err = write_ascii_line(out, wbuf, out_rowbytes); 10469949213aSStephan Aßmus } 10479949213aSStephan Aßmus else if (!err) { 10489949213aSStephan Aßmus err = out->Write(wbuf, out_rowbytes); 10499949213aSStephan Aßmus if (err == out_rowbytes) { 10509949213aSStephan Aßmus err = B_OK; 10519949213aSStephan Aßmus } 10529949213aSStephan Aßmus } 10539949213aSStephan Aßmus } 10549949213aSStephan Aßmus } 10559949213aSStephan Aßmus free(data); 10569949213aSStephan Aßmus free(out_data); 10579949213aSStephan Aßmus free(scale); 10589949213aSStephan Aßmus return err > 0 ? B_IO_ERROR : err; 10599949213aSStephan Aßmus } 10609949213aSStephan Aßmus 10619949213aSStephan Aßmus 1062