2 Copyright 1999, Be Incorporated. All Rights Reserved.
3 This file may be used under the terms of the Be Sample Code License.
6 /* Parse the ASCII and raw versions of PPM. */
7 /* Note that the parsing of ASCII is very inefficient, because BFile */
8 /* does not buffer data. We should wrap a buffering thing around */
9 /* the input or output when they are in ASCII mode. */
12 #include <ByteOrder.h>
15 #include <FindDirectory.h>
16 #include <LayoutBuilder.h>
18 #include <MenuField.h>
22 #include <PopUpMenu.h>
24 #include <StringView.h>
25 #include <TranslatorAddOn.h>
26 #include <TranslationKit.h>
34 #include "colorspace.h"
36 #undef B_TRANSLATION_CONTEXT
37 #define B_TRANSLATION_CONTEXT "PPMTranslator"
40 #define dprintf(x) printf x
46 #if !defined(_PR3_COMPATIBLE_) /* R4 headers? Else we need to define these constants. */
47 #define B_CMY24 ((color_space)0xC001) /* C[7:0] M[7:0] Y[7:0] No gray removal done */
48 #define B_CMY32 ((color_space)0xC002) /* C[7:0] M[7:0] Y[7:0] X[7:0] No gray removal done */
49 #define B_CMYA32 ((color_space)0xE002) /* C[7:0] M[7:0] Y[7:0] A[7:0] No gray removal done */
50 #define B_CMYK32 ((color_space)0xC003) /* C[7:0] M[7:0] Y[7:0] K[7:0] */
53 #define PPM_TRANSLATOR_VERSION 0x100
55 /* These three data items are exported by every translator. */
56 char translatorName
[] = "PPM images";
57 char translatorInfo
[] = "PPM image translator v1.0.0, " __DATE__
;
58 int32 translatorVersion
= PPM_TRANSLATOR_VERSION
;
59 // Revision: lowest 4 bits
61 // Major: highest 24 bits
63 /* Be reserves all codes with non-lowercase letters in them. */
64 /* Luckily, there is already a reserved code for PPM. If you */
65 /* make up your own for a new type, use lower-case letters. */
66 #define PPM_TYPE 'PPM '
69 /* These two data arrays are a really good idea to export from Translators, but not required. */
70 translation_format inputFormats
[] = {
71 { B_TRANSLATOR_BITMAP
, B_TRANSLATOR_BITMAP
, 0.4, 0.8, "image/x-be-bitmap", "Be Bitmap Format (PPMTranslator)" },
72 { PPM_TYPE
, B_TRANSLATOR_BITMAP
, 0.3, 0.8, "image/x-portable-pixmap", "PPM image" },
73 { 0, 0, 0, 0, "\0", "\0" }
74 }; /* optional (else Identify is always called) */
76 translation_format outputFormats
[] = {
77 { B_TRANSLATOR_BITMAP
, B_TRANSLATOR_BITMAP
, 0.4, 0.8, "image/x-be-bitmap", "Be Bitmap Format (PPMTranslator)" },
78 { PPM_TYPE
, B_TRANSLATOR_BITMAP
, 0.3, 0.8, "image/x-portable-pixmap", "PPM image" },
79 { 0, 0, 0, 0, "\0", "\0" }
80 }; /* optional (else Translate is called anyway) */
82 /* Translators that don't export outputFormats */
83 /* will not be considered by files looking for */
84 /* specific output formats. */
87 /* We keep our settings in a global struct, and wrap a lock around them. */
89 color_space out_space
;
92 bool settings_touched
;
94 static BLocker
g_settings_lock("PPM settings lock");
95 static ppm_settings g_settings
;
97 BPoint
get_window_origin();
98 void set_window_origin(BPoint pos
);
99 BPoint
get_window_origin()
102 g_settings_lock
.Lock();
103 ret
= g_settings
.window_pos
;
104 g_settings_lock
.Unlock();
108 void set_window_origin(BPoint pos
)
110 g_settings_lock
.Lock();
111 g_settings
.window_pos
= pos
;
112 g_settings
.settings_touched
= true;
113 g_settings_lock
.Unlock();
122 dprintf(("PPMTranslator: PrefsLoader()\n"));
124 g_settings
.out_space
= B_NO_COLOR_SPACE
;
125 g_settings
.window_pos
= B_ORIGIN
;
126 g_settings
.write_ascii
= false;
127 g_settings
.settings_touched
= false;
129 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
)) {
133 FILE * f
= fopen(path
.Path(), "r");
134 /* parse text settings file -- this should be a library... */
141 fgets(line
, 1024, f
);
145 /* remember: line ends with \n, so printf()s don't have to */
147 while (isspace(*ptr
)) {
150 if (*ptr
== '#' || !*ptr
) { /* comment or blank */
153 if (sscanf(ptr
, "%31[a-zA-Z_0-9] =", name
) != 1) {
154 syslog(LOG_ERR
, "unknown PPMTranslator "
155 "settings line: %s", line
);
158 if (!strcmp(name
, "color_space")) {
159 while (*ptr
!= '=') {
163 if (sscanf(ptr
, "%d",
164 (int*)&g_settings
.out_space
) != 1) {
165 syslog(LOG_ERR
, "illegal color space "
166 "in PPMTranslator settings: %s", ptr
);
169 else if (!strcmp(name
, "window_pos")) {
170 while (*ptr
!= '=') {
174 if (sscanf(ptr
, "%f,%f",
175 &g_settings
.window_pos
.x
,
176 &g_settings
.window_pos
.y
) != 2) {
177 syslog(LOG_ERR
, "illegal window position "
178 "in PPMTranslator settings: %s", ptr
);
181 else if (!strcmp(name
, "write_ascii")) {
182 while (*ptr
!= '=') {
186 int ascii
= g_settings
.write_ascii
;
187 if (sscanf(ptr
, "%d", &ascii
) != 1) {
188 syslog(LOG_ERR
, "illegal write_ascii value "
189 "in PPMTranslator settings: %s", ptr
);
192 g_settings
.write_ascii
= ascii
;
197 "unknown PPMTranslator setting: %s", line
);
206 /* No need writing settings if there aren't any */
207 if (g_settings
.settings_touched
) {
209 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
)) {
212 path
.Append("PPMTranslator_Settings");
213 FILE * f
= fopen(path
.Path(), "w");
215 fprintf(f
, "# PPMTranslator settings version %d.%d.%d\n",
216 static_cast<int>(translatorVersion
>> 8),
217 static_cast<int>((translatorVersion
>> 4) & 0xf),
218 static_cast<int>(translatorVersion
& 0xf));
219 fprintf(f
, "color_space = %d\n", g_settings
.out_space
);
220 fprintf(f
, "window_pos = %g,%g\n", g_settings
.window_pos
.x
,
221 g_settings
.window_pos
.y
);
222 fprintf(f
, "write_ascii = %d\n", g_settings
.write_ascii
? 1 : 0);
229 PrefsLoader
g_prefs_loader("PPMTranslator_Settings");
231 /* Some prototypes for functions we use. */
232 status_t
read_ppm_header(BDataIO
* io
, int * width
, int * rowbytes
, int * height
,
233 int * max
, bool * ascii
, color_space
* space
, bool * is_ppm
, char ** comment
);
234 status_t
read_bits_header(BDataIO
* io
, int skipped
, int * width
, int * rowbytes
,
235 int * height
, int * max
, bool * ascii
, color_space
* space
);
236 status_t
write_comment(const char * str
, BDataIO
* io
);
237 status_t
copy_data(BDataIO
* in
, BDataIO
* out
, int rowbytes
, int out_rowbytes
,
238 int height
, int max
, bool in_ascii
, bool out_ascii
, color_space in_space
,
239 color_space out_space
);
241 /* Return B_NO_TRANSLATOR if not handling this data. */
242 /* Even if inputFormats exists, may be called for data without hints */
243 /* If outType is not 0, must be able to export in wanted format */
246 Identify( /* required */
247 BPositionIO
* inSource
,
248 const translation_format
* inFormat
, /* can beNULL */
249 BMessage
* ioExtension
, /* can be NULL */
250 translator_info
* outInfo
,
253 dprintf(("PPMTranslator: Identify()\n"));
254 /* Silence compiler warnings. */
256 ioExtension
= ioExtension
;
258 /* Check that requested format is something we can deal with. */
260 outType
= B_TRANSLATOR_BITMAP
;
262 if (outType
!= B_TRANSLATOR_BITMAP
&& outType
!= PPM_TYPE
) {
263 return B_NO_TRANSLATOR
;
267 int width
, rowbytes
, height
, max
;
270 status_t err
= read_ppm_header(inSource
, &width
, &rowbytes
, &height
, &max
, &ascii
, &space
, &is_ppm
, NULL
);
274 /* Stuff info into info struct -- Translation Kit will do "translator" for us. */
275 outInfo
->group
= B_TRANSLATOR_BITMAP
;
277 outInfo
->type
= PPM_TYPE
;
278 outInfo
->quality
= 0.3; /* no alpha, etc */
279 outInfo
->capability
= 0.8; /* we're pretty good at PPM reading, though */
280 strlcpy(outInfo
->name
, B_TRANSLATE("PPM image"), sizeof(outInfo
->name
));
281 strcpy(outInfo
->MIME
, "image/x-portable-pixmap");
284 outInfo
->type
= B_TRANSLATOR_BITMAP
;
285 outInfo
->quality
= 0.4; /* B_TRANSLATOR_BITMAP can do alpha, at least */
286 outInfo
->capability
= 0.8; /* and we might not know many variations thereof */
287 strlcpy(outInfo
->name
, B_TRANSLATE("Be Bitmap Format (PPMTranslator)"),
288 sizeof(outInfo
->name
));
289 strcpy(outInfo
->MIME
, "image/x-be-bitmap"); /* this is the MIME type of B_TRANSLATOR_BITMAP */
295 /* Return B_NO_TRANSLATOR if not handling the output format */
296 /* If outputFormats exists, will only be called for those formats */
299 Translate( /* required */
300 BPositionIO
* inSource
,
301 const translator_info
* /* inInfo*/ , /* silence compiler warning */
302 BMessage
* ioExtension
, /* can be NULL */
304 BPositionIO
* outDestination
)
306 dprintf(("PPMTranslator: Translate()\n"));
307 inSource
->Seek(0, SEEK_SET
); /* paranoia */
308 // inInfo = inInfo; /* silence compiler warning */
309 /* Check what we're being asked to produce. */
311 outType
= B_TRANSLATOR_BITMAP
;
313 dprintf(("PPMTranslator: outType is '%c%c%c%c'\n", char(outType
>>24), char(outType
>>16), char(outType
>>8), char(outType
)));
314 if (outType
!= B_TRANSLATOR_BITMAP
&& outType
!= PPM_TYPE
) {
315 return B_NO_TRANSLATOR
;
318 /* Figure out what we've been given (again). */
319 int width
, rowbytes
, height
, max
;
322 /* Read_ppm_header() will always return with stream at beginning of data */
323 /* for both B_TRANSLATOR_BITMAP and PPM_TYPE, and indicate what it is. */
324 char * comment
= NULL
;
325 status_t err
= read_ppm_header(inSource
, &width
, &rowbytes
, &height
, &max
, &ascii
, &space
, &is_ppm
, &comment
);
326 if (comment
!= NULL
) {
327 if (ioExtension
!= NULL
) {
328 #if defined(_PR3_COMPATIBLE_) /* R4 headers? */
329 ioExtension
->AddString(B_TRANSLATOR_EXT_COMMENT
, comment
);
331 ioExtension
->AddString("/comment", comment
);
337 dprintf(("read_ppm_header() error %s [%" B_PRIx32
"]\n", strerror(err
),
341 /* Check if we're configured to write ASCII format file. */
342 bool out_ascii
= false;
343 if (outType
== PPM_TYPE
) {
344 out_ascii
= g_settings
.write_ascii
;
345 if (ioExtension
!= NULL
) {
346 ioExtension
->FindBool("ppm /ascii", &out_ascii
);
350 /* Figure out which color space to convert to */
351 color_space out_space
;
353 g_settings_lock
.Lock();
354 if (outType
== PPM_TYPE
) {
355 out_space
= B_RGB24_BIG
;
356 out_rowbytes
= 3*width
;
358 else { /* When outputting to B_TRANSLATOR_BITMAP, follow user's wishes. */
359 #if defined(_PR3_COMPATIBLE_) /* R4 headers? */
360 if (!ioExtension
|| ioExtension
->FindInt32(B_TRANSLATOR_EXT_BITMAP_COLOR_SPACE
, (int32
*)&out_space
) ||
362 if (!ioExtension
|| ioExtension
->FindInt32("bits/space", (int32
*)&out_space
) ||
364 (out_space
== B_NO_COLOR_SPACE
)) {
365 if (g_settings
.out_space
== B_NO_COLOR_SPACE
) {
366 switch (space
) { /* The 24-bit versions are pretty silly, use 32 instead. */
372 /* use whatever is there */
378 out_space
= g_settings
.out_space
;
381 out_rowbytes
= calc_rowbytes(out_space
, width
);
383 g_settings_lock
.Unlock();
384 /* Write file header */
385 if (outType
== PPM_TYPE
) {
386 dprintf(("PPMTranslator: write PPM\n"));
387 /* begin PPM header */
393 err
= outDestination
->Write(magic
, strlen(magic
));
394 if (err
== (long)strlen(magic
)) err
= 0;
396 const char* fsComment
;
397 #if defined(_PR3_COMPATIBLE_) /* R4 headers? */
398 if ((ioExtension
!= NULL
) && !ioExtension
->FindString(B_TRANSLATOR_EXT_COMMENT
, &fsComment
)) {
400 if ((ioExtension
!= NULL
) && !ioExtension
->FindString("/comment", &fsComment
)) {
402 err
= write_comment(fsComment
, outDestination
);
406 sprintf(data
, "%d %d %d\n", width
, height
, max
);
407 err
= outDestination
->Write(data
, strlen(data
));
408 if (err
== (long)strlen(data
)) err
= 0;
413 dprintf(("PPMTranslator: write B_TRANSLATOR_BITMAP\n"));
414 /* B_TRANSLATOR_BITMAP header */
415 TranslatorBitmap hdr
;
416 hdr
.magic
= B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP
);
417 hdr
.bounds
.left
= B_HOST_TO_BENDIAN_FLOAT(0);
418 hdr
.bounds
.top
= B_HOST_TO_BENDIAN_FLOAT(0);
419 hdr
.bounds
.right
= B_HOST_TO_BENDIAN_FLOAT(width
-1);
420 hdr
.bounds
.bottom
= B_HOST_TO_BENDIAN_FLOAT(height
-1);
421 hdr
.rowBytes
= B_HOST_TO_BENDIAN_INT32(out_rowbytes
);
422 hdr
.colors
= (color_space
)B_HOST_TO_BENDIAN_INT32(out_space
);
423 hdr
.dataSize
= B_HOST_TO_BENDIAN_INT32(out_rowbytes
*height
);
424 dprintf(("rowBytes is %d, width %d, out_space %x, space %x\n", out_rowbytes
, width
, out_space
, space
));
425 err
= outDestination
->Write(&hdr
, sizeof(hdr
));
426 dprintf(("PPMTranslator: Write() returns %" B_PRIx32
"\n", err
));
429 BBitmap
* map
= new BBitmap(BRect(0,0,width
-1,height
-1), out_space
);
430 printf("map rb = %" B_PRId32
"\n", map
->BytesPerRow());
434 if (err
== sizeof(hdr
)) err
= 0;
438 return err
> 0 ? B_IO_ERROR
: err
;
440 /* Write data. Luckily, PPM and B_TRANSLATOR_BITMAP both scan from left to right, top to bottom. */
441 return copy_data(inSource
, outDestination
, rowbytes
, out_rowbytes
, height
, max
, ascii
, out_ascii
, space
, out_space
);
454 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR
));
456 fTitle
= new BStringView("title",
457 B_TRANSLATE("PPM image translator"));
458 fTitle
->SetFont(be_bold_font
);
461 int ver
= static_cast<int>(translatorVersion
);
462 sprintf(detail
, B_TRANSLATE("Version %d.%d.%d, %s"), ver
>> 8,
464 (ver
& 0xf), __DATE__
);
465 fDetail
= new BStringView("detail", detail
);
467 fBasedOn
= new BStringView("basedOn",
468 B_TRANSLATE("Based on PPMTranslator sample code"));
470 fCopyright
= new BStringView("copyright",
471 B_TRANSLATE("Sample code copyright 1999, Be Incorporated"));
473 fMenu
= new BPopUpMenu("Color Space");
474 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("None"),
475 CSMessage(B_NO_COLOR_SPACE
)));
476 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("RGB 8:8:8 32 bits"),
477 CSMessage(B_RGB32
)));
478 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("RGBA 8:8:8:8 32 "
479 "bits"), CSMessage(B_RGBA32
)));
480 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("RGB 5:5:5 16 bits"),
481 CSMessage(B_RGB15
)));
482 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("RGBA 5:5:5:1 16 "
483 "bits"), CSMessage(B_RGBA15
)));
484 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("RGB 5:6:5 16 bits"),
485 CSMessage(B_RGB16
)));
486 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("System palette 8 "
487 "bits"), CSMessage(B_CMAP8
)));
488 fMenu
->AddSeparatorItem();
489 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("Grayscale 8 bits"),
490 CSMessage(B_GRAY8
)));
491 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("Bitmap 1 bit"),
492 CSMessage(B_GRAY1
)));
493 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("CMY 8:8:8 32 bits"),
494 CSMessage(B_CMY32
)));
495 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("CMYA 8:8:8:8 32 "
496 "bits"), CSMessage(B_CMYA32
)));
497 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("CMYK 8:8:8:8 32 "
498 "bits"), CSMessage(B_CMYK32
)));
499 fMenu
->AddSeparatorItem();
500 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("RGB 8:8:8 32 bits "
501 "big-endian"), CSMessage(B_RGB32_BIG
)));
502 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("RGBA 8:8:8:8 32 "
503 "bits big-endian"), CSMessage(B_RGBA32_BIG
)));
504 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("RGB 5:5:5 16 bits "
505 "big-endian"), CSMessage(B_RGB15_BIG
)));
506 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("RGBA 5:5:5:1 16 "
507 "bits big-endian"), CSMessage(B_RGBA15_BIG
)));
508 fMenu
->AddItem(new BMenuItem(B_TRANSLATE("RGB 5:6:5 16 bits "
509 "big-endian"), CSMessage(B_RGB16
)));
510 fField
= new BMenuField(B_TRANSLATE("Input color space:"),
512 fField
->SetViewColor(ViewColor());
513 SelectColorSpace(g_settings
.out_space
);
514 BMessage
* msg
= new BMessage(CHANGE_ASCII
);
515 fAscii
= new BCheckBox(B_TRANSLATE("Write ASCII"), msg
);
516 if (g_settings
.write_ascii
)
518 fAscii
->SetViewColor(ViewColor());
521 BLayoutBuilder::Group
<>(this, B_VERTICAL
, 0)
522 .SetInsets(B_USE_DEFAULT_SPACING
)
526 .AddGroup(B_HORIZONTAL
)
537 SetExplicitPreferredSize(BSize((font
.Size() * 350)/12,
538 (font
.Size() * 200)/12));
546 SET_COLOR_SPACE
= 'ppm=',
550 virtual void MessageReceived(
553 if (message
->what
== SET_COLOR_SPACE
) {
554 SetSettings(message
);
556 else if (message
->what
== CHANGE_ASCII
) {
558 msg
.AddBool("ppm /ascii", fAscii
->Value());
562 BView::MessageReceived(message
);
565 virtual void AllAttached()
567 BView::AllAttached();
568 BMessenger
msgr(this);
569 /* Tell all menu items we're the man. */
570 for (int ix
=0; ix
<fMenu
->CountItems(); ix
++) {
571 BMenuItem
* i
= fMenu
->ItemAt(ix
);
576 fAscii
->SetTarget(msgr
);
582 g_settings_lock
.Lock();
584 if (!message
->FindInt32("space", (int32
*)&space
)) {
585 g_settings
.out_space
= space
;
586 SelectColorSpace(space
);
587 g_settings
.settings_touched
= true;
590 if (!message
->FindBool("ppm /ascii", &ascii
)) {
591 g_settings
.write_ascii
= ascii
;
592 g_settings
.settings_touched
= true;
594 g_settings_lock
.Unlock();
598 BStringView
* fTitle
;
599 BStringView
* fDetail
;
600 BStringView
* fBasedOn
;
601 BStringView
* fCopyright
;
606 BMessage
* CSMessage(
609 BMessage
* ret
= new BMessage(SET_COLOR_SPACE
);
610 ret
->AddInt32("space", space
);
614 void SelectColorSpace(
617 for (int ix
=0; ix
<fMenu
->CountItems(); ix
++) {
619 BMenuItem
* i
= fMenu
->ItemAt(ix
);
621 BMessage
* m
= i
->Message();
622 if (m
&& !m
->FindInt32("space", &s
) && (s
== space
)) {
623 fMenu
->Superitem()->SetLabel(i
->Label());
632 /* The view will get resized to what the parent thinks is */
633 /* reasonable. However, it will still receive MouseDowns etc. */
634 /* Your view should change settings in the translator immediately, */
635 /* taking care not to change parameters for a translation that is */
636 /* currently running. Typically, you'll have a global struct for */
637 /* settings that is atomically copied into the translator function */
638 /* as a local when translation starts. */
639 /* Store your settings wherever you feel like it. */
642 MakeConfig( /* optional */
643 BMessage
* ioExtension
, /* can be NULL */
647 PPMView
* v
= new PPMView(B_TRANSLATE("PPMTranslator Settings"),
650 v
->ResizeTo(v
->ExplicitPreferredSize());;
651 *outExtent
= v
->Bounds();
653 v
->SetSettings(ioExtension
);
659 /* Copy your current settings to a BMessage that may be passed */
660 /* to BTranslators::Translate at some later time when the user wants to */
661 /* use whatever settings you're using right now. */
664 GetConfigMessage( /* optional */
665 BMessage
* ioExtension
)
668 #if defined(_PR3_COMPATIBLE_)
669 const char * name
= B_TRANSLATOR_EXT_BITMAP_COLOR_SPACE
;
671 const char * name
= B_TRANSLATE_MARK("bits/space");
673 g_settings_lock
.Lock();
674 (void)ioExtension
->RemoveName(name
);
675 err
= ioExtension
->AddInt32(name
, g_settings
.out_space
);
676 g_settings_lock
.Unlock();
696 /* check for PPM magic number */
698 if (inSource
->Read(ch
, 2) != 2) {
699 return B_NO_TRANSLATOR
;
701 /* look for magic number */
703 /* B_TRANSLATOR_BITMAP magic? */
704 if (ch
[0] == 'b' && ch
[1] == 'i') {
706 return read_bits_header(inSource
, 2, width
, rowbytes
, height
, max
, ascii
, space
);
708 return B_NO_TRANSLATOR
;
714 else if (ch
[1] == '3') {
718 return B_NO_TRANSLATOR
;
720 // status_t err = B_NO_TRANSLATOR;
726 } state
= scan_width
;
728 bool in_comment
= false;
729 *space
= B_RGB24_BIG
;
730 /* The description of PPM is slightly ambiguous as far as comments */
731 /* go. We choose to allow comments anywhere, in the spirit of laxness. */
732 /* See http://www.dcs.ed.ac.uk/~mxr/gfx/2d/PPM.txt */
735 while (inSource
->Read(ch
, 1) == 1) {
736 if (in_comment
&& (ch
[0] != 10) && (ch
[0] != 13)) {
737 if (comment
) { /* collect comment(s) into comment string */
738 if (comptr
>= comlen
-1) {
739 char * n
= (char *)realloc(*comment
, comlen
+100);
747 (*comment
)[comptr
++] = ch
[0];
748 (*comment
)[comptr
] = 0;
757 /* once we're done with whitespace after max, we're done with header */
758 if (isdigit(ch
[0])) {
759 if (!scan
) { /* first digit for this value */
765 *rowbytes
= *width
*3;
772 return B_OK
; /* done with header, all OK */
776 *scan
= (*scan
)*10 + (ch
[0]-'0');
778 else if (isspace(ch
[0])) {
779 if (scan
) { /* are we done with one value? */
781 state
= (enum scan_state
)(state
+1);
783 if (state
== scan_white
) { /* we only ever read one whitespace, since we skip space */
784 return B_OK
; /* when reading ASCII, and there is a single whitespace after max in raw mode */
788 if (state
!= scan_white
) {
789 return B_NO_TRANSLATOR
;
791 return B_OK
; /* header done */
794 return B_NO_TRANSLATOR
;
810 /* read the rest of a possible B_TRANSLATOR_BITMAP header */
811 if (skipped
< 0 || skipped
> 4) return B_NO_TRANSLATOR
;
812 int rd
= sizeof(TranslatorBitmap
)-skipped
;
813 TranslatorBitmap hdr
;
814 /* pre-initialize magic because we might have skipped part of it already */
815 hdr
.magic
= B_HOST_TO_BENDIAN_INT32(B_TRANSLATOR_BITMAP
);
816 char * ptr
= (char *)&hdr
;
817 if (io
->Read(ptr
+skipped
, rd
) != rd
) {
818 return B_NO_TRANSLATOR
;
820 /* swap header values */
821 hdr
.magic
= B_BENDIAN_TO_HOST_INT32(hdr
.magic
);
822 hdr
.bounds
.left
= B_BENDIAN_TO_HOST_FLOAT(hdr
.bounds
.left
);
823 hdr
.bounds
.right
= B_BENDIAN_TO_HOST_FLOAT(hdr
.bounds
.right
);
824 hdr
.bounds
.top
= B_BENDIAN_TO_HOST_FLOAT(hdr
.bounds
.top
);
825 hdr
.bounds
.bottom
= B_BENDIAN_TO_HOST_FLOAT(hdr
.bounds
.bottom
);
826 hdr
.rowBytes
= B_BENDIAN_TO_HOST_INT32(hdr
.rowBytes
);
827 hdr
.colors
= (color_space
)B_BENDIAN_TO_HOST_INT32(hdr
.colors
);
828 hdr
.dataSize
= B_BENDIAN_TO_HOST_INT32(hdr
.dataSize
);
829 /* sanity checking */
830 if (hdr
.magic
!= B_TRANSLATOR_BITMAP
) {
831 return B_NO_TRANSLATOR
;
833 if (hdr
.colors
& 0xffff0000) { /* according to <GraphicsDefs.h> this is a reasonable check. */
834 return B_NO_TRANSLATOR
;
836 if (hdr
.rowBytes
* (hdr
.bounds
.Height()+1) > hdr
.dataSize
) {
837 return B_NO_TRANSLATOR
;
839 /* return information about the data in the stream */
840 *width
= (int)hdr
.bounds
.Width()+1;
841 *rowbytes
= hdr
.rowBytes
;
842 *height
= (int)hdr
.bounds
.Height()+1;
850 /* String may contain newlines, after which we need to insert extra hash signs. */
856 const char * end
= str
+strlen(str
);
857 const char * ptr
= str
;
859 /* write each line as it's found */
860 while ((ptr
< end
) && !err
) {
861 if ((*ptr
== 10) || (*ptr
== 13)) {
862 err
= io
->Write("# ", 2);
864 err
= io
->Write(str
, ptr
-str
);
865 if (err
== ptr
-str
) {
866 if (io
->Write("\n", 1) == 1) {
875 /* write the last data, if any, as a line */
877 err
= io
->Write("# ", 2);
879 err
= io
->Write(str
, ptr
-str
);
880 if (err
== ptr
-str
) {
881 if (io
->Write("\n", 1) == 1) {
898 unsigned char * data
,
904 bool comment
= false;
907 while ((err
= in
->Read(&ch
, 1)) == 1) {
909 if ((ch
== '\n') || (ch
== '\r')) {
915 val
= val
* 10 + (ch
- '0');
919 *(data
++) = val
*255/max
;
934 *(data
++) = val
*255/max
;
949 unsigned char * data
,
954 while (rowbytes
> 2) {
955 sprintf(buffer
, "%d %d %d ", data
[0], data
[1], data
[2]);
957 int l
= strlen(buffer
);
958 if (l
+ linelen
> 70) {
962 if (out
->Write(buffer
, l
) != l
) {
968 out
->Write("\n", 1); /* terminate each scanline */
973 static unsigned char *
977 unsigned char * ptr
= (unsigned char *)malloc(max
);
978 for (int ix
=0; ix
<max
; ix
++) {
979 ptr
[ix
] = ix
*255/max
;
987 unsigned char * scale
,
988 unsigned char * data
,
991 for (int ix
=0; ix
<bytes
; ix
++) {
992 data
[ix
] = scale
[data
[ix
]];
1007 color_space in_space
,
1008 color_space out_space
)
1010 dprintf(("copy_data(%x, %x, %x, %x, %x, %x)\n", rowbytes
, out_rowbytes
, height
, max
, in_space
, out_space
));
1011 /* We read/write one scanline at a time. */
1012 unsigned char * data
= (unsigned char *)malloc(rowbytes
);
1013 unsigned char * out_data
= (unsigned char *)malloc(out_rowbytes
);
1014 if (data
== NULL
|| out_data
== NULL
) {
1019 unsigned char * scale
= NULL
;
1021 scale
= make_scale_data(max
);
1023 status_t err
= B_OK
;
1024 /* There is no data format conversion, so we can just copy data. */
1025 while ((height
-- > 0) && !err
) {
1027 err
= read_ascii_line(in
, max
, data
, rowbytes
);
1030 err
= in
->Read(data
, rowbytes
);
1031 if (err
== rowbytes
) {
1034 if (scale
) { /* for reading PPM that is smaller than 8 bit */
1035 scale_data(scale
, data
, rowbytes
);
1039 unsigned char * wbuf
= data
;
1040 if (in_space
!= out_space
) {
1041 err
= convert_space(in_space
, out_space
, data
, rowbytes
, out_data
);
1044 if (!err
&& out_ascii
) {
1045 err
= write_ascii_line(out
, wbuf
, out_rowbytes
);
1048 err
= out
->Write(wbuf
, out_rowbytes
);
1049 if (err
== out_rowbytes
) {
1058 return err
> 0 ? B_IO_ERROR
: err
;